From 4518cd28d81fa4d2872268e4f8f7b35f387642cc Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 29 Jan 2018 17:31:40 +0200 Subject: dma-fence: add comment for WARN_ON in dma_fence_release() In dma_fence_release() there is a WARN_ON which could be triggered by several cases of wrong dma-fence usage. This patch adds a comment to explain two use-cases to help driver developers that use dma-fence and trigger that WARN_ON to better understand the reasons for it. v2: change to a more generic, one-liner comment Reviewed-by: Daniel Vetter Signed-off-by: Oded Gabbay --- drivers/dma-buf/dma-fence.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 5d101c4053e0..4edb9fd3cf47 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -171,6 +171,7 @@ void dma_fence_release(struct kref *kref) trace_dma_fence_destroy(fence); + /* Failed to signal before release, could be a refcounting issue */ WARN_ON(!list_empty(&fence->cb_list)); if (fence->ops->release) -- cgit v1.2.3 From 3f866f5f04d3645970662409d2bdff3dca58b1a3 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 18 Jan 2018 18:39:55 -0600 Subject: drm/amdkfd: Use ARRAY_SIZE macro in kfd_build_sysfs_node_entry Use ARRAY_SIZE instead of dividing sizeof array with sizeof an element. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Reviewed-by: Felix Kuehling Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index c6a76090a725..7783250e1c6d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -677,7 +677,7 @@ static int kfd_build_sysfs_node_entry(struct kfd_topology_device *dev, } /* All hardware blocks have the same number of attributes. */ - num_attrs = sizeof(perf_attr_iommu)/sizeof(struct kfd_perf_attr); + num_attrs = ARRAY_SIZE(perf_attr_iommu); list_for_each_entry(perf, &dev->perf_props, list) { perf->attr_group = kzalloc(sizeof(struct kfd_perf_attr) * num_attrs + sizeof(struct attribute_group), -- cgit v1.2.3 From 3ee2d00cfb6c0b44aeb9575c20ad8d1abf09be0f Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Thu, 4 Jan 2018 17:17:41 -0500 Subject: drm/amdkfd: Conditionally enable PCIe atomics This will be needed for most dGPUs. CC: linux-pci@vger.kernel.org Signed-off-by: Felix Kuehling Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 17 +++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 1 + 2 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index a8fa33a08de3..fafe971d1d49 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -41,6 +41,7 @@ static const struct kfd_device_info kaveri_device_info = { .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED, .supports_cwsr = false, + .needs_pci_atomics = false, }; static const struct kfd_device_info carrizo_device_info = { @@ -53,6 +54,7 @@ static const struct kfd_device_info carrizo_device_info = { .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED, .supports_cwsr = true, + .needs_pci_atomics = false, }; struct kfd_deviceid { @@ -127,6 +129,21 @@ struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, return NULL; } + if (device_info->needs_pci_atomics) { + /* Allow BIF to recode atomics to PCIe 3.0 + * AtomicOps. 32 and 64-bit requests are possible and + * must be supported. + */ + if (pci_enable_atomic_ops_to_root(pdev, + PCI_EXP_DEVCAP2_ATOMIC_COMP32 | + PCI_EXP_DEVCAP2_ATOMIC_COMP64) < 0) { + dev_info(kfd_device, + "skipped device %x:%x, PCI rejects atomics", + pdev->vendor, pdev->device); + return NULL; + } + } + kfd = kzalloc(sizeof(*kfd), GFP_KERNEL); if (!kfd) return NULL; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 0bedcf9cc08c..e5b16209f069 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -158,6 +158,7 @@ struct kfd_device_info { uint8_t num_of_watch_points; uint16_t mqd_size_aligned; bool supports_cwsr; + bool needs_pci_atomics; }; struct kfd_mem_obj { -- cgit v1.2.3 From d146c5a7196b4c2c2586569971a55392b501b93b Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Thu, 4 Jan 2018 17:17:43 -0500 Subject: drm/amdkfd: Make sched_policy a per-device setting Some dGPUs don't support HWS. Allow them to use a per-device sched_policy that may be different from the global default. Signed-off-by: Felix Kuehling Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 3 ++- drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c | 3 ++- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 2 +- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 26 +++++++++++++++++----- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | 1 + .../gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 3 ++- 6 files changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 62c3d9cd6ef1..6fe24964540b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -901,7 +901,8 @@ static int kfd_ioctl_set_scratch_backing_va(struct file *filep, mutex_unlock(&p->mutex); - if (sched_policy == KFD_SCHED_POLICY_NO_HWS && pdd->qpd.vmid != 0) + if (dev->dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS && + pdd->qpd.vmid != 0) dev->kfd2kgd->set_scratch_backing_va( dev->kgd, args->va_addr, pdd->qpd.vmid); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c b/drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c index 3da25f7bda6b..9d4af961c5d1 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c @@ -33,6 +33,7 @@ #include "kfd_pm4_headers_diq.h" #include "kfd_dbgmgr.h" #include "kfd_dbgdev.h" +#include "kfd_device_queue_manager.h" static DEFINE_MUTEX(kfd_dbgmgr_mutex); @@ -83,7 +84,7 @@ bool kfd_dbgmgr_create(struct kfd_dbgmgr **ppmgr, struct kfd_dev *pdev) } /* get actual type of DBGDevice cpsch or not */ - if (sched_policy == KFD_SCHED_POLICY_NO_HWS) + if (pdev->dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) type = DBGDEV_TYPE_NODIQ; kfd_dbgdev_init(new_buff->dbgdev, pdev, type); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index fafe971d1d49..e8ff4eab63e7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -340,7 +340,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, kfd->pdev->device); pr_debug("Starting kfd with the following scheduling policy %d\n", - sched_policy); + kfd->dqm->sched_policy); goto out; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index b21285afa4ea..e57781d99664 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -385,7 +385,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) prev_active = q->properties.is_active; /* Make sure the queue is unmapped before updating the MQD */ - if (sched_policy != KFD_SCHED_POLICY_NO_HWS) { + if (dqm->sched_policy != KFD_SCHED_POLICY_NO_HWS) { retval = unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0); if (retval) { @@ -417,7 +417,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) else if (!q->properties.is_active && prev_active) dqm->queue_count--; - if (sched_policy != KFD_SCHED_POLICY_NO_HWS) + if (dqm->sched_policy != KFD_SCHED_POLICY_NO_HWS) retval = map_queues_cpsch(dqm); else if (q->properties.is_active && (q->properties.type == KFD_QUEUE_TYPE_COMPUTE || @@ -1097,7 +1097,7 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm, alternate_aperture_base, alternate_aperture_size); - if ((sched_policy == KFD_SCHED_POLICY_NO_HWS) && (qpd->vmid != 0)) + if ((dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) && (qpd->vmid != 0)) program_sh_mem_settings(dqm, qpd); pr_debug("sh_mem_config: 0x%x, ape1_base: 0x%x, ape1_limit: 0x%x\n", @@ -1242,8 +1242,24 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) if (!dqm) return NULL; + switch (dev->device_info->asic_family) { + /* HWS is not available on Hawaii. */ + case CHIP_HAWAII: + /* HWS depends on CWSR for timely dequeue. CWSR is not + * available on Tonga. + * + * FIXME: This argument also applies to Kaveri. + */ + case CHIP_TONGA: + dqm->sched_policy = KFD_SCHED_POLICY_NO_HWS; + break; + default: + dqm->sched_policy = sched_policy; + break; + } + dqm->dev = dev; - switch (sched_policy) { + switch (dqm->sched_policy) { case KFD_SCHED_POLICY_HWS: case KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION: /* initialize dqm for cp scheduling */ @@ -1280,7 +1296,7 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) dqm->ops.process_termination = process_termination_nocpsch; break; default: - pr_err("Invalid scheduling policy %d\n", sched_policy); + pr_err("Invalid scheduling policy %d\n", dqm->sched_policy); goto out_free; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index c61b693bfa8c..9fdc9c2a107a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -180,6 +180,7 @@ struct device_queue_manager { unsigned int *fence_addr; struct kfd_mem_obj *fence_mem; bool active_runlist; + int sched_policy; }; void device_queue_manager_init_cik( diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 876380632668..7817e327ea6d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -208,7 +208,8 @@ int pqm_create_queue(struct process_queue_manager *pqm, case KFD_QUEUE_TYPE_COMPUTE: /* check if there is over subscription */ - if ((sched_policy == KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) && + if ((dev->dqm->sched_policy == + KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) && ((dev->dqm->processes_count >= dev->vm_info.vmid_num_kfd) || (dev->dqm->queue_count >= get_queues_num(dev->dqm)))) { pr_err("Over-subscription is not allowed in radeon_kfd.sched_policy == 1\n"); -- cgit v1.2.3 From 97672cbe3de809ef8c4ea66cce675f5da3d3df44 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Thu, 4 Jan 2018 17:17:44 -0500 Subject: drm/amdkfd: Add dGPU support to the device queue manager GFXv7 and v8 dGPUs use a different addressing mode for KFD compared to APUs (GPUVM64 vs HSA64). And dGPUs don't support MTYPE_CC. They use MTYPE_UC instead for memory that requires coherency. Signed-off-by: Felix Kuehling Acked-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 11 +++ .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | 4 + .../drm/amd/amdkfd/kfd_device_queue_manager_cik.c | 56 +++++++++++++ .../drm/amd/amdkfd/kfd_device_queue_manager_vi.c | 93 ++++++++++++++++++++++ 4 files changed, 164 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index e57781d99664..47d493ea8e4f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -1308,6 +1308,17 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) case CHIP_KAVERI: device_queue_manager_init_cik(&dqm->asic_ops); break; + + case CHIP_HAWAII: + device_queue_manager_init_cik_hawaii(&dqm->asic_ops); + break; + + case CHIP_TONGA: + case CHIP_FIJI: + case CHIP_POLARIS10: + case CHIP_POLARIS11: + device_queue_manager_init_vi_tonga(&dqm->asic_ops); + break; default: WARN(1, "Unexpected ASIC family %u", dev->device_info->asic_family); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index 9fdc9c2a107a..68be0aaff3f4 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -185,8 +185,12 @@ struct device_queue_manager { void device_queue_manager_init_cik( struct device_queue_manager_asic_ops *asic_ops); +void device_queue_manager_init_cik_hawaii( + struct device_queue_manager_asic_ops *asic_ops); void device_queue_manager_init_vi( struct device_queue_manager_asic_ops *asic_ops); +void device_queue_manager_init_vi_tonga( + struct device_queue_manager_asic_ops *asic_ops); void program_sh_mem_settings(struct device_queue_manager *dqm, struct qcm_process_device *qpd); unsigned int get_queues_num(struct device_queue_manager *dqm); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c index 28e48c90c596..aed4c21417bf 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c @@ -34,8 +34,13 @@ static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm, uint64_t alternate_aperture_size); static int update_qpd_cik(struct device_queue_manager *dqm, struct qcm_process_device *qpd); +static int update_qpd_cik_hawaii(struct device_queue_manager *dqm, + struct qcm_process_device *qpd); static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd); +static void init_sdma_vm_hawaii(struct device_queue_manager *dqm, + struct queue *q, + struct qcm_process_device *qpd); void device_queue_manager_init_cik( struct device_queue_manager_asic_ops *asic_ops) @@ -45,6 +50,14 @@ void device_queue_manager_init_cik( asic_ops->init_sdma_vm = init_sdma_vm; } +void device_queue_manager_init_cik_hawaii( + struct device_queue_manager_asic_ops *asic_ops) +{ + asic_ops->set_cache_memory_policy = set_cache_memory_policy_cik; + asic_ops->update_qpd = update_qpd_cik_hawaii; + asic_ops->init_sdma_vm = init_sdma_vm_hawaii; +} + static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble) { /* In 64-bit mode, we can only control the top 3 bits of the LDS, @@ -132,6 +145,36 @@ static int update_qpd_cik(struct device_queue_manager *dqm, return 0; } +static int update_qpd_cik_hawaii(struct device_queue_manager *dqm, + struct qcm_process_device *qpd) +{ + struct kfd_process_device *pdd; + unsigned int temp; + + pdd = qpd_to_pdd(qpd); + + /* check if sh_mem_config register already configured */ + if (qpd->sh_mem_config == 0) { + qpd->sh_mem_config = + ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) | + DEFAULT_MTYPE(MTYPE_NONCACHED) | + APE1_MTYPE(MTYPE_NONCACHED); + qpd->sh_mem_ape1_limit = 0; + qpd->sh_mem_ape1_base = 0; + } + + /* On dGPU we're always in GPUVM64 addressing mode with 64-bit + * aperture addresses. + */ + temp = get_sh_mem_bases_nybble_64(pdd); + qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp); + + pr_debug("is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n", + qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases); + + return 0; +} + static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd) { @@ -147,3 +190,16 @@ static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, q->properties.sdma_vm_addr = value; } + +static void init_sdma_vm_hawaii(struct device_queue_manager *dqm, + struct queue *q, + struct qcm_process_device *qpd) +{ + /* On dGPU we're always in GPUVM64 addressing mode with 64-bit + * aperture addresses. + */ + q->properties.sdma_vm_addr = + ((get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd))) << + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) & + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE_MASK; +} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c index 2fbce57a2f21..fd60a116be37 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c @@ -33,10 +33,21 @@ static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, enum cache_policy alternate_policy, void __user *alternate_aperture_base, uint64_t alternate_aperture_size); +static bool set_cache_memory_policy_vi_tonga(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + enum cache_policy default_policy, + enum cache_policy alternate_policy, + void __user *alternate_aperture_base, + uint64_t alternate_aperture_size); static int update_qpd_vi(struct device_queue_manager *dqm, struct qcm_process_device *qpd); +static int update_qpd_vi_tonga(struct device_queue_manager *dqm, + struct qcm_process_device *qpd); static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd); +static void init_sdma_vm_tonga(struct device_queue_manager *dqm, + struct queue *q, + struct qcm_process_device *qpd); void device_queue_manager_init_vi( struct device_queue_manager_asic_ops *asic_ops) @@ -46,6 +57,14 @@ void device_queue_manager_init_vi( asic_ops->init_sdma_vm = init_sdma_vm; } +void device_queue_manager_init_vi_tonga( + struct device_queue_manager_asic_ops *asic_ops) +{ + asic_ops->set_cache_memory_policy = set_cache_memory_policy_vi_tonga; + asic_ops->update_qpd = update_qpd_vi_tonga; + asic_ops->init_sdma_vm = init_sdma_vm_tonga; +} + static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble) { /* In 64-bit mode, we can only control the top 3 bits of the LDS, @@ -103,6 +122,33 @@ static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, return true; } +static bool set_cache_memory_policy_vi_tonga(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + enum cache_policy default_policy, + enum cache_policy alternate_policy, + void __user *alternate_aperture_base, + uint64_t alternate_aperture_size) +{ + uint32_t default_mtype; + uint32_t ape1_mtype; + + default_mtype = (default_policy == cache_policy_coherent) ? + MTYPE_UC : + MTYPE_NC; + + ape1_mtype = (alternate_policy == cache_policy_coherent) ? + MTYPE_UC : + MTYPE_NC; + + qpd->sh_mem_config = + SH_MEM_ALIGNMENT_MODE_UNALIGNED << + SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT | + default_mtype << SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT | + ape1_mtype << SH_MEM_CONFIG__APE1_MTYPE__SHIFT; + + return true; +} + static int update_qpd_vi(struct device_queue_manager *dqm, struct qcm_process_device *qpd) { @@ -144,6 +190,40 @@ static int update_qpd_vi(struct device_queue_manager *dqm, return 0; } +static int update_qpd_vi_tonga(struct device_queue_manager *dqm, + struct qcm_process_device *qpd) +{ + struct kfd_process_device *pdd; + unsigned int temp; + + pdd = qpd_to_pdd(qpd); + + /* check if sh_mem_config register already configured */ + if (qpd->sh_mem_config == 0) { + qpd->sh_mem_config = + SH_MEM_ALIGNMENT_MODE_UNALIGNED << + SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT | + MTYPE_UC << + SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT | + MTYPE_UC << + SH_MEM_CONFIG__APE1_MTYPE__SHIFT; + + qpd->sh_mem_ape1_limit = 0; + qpd->sh_mem_ape1_base = 0; + } + + /* On dGPU we're always in GPUVM64 addressing mode with 64-bit + * aperture addresses. + */ + temp = get_sh_mem_bases_nybble_64(pdd); + qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp); + + pr_debug("sh_mem_bases nybble: 0x%X and register 0x%X\n", + temp, qpd->sh_mem_bases); + + return 0; +} + static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd) { @@ -159,3 +239,16 @@ static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, q->properties.sdma_vm_addr = value; } + +static void init_sdma_vm_tonga(struct device_queue_manager *dqm, + struct queue *q, + struct qcm_process_device *qpd) +{ + /* On dGPU we're always in GPUVM64 addressing mode with 64-bit + * aperture addresses. + */ + q->properties.sdma_vm_addr = + ((get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd))) << + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) & + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE_MASK; +} -- cgit v1.2.3 From ee04955af6b851a4f133d2472bc65c5d8b9aa692 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Thu, 4 Jan 2018 17:17:45 -0500 Subject: drm/amdkfd: Add dGPU support to the MQD manager On dGPUs don't set ATC addressing bits and use MTYPE_UC for coherent memory. Signed-off-by: Felix Kuehling Acked-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c | 7 +++++ drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c | 35 ++++++++++++++++++++++-- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 21 ++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 4 +++ 4 files changed, 64 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c index dfd260ef81ff..ee7061e1c466 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c @@ -29,8 +29,15 @@ struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type, switch (dev->device_info->asic_family) { case CHIP_KAVERI: return mqd_manager_init_cik(type, dev); + case CHIP_HAWAII: + return mqd_manager_init_cik_hawaii(type, dev); case CHIP_CARRIZO: return mqd_manager_init_vi(type, dev); + case CHIP_TONGA: + case CHIP_FIJI: + case CHIP_POLARIS10: + case CHIP_POLARIS11: + return mqd_manager_init_vi_tonga(type, dev); default: WARN(1, "Unexpected ASIC family %u", dev->device_info->asic_family); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c index f8ef4a051e08..fbe3f83ba685 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -170,14 +170,19 @@ static int load_mqd_sdma(struct mqd_manager *mm, void *mqd, mms); } -static int update_mqd(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) +static int __update_mqd(struct mqd_manager *mm, void *mqd, + struct queue_properties *q, unsigned int atc_bit) { struct cik_mqd *m; m = get_mqd(mqd); m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE | - DEFAULT_MIN_AVAIL_SIZE | PQ_ATC_EN; + DEFAULT_MIN_AVAIL_SIZE; + m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE; + if (atc_bit) { + m->cp_hqd_pq_control |= PQ_ATC_EN; + m->cp_hqd_ib_control |= IB_ATC_EN; + } /* * Calculating queue size which is log base 2 of actual queue size -1 @@ -202,6 +207,18 @@ static int update_mqd(struct mqd_manager *mm, void *mqd, return 0; } +static int update_mqd(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + return __update_mqd(mm, mqd, q, 1); +} + +static int update_mqd_hawaii(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + return __update_mqd(mm, mqd, q, 0); +} + static int update_mqd_sdma(struct mqd_manager *mm, void *mqd, struct queue_properties *q) { @@ -441,3 +458,15 @@ struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type, return mqd; } +struct mqd_manager *mqd_manager_init_cik_hawaii(enum KFD_MQD_TYPE type, + struct kfd_dev *dev) +{ + struct mqd_manager *mqd; + + mqd = mqd_manager_init_cik(type, dev); + if (!mqd) + return NULL; + if ((type == KFD_MQD_TYPE_CP) || (type == KFD_MQD_TYPE_COMPUTE)) + mqd->update_mqd = update_mqd_hawaii; + return mqd; +} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index 971aec0637dc..58221c1fc917 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -151,6 +151,8 @@ static int __update_mqd(struct mqd_manager *mm, void *mqd, m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr); m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr); + m->cp_hqd_pq_wptr_poll_addr_lo = lower_32_bits((uint64_t)q->write_ptr); + m->cp_hqd_pq_wptr_poll_addr_hi = upper_32_bits((uint64_t)q->write_ptr); m->cp_hqd_pq_doorbell_control = q->doorbell_off << @@ -208,6 +210,12 @@ static int update_mqd(struct mqd_manager *mm, void *mqd, return __update_mqd(mm, mqd, q, MTYPE_CC, 1); } +static int update_mqd_tonga(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + return __update_mqd(mm, mqd, q, MTYPE_UC, 0); +} + static int destroy_mqd(struct mqd_manager *mm, void *mqd, enum kfd_preempt_type type, unsigned int timeout, uint32_t pipe_id, @@ -432,3 +440,16 @@ struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type, return mqd; } + +struct mqd_manager *mqd_manager_init_vi_tonga(enum KFD_MQD_TYPE type, + struct kfd_dev *dev) +{ + struct mqd_manager *mqd; + + mqd = mqd_manager_init_vi(type, dev); + if (!mqd) + return NULL; + if ((type == KFD_MQD_TYPE_CP) || (type == KFD_MQD_TYPE_COMPUTE)) + mqd->update_mqd = update_mqd_tonga; + return mqd; +} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index e5b16209f069..594f85355397 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -706,8 +706,12 @@ struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type, struct kfd_dev *dev); struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type, struct kfd_dev *dev); +struct mqd_manager *mqd_manager_init_cik_hawaii(enum KFD_MQD_TYPE type, + struct kfd_dev *dev); struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type, struct kfd_dev *dev); +struct mqd_manager *mqd_manager_init_vi_tonga(enum KFD_MQD_TYPE type, + struct kfd_dev *dev); struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev); void device_queue_manager_uninit(struct device_queue_manager *dqm); struct kernel_queue *kernel_queue_init(struct kfd_dev *dev, -- cgit v1.2.3 From 1d63669885ebc8fca13e44864f7199c3ff50cea3 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Thu, 4 Jan 2018 17:17:46 -0500 Subject: drm/amdkfd: Add dGPU support to kernel_queue_init Recognize dGPU ASIC families. Signed-off-by: Felix Kuehling Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c index 5dc6567d4a13..69f496485331 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c @@ -297,10 +297,15 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev, switch (dev->device_info->asic_family) { case CHIP_CARRIZO: + case CHIP_TONGA: + case CHIP_FIJI: + case CHIP_POLARIS10: + case CHIP_POLARIS11: kernel_queue_init_vi(&kq->ops_asic_specific); break; case CHIP_KAVERI: + case CHIP_HAWAII: kernel_queue_init_cik(&kq->ops_asic_specific); break; default: -- cgit v1.2.3 From a3084e6c522f94130c9dfc26fe6458c353dbc0c9 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Thu, 4 Jan 2018 17:17:47 -0500 Subject: drm/amdkfd: Add dGPU device IDs and device info v2: remove needs_iommu field as it doesn't exists CC: linux-pci@vger.kernel.org Signed-off-by: Felix Kuehling Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 145 +++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index e8ff4eab63e7..83d6f410890e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -57,12 +57,110 @@ static const struct kfd_device_info carrizo_device_info = { .needs_pci_atomics = false, }; +static const struct kfd_device_info hawaii_device_info = { + .asic_family = CHIP_HAWAII, + .max_pasid_bits = 16, + /* max num of queues for KV.TODO should be a dynamic value */ + .max_no_of_hqd = 24, + .ih_ring_entry_size = 4 * sizeof(uint32_t), + .event_interrupt_class = &event_interrupt_class_cik, + .num_of_watch_points = 4, + .mqd_size_aligned = MQD_SIZE_ALIGNED, + .supports_cwsr = false, + .needs_pci_atomics = false, +}; + +static const struct kfd_device_info tonga_device_info = { + .asic_family = CHIP_TONGA, + .max_pasid_bits = 16, + .max_no_of_hqd = 24, + .ih_ring_entry_size = 4 * sizeof(uint32_t), + .event_interrupt_class = &event_interrupt_class_cik, + .num_of_watch_points = 4, + .mqd_size_aligned = MQD_SIZE_ALIGNED, + .supports_cwsr = false, + .needs_pci_atomics = true, +}; + +static const struct kfd_device_info tonga_vf_device_info = { + .asic_family = CHIP_TONGA, + .max_pasid_bits = 16, + .max_no_of_hqd = 24, + .ih_ring_entry_size = 4 * sizeof(uint32_t), + .event_interrupt_class = &event_interrupt_class_cik, + .num_of_watch_points = 4, + .mqd_size_aligned = MQD_SIZE_ALIGNED, + .supports_cwsr = false, + .needs_pci_atomics = false, +}; + +static const struct kfd_device_info fiji_device_info = { + .asic_family = CHIP_FIJI, + .max_pasid_bits = 16, + .max_no_of_hqd = 24, + .ih_ring_entry_size = 4 * sizeof(uint32_t), + .event_interrupt_class = &event_interrupt_class_cik, + .num_of_watch_points = 4, + .mqd_size_aligned = MQD_SIZE_ALIGNED, + .supports_cwsr = true, + .needs_pci_atomics = true, +}; + +static const struct kfd_device_info fiji_vf_device_info = { + .asic_family = CHIP_FIJI, + .max_pasid_bits = 16, + .max_no_of_hqd = 24, + .ih_ring_entry_size = 4 * sizeof(uint32_t), + .event_interrupt_class = &event_interrupt_class_cik, + .num_of_watch_points = 4, + .mqd_size_aligned = MQD_SIZE_ALIGNED, + .supports_cwsr = true, + .needs_pci_atomics = false, +}; + + +static const struct kfd_device_info polaris10_device_info = { + .asic_family = CHIP_POLARIS10, + .max_pasid_bits = 16, + .max_no_of_hqd = 24, + .ih_ring_entry_size = 4 * sizeof(uint32_t), + .event_interrupt_class = &event_interrupt_class_cik, + .num_of_watch_points = 4, + .mqd_size_aligned = MQD_SIZE_ALIGNED, + .supports_cwsr = true, + .needs_pci_atomics = true, +}; + +static const struct kfd_device_info polaris10_vf_device_info = { + .asic_family = CHIP_POLARIS10, + .max_pasid_bits = 16, + .max_no_of_hqd = 24, + .ih_ring_entry_size = 4 * sizeof(uint32_t), + .event_interrupt_class = &event_interrupt_class_cik, + .num_of_watch_points = 4, + .mqd_size_aligned = MQD_SIZE_ALIGNED, + .supports_cwsr = true, + .needs_pci_atomics = false, +}; + +static const struct kfd_device_info polaris11_device_info = { + .asic_family = CHIP_POLARIS11, + .max_pasid_bits = 16, + .max_no_of_hqd = 24, + .ih_ring_entry_size = 4 * sizeof(uint32_t), + .event_interrupt_class = &event_interrupt_class_cik, + .num_of_watch_points = 4, + .mqd_size_aligned = MQD_SIZE_ALIGNED, + .supports_cwsr = true, + .needs_pci_atomics = true, +}; + + struct kfd_deviceid { unsigned short did; const struct kfd_device_info *device_info; }; -/* Please keep this sorted by increasing device id. */ static const struct kfd_deviceid supported_devices[] = { { 0x1304, &kaveri_device_info }, /* Kaveri */ { 0x1305, &kaveri_device_info }, /* Kaveri */ @@ -90,7 +188,50 @@ static const struct kfd_deviceid supported_devices[] = { { 0x9874, &carrizo_device_info }, /* Carrizo */ { 0x9875, &carrizo_device_info }, /* Carrizo */ { 0x9876, &carrizo_device_info }, /* Carrizo */ - { 0x9877, &carrizo_device_info } /* Carrizo */ + { 0x9877, &carrizo_device_info }, /* Carrizo */ + { 0x67A0, &hawaii_device_info }, /* Hawaii */ + { 0x67A1, &hawaii_device_info }, /* Hawaii */ + { 0x67A2, &hawaii_device_info }, /* Hawaii */ + { 0x67A8, &hawaii_device_info }, /* Hawaii */ + { 0x67A9, &hawaii_device_info }, /* Hawaii */ + { 0x67AA, &hawaii_device_info }, /* Hawaii */ + { 0x67B0, &hawaii_device_info }, /* Hawaii */ + { 0x67B1, &hawaii_device_info }, /* Hawaii */ + { 0x67B8, &hawaii_device_info }, /* Hawaii */ + { 0x67B9, &hawaii_device_info }, /* Hawaii */ + { 0x67BA, &hawaii_device_info }, /* Hawaii */ + { 0x67BE, &hawaii_device_info }, /* Hawaii */ + { 0x6920, &tonga_device_info }, /* Tonga */ + { 0x6921, &tonga_device_info }, /* Tonga */ + { 0x6928, &tonga_device_info }, /* Tonga */ + { 0x6929, &tonga_device_info }, /* Tonga */ + { 0x692B, &tonga_device_info }, /* Tonga */ + { 0x692F, &tonga_vf_device_info }, /* Tonga vf */ + { 0x6938, &tonga_device_info }, /* Tonga */ + { 0x6939, &tonga_device_info }, /* Tonga */ + { 0x7300, &fiji_device_info }, /* Fiji */ + { 0x730F, &fiji_vf_device_info }, /* Fiji vf*/ + { 0x67C0, &polaris10_device_info }, /* Polaris10 */ + { 0x67C1, &polaris10_device_info }, /* Polaris10 */ + { 0x67C2, &polaris10_device_info }, /* Polaris10 */ + { 0x67C4, &polaris10_device_info }, /* Polaris10 */ + { 0x67C7, &polaris10_device_info }, /* Polaris10 */ + { 0x67C8, &polaris10_device_info }, /* Polaris10 */ + { 0x67C9, &polaris10_device_info }, /* Polaris10 */ + { 0x67CA, &polaris10_device_info }, /* Polaris10 */ + { 0x67CC, &polaris10_device_info }, /* Polaris10 */ + { 0x67CF, &polaris10_device_info }, /* Polaris10 */ + { 0x67D0, &polaris10_vf_device_info }, /* Polaris10 vf*/ + { 0x67DF, &polaris10_device_info }, /* Polaris10 */ + { 0x67E0, &polaris11_device_info }, /* Polaris11 */ + { 0x67E1, &polaris11_device_info }, /* Polaris11 */ + { 0x67E3, &polaris11_device_info }, /* Polaris11 */ + { 0x67E7, &polaris11_device_info }, /* Polaris11 */ + { 0x67E8, &polaris11_device_info }, /* Polaris11 */ + { 0x67E9, &polaris11_device_info }, /* Polaris11 */ + { 0x67EB, &polaris11_device_info }, /* Polaris11 */ + { 0x67EF, &polaris11_device_info }, /* Polaris11 */ + { 0x67FF, &polaris11_device_info }, /* Polaris11 */ }; static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size, -- cgit v1.2.3 From 30d13424fba9236b741887eabb016279519c6ac4 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Thu, 4 Jan 2018 17:17:48 -0500 Subject: drm/amdgpu: Enable KFD initialization on dGPUs Signed-off-by: Felix Kuehling Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 450426dbed92..1d2b6ca82f1d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -78,10 +78,15 @@ void amdgpu_amdkfd_device_probe(struct amdgpu_device *adev) switch (adev->asic_type) { #ifdef CONFIG_DRM_AMDGPU_CIK case CHIP_KAVERI: + case CHIP_HAWAII: kfd2kgd = amdgpu_amdkfd_gfx_7_get_functions(); break; #endif case CHIP_CARRIZO: + case CHIP_TONGA: + case CHIP_FIJI: + case CHIP_POLARIS10: + case CHIP_POLARIS11: kfd2kgd = amdgpu_amdkfd_gfx_8_0_get_functions(); break; default: -- cgit v1.2.3 From fa72d66198c90668723bb25ec23639a012bee99b Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Tue, 6 Feb 2018 20:32:30 -0500 Subject: drm/amdgpu: remove useless BUG_ONs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dereferencing NULL pointers will cause a BUG anyway. No need to do an explicit check. Signed-off-by: Felix Kuehling Reviewed-by: Christian König Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 6 ------ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 2 -- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 2 -- 3 files changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 1d2b6ca82f1d..e06d7919747a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -212,10 +212,6 @@ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, struct kgd_mem **mem = (struct kgd_mem **) mem_obj; int r; - BUG_ON(kgd == NULL); - BUG_ON(gpu_addr == NULL); - BUG_ON(cpu_ptr == NULL); - *mem = kmalloc(sizeof(struct kgd_mem), GFP_KERNEL); if ((*mem) == NULL) return -ENOMEM; @@ -269,8 +265,6 @@ void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj) { struct kgd_mem *mem = (struct kgd_mem *) mem_obj; - BUG_ON(mem == NULL); - amdgpu_bo_reserve(mem->bo, true); amdgpu_bo_kunmap(mem->bo); amdgpu_bo_unpin(mem->bo); 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 a9e6aea0e5f8..74fcb8b42fd0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -812,8 +812,6 @@ static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) struct amdgpu_device *adev = (struct amdgpu_device *) kgd; const union amdgpu_firmware_header *hdr; - BUG_ON(kgd == NULL); - switch (type) { case KGD_ENGINE_PFP: hdr = (const union amdgpu_firmware_header *) 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 b127259d7d85..c70c8e1d1863 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -775,8 +775,6 @@ static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) struct amdgpu_device *adev = (struct amdgpu_device *) kgd; const union amdgpu_firmware_header *hdr; - BUG_ON(kgd == NULL); - switch (type) { case KGD_ENGINE_PFP: hdr = (const union amdgpu_firmware_header *) -- cgit v1.2.3 From 473fee476a3c39f50bae07354972dd1cefaf79e9 Mon Sep 17 00:00:00 2001 From: Yong Zhao Date: Tue, 6 Feb 2018 20:32:31 -0500 Subject: drm/amdgpu: Replace kgd_mem with amdgpu_bo for kernel pinned gtt mem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The extra fields in struct kgd_mem aren't actually needed. This struct will be used for GPUVM allocations later. Signed-off-by: Yong Zhao Signed-off-by: Felix Kuehling Reviewed-by: Christian König Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 47 +++++++++++++++--------------- 1 file changed, 23 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index e06d7919747a..141d11dfede0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -209,15 +209,13 @@ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, void **cpu_ptr) { struct amdgpu_device *adev = (struct amdgpu_device *)kgd; - struct kgd_mem **mem = (struct kgd_mem **) mem_obj; + struct amdgpu_bo *bo = NULL; int r; - - *mem = kmalloc(sizeof(struct kgd_mem), GFP_KERNEL); - if ((*mem) == NULL) - return -ENOMEM; + uint64_t gpu_addr_tmp = 0; + void *cpu_ptr_tmp = NULL; r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_GTT, - AMDGPU_GEM_CREATE_CPU_GTT_USWC, NULL, NULL, &(*mem)->bo); + AMDGPU_GEM_CREATE_CPU_GTT_USWC, NULL, NULL, &bo); if (r) { dev_err(adev->dev, "failed to allocate BO for amdkfd (%d)\n", r); @@ -225,52 +223,53 @@ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, } /* map the buffer */ - r = amdgpu_bo_reserve((*mem)->bo, true); + r = amdgpu_bo_reserve(bo, true); if (r) { dev_err(adev->dev, "(%d) failed to reserve bo for amdkfd\n", r); goto allocate_mem_reserve_bo_failed; } - r = amdgpu_bo_pin((*mem)->bo, AMDGPU_GEM_DOMAIN_GTT, - &(*mem)->gpu_addr); + r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT, + &gpu_addr_tmp); if (r) { dev_err(adev->dev, "(%d) failed to pin bo for amdkfd\n", r); goto allocate_mem_pin_bo_failed; } - *gpu_addr = (*mem)->gpu_addr; - r = amdgpu_bo_kmap((*mem)->bo, &(*mem)->cpu_ptr); + r = amdgpu_bo_kmap(bo, &cpu_ptr_tmp); if (r) { dev_err(adev->dev, "(%d) failed to map bo to kernel for amdkfd\n", r); goto allocate_mem_kmap_bo_failed; } - *cpu_ptr = (*mem)->cpu_ptr; - amdgpu_bo_unreserve((*mem)->bo); + *mem_obj = bo; + *gpu_addr = gpu_addr_tmp; + *cpu_ptr = cpu_ptr_tmp; + + amdgpu_bo_unreserve(bo); return 0; allocate_mem_kmap_bo_failed: - amdgpu_bo_unpin((*mem)->bo); + amdgpu_bo_unpin(bo); allocate_mem_pin_bo_failed: - amdgpu_bo_unreserve((*mem)->bo); + amdgpu_bo_unreserve(bo); allocate_mem_reserve_bo_failed: - amdgpu_bo_unref(&(*mem)->bo); + amdgpu_bo_unref(&bo); return r; } void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj) { - struct kgd_mem *mem = (struct kgd_mem *) mem_obj; - - amdgpu_bo_reserve(mem->bo, true); - amdgpu_bo_kunmap(mem->bo); - amdgpu_bo_unpin(mem->bo); - amdgpu_bo_unreserve(mem->bo); - amdgpu_bo_unref(&(mem->bo)); - kfree(mem); + struct amdgpu_bo *bo = (struct amdgpu_bo *) mem_obj; + + amdgpu_bo_reserve(bo, true); + amdgpu_bo_kunmap(bo); + amdgpu_bo_unpin(bo); + amdgpu_bo_unreserve(bo); + amdgpu_bo_unref(&(bo)); } void get_local_mem_info(struct kgd_dev *kgd, -- cgit v1.2.3 From 61b100e98f16e02df44862bba7798c7654b565f2 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Tue, 6 Feb 2018 20:32:32 -0500 Subject: drm/amdgpu: Fix header file dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Felix Kuehling Reviewed-by: Christian König Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index 1d0d250cbfdf..06436c3ebd2b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -26,6 +26,7 @@ #include #include +#include /* max number of rings */ #define AMDGPU_MAX_RINGS 18 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index fabf44b262be..e9841518343e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "amdgpu_sync.h" #include "amdgpu_ring.h" -- cgit v1.2.3 From 2f901c25eb35a1b24a6006b9b668ad8bf88da582 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Tue, 6 Feb 2018 20:32:33 -0500 Subject: drm/amdgpu: Fix wrong mask in get_atc_vmid_pasid_mapping_pasid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Felix Kuehling Reviewed-by: Christian König Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') 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 74fcb8b42fd0..b8be7b961b7e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -787,7 +787,7 @@ static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, struct amdgpu_device *adev = (struct amdgpu_device *) kgd; reg = RREG32(mmATC_VMID0_PASID_MAPPING + vmid); - return reg & ATC_VMID0_PASID_MAPPING__VALID_MASK; + return reg & ATC_VMID0_PASID_MAPPING__PASID_MASK; } static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid) 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 c70c8e1d1863..744c05b186d5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -704,7 +704,7 @@ static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, struct amdgpu_device *adev = (struct amdgpu_device *) kgd; reg = RREG32(mmATC_VMID0_PASID_MAPPING + vmid); - return reg & ATC_VMID0_PASID_MAPPING__VALID_MASK; + return reg & ATC_VMID0_PASID_MAPPING__PASID_MASK; } static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid) -- cgit v1.2.3 From 1029a3f33678afb8978285209ec5cfe153fe44ef Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Tue, 6 Feb 2018 20:32:34 -0500 Subject: drm/amdgpu: Remove unused kfd2kgd interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Felix Kuehling Reviewed-by: Christian König Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 9 --------- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 10 ---------- drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 2 -- 3 files changed, 21 deletions(-) (limited to 'drivers') 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 b8be7b961b7e..1362181b10d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -139,7 +139,6 @@ static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd, static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd, uint8_t vmid); static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, uint8_t vmid); -static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid); static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type); static void set_scratch_backing_va(struct kgd_dev *kgd, @@ -196,7 +195,6 @@ static const struct kfd2kgd_calls kfd2kgd = { .address_watch_get_offset = kgd_address_watch_get_offset, .get_atc_vmid_pasid_mapping_pasid = get_atc_vmid_pasid_mapping_pasid, .get_atc_vmid_pasid_mapping_valid = get_atc_vmid_pasid_mapping_valid, - .write_vmid_invalidate_request = write_vmid_invalidate_request, .get_fw_version = get_fw_version, .set_scratch_backing_va = set_scratch_backing_va, .get_tile_config = get_tile_config, @@ -790,13 +788,6 @@ static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, return reg & ATC_VMID0_PASID_MAPPING__PASID_MASK; } -static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid) -{ - struct amdgpu_device *adev = (struct amdgpu_device *) kgd; - - WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); -} - static void set_scratch_backing_va(struct kgd_dev *kgd, uint64_t va, uint32_t vmid) { 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 744c05b186d5..5130eac7afdd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -81,7 +81,6 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, void *mqd, uint32_t queue_id); static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd, unsigned int utimeout); -static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid); static int kgd_address_watch_disable(struct kgd_dev *kgd); static int kgd_address_watch_execute(struct kgd_dev *kgd, unsigned int watch_point_id, @@ -99,7 +98,6 @@ static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd, uint8_t vmid); static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, uint8_t vmid); -static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid); static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type); static void set_scratch_backing_va(struct kgd_dev *kgd, uint64_t va, uint32_t vmid); @@ -157,7 +155,6 @@ static const struct kfd2kgd_calls kfd2kgd = { get_atc_vmid_pasid_mapping_pasid, .get_atc_vmid_pasid_mapping_valid = get_atc_vmid_pasid_mapping_valid, - .write_vmid_invalidate_request = write_vmid_invalidate_request, .get_fw_version = get_fw_version, .set_scratch_backing_va = set_scratch_backing_va, .get_tile_config = get_tile_config, @@ -707,13 +704,6 @@ static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, return reg & ATC_VMID0_PASID_MAPPING__PASID_MASK; } -static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid) -{ - struct amdgpu_device *adev = (struct amdgpu_device *) kgd; - - WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); -} - static int kgd_address_watch_disable(struct kgd_dev *kgd) { return 0; diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index a6752bd0c871..94eab54864bf 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -258,8 +258,6 @@ struct kfd2kgd_calls { uint16_t (*get_atc_vmid_pasid_mapping_pasid)( struct kgd_dev *kgd, uint8_t vmid); - void (*write_vmid_invalidate_request)(struct kgd_dev *kgd, - uint8_t vmid); uint16_t (*get_fw_version)(struct kgd_dev *kgd, enum kgd_engine_type type); -- cgit v1.2.3 From d8d019ccffb838bb0dd98e583b5c25ccc0bc6ece Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Tue, 6 Feb 2018 20:32:35 -0500 Subject: drm/amdgpu: Add KFD eviction fence This fence is used by KFD to keep memory resident while user mode queues are enabled. Trying to evict memory will trigger the enable_signaling callback, which starts a KFD eviction, which involves preempting user mode queues before signaling the fence. There is one such fence per process. v2: * Grab a reference to mm_struct * Dereference fence after NULL check * Simplify fence release, no need to signal without anyone waiting * Added signed-off-by Harish, who is the original author of this code v3: * update MAINTAINERS file * change amd_kfd_ prefix to amdkfd_ * remove useless initialization of variable to NULL v4: * set amdkfd_fence_ops to be static * Suggested by: Fengguang Wu Signed-off-by: Harish Kasiviswanathan Signed-off-by: Felix Kuehling Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdgpu/Makefile | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 15 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c | 179 +++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 5 +- drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 21 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 18 +++ drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 6 + 7 files changed, 241 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 353c937d947d..5dd317579e77 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -129,6 +129,7 @@ amdgpu-y += \ # add amdkfd interfaces amdgpu-y += \ amdgpu_amdkfd.o \ + amdgpu_amdkfd_fence.o \ amdgpu_amdkfd_gfx_v8.o # add cgs diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index 2a519f9062ee..833dc26d402f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -29,6 +29,8 @@ #include #include +extern const struct kgd2kfd_calls *kgd2kfd; + struct amdgpu_device; struct kgd_mem { @@ -37,6 +39,19 @@ struct kgd_mem { void *cpu_ptr; }; +/* KFD Memory Eviction */ +struct amdgpu_amdkfd_fence { + struct dma_fence base; + struct mm_struct *mm; + spinlock_t lock; + char timeline_name[TASK_COMM_LEN]; +}; + +struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context, + struct mm_struct *mm); +bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm); +struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f); + int amdgpu_amdkfd_init(void); void amdgpu_amdkfd_fini(void); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c new file mode 100644 index 000000000000..2c14025e5e76 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c @@ -0,0 +1,179 @@ +/* + * Copyright 2016-2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "amdgpu_amdkfd.h" + +static const struct dma_fence_ops amdkfd_fence_ops; +static atomic_t fence_seq = ATOMIC_INIT(0); + +/* Eviction Fence + * Fence helper functions to deal with KFD memory eviction. + * Big Idea - Since KFD submissions are done by user queues, a BO cannot be + * evicted unless all the user queues for that process are evicted. + * + * All the BOs in a process share an eviction fence. When process X wants + * to map VRAM memory but TTM can't find enough space, TTM will attempt to + * evict BOs from its LRU list. TTM checks if the BO is valuable to evict + * by calling ttm_bo_driver->eviction_valuable(). + * + * ttm_bo_driver->eviction_valuable() - will return false if the BO belongs + * to process X. Otherwise, it will return true to indicate BO can be + * evicted by TTM. + * + * If ttm_bo_driver->eviction_valuable returns true, then TTM will continue + * the evcition process for that BO by calling ttm_bo_evict --> amdgpu_bo_move + * --> amdgpu_copy_buffer(). This sets up job in GPU scheduler. + * + * GPU Scheduler (amd_sched_main) - sets up a cb (fence_add_callback) to + * nofity when the BO is free to move. fence_add_callback --> enable_signaling + * --> amdgpu_amdkfd_fence.enable_signaling + * + * amdgpu_amdkfd_fence.enable_signaling - Start a work item that will quiesce + * user queues and signal fence. The work item will also start another delayed + * work item to restore BOs + */ + +struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context, + struct mm_struct *mm) +{ + struct amdgpu_amdkfd_fence *fence; + + fence = kzalloc(sizeof(*fence), GFP_KERNEL); + if (fence == NULL) + return NULL; + + /* This reference gets released in amdkfd_fence_release */ + mmgrab(mm); + fence->mm = mm; + get_task_comm(fence->timeline_name, current); + spin_lock_init(&fence->lock); + + dma_fence_init(&fence->base, &amdkfd_fence_ops, &fence->lock, + context, atomic_inc_return(&fence_seq)); + + return fence; +} + +struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f) +{ + struct amdgpu_amdkfd_fence *fence; + + if (!f) + return NULL; + + fence = container_of(f, struct amdgpu_amdkfd_fence, base); + if (fence && f->ops == &amdkfd_fence_ops) + return fence; + + return NULL; +} + +static const char *amdkfd_fence_get_driver_name(struct dma_fence *f) +{ + return "amdgpu_amdkfd_fence"; +} + +static const char *amdkfd_fence_get_timeline_name(struct dma_fence *f) +{ + struct amdgpu_amdkfd_fence *fence = to_amdgpu_amdkfd_fence(f); + + return fence->timeline_name; +} + +/** + * amdkfd_fence_enable_signaling - This gets called when TTM wants to evict + * a KFD BO and schedules a job to move the BO. + * If fence is already signaled return true. + * If fence is not signaled schedule a evict KFD process work item. + */ +static bool amdkfd_fence_enable_signaling(struct dma_fence *f) +{ + struct amdgpu_amdkfd_fence *fence = to_amdgpu_amdkfd_fence(f); + + if (!fence) + return false; + + if (dma_fence_is_signaled(f)) + return true; + + if (!kgd2kfd->schedule_evict_and_restore_process(fence->mm, f)) + return true; + + return false; +} + +/** + * amdkfd_fence_release - callback that fence can be freed + * + * @fence: fence + * + * This function is called when the reference count becomes zero. + * Drops the mm_struct reference and RCU schedules freeing up the fence. + */ +static void amdkfd_fence_release(struct dma_fence *f) +{ + struct amdgpu_amdkfd_fence *fence = to_amdgpu_amdkfd_fence(f); + + /* Unconditionally signal the fence. The process is getting + * terminated. + */ + if (WARN_ON(!fence)) + return; /* Not an amdgpu_amdkfd_fence */ + + mmdrop(fence->mm); + kfree_rcu(f, rcu); +} + +/** + * amdkfd_fence_check_mm - Check if @mm is same as that of the fence @f + * if same return TRUE else return FALSE. + * + * @f: [IN] fence + * @mm: [IN] mm that needs to be verified + */ +bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm) +{ + struct amdgpu_amdkfd_fence *fence = to_amdgpu_amdkfd_fence(f); + + if (!fence) + return false; + else if (fence->mm == mm) + return true; + + return false; +} + +static const struct dma_fence_ops amdkfd_fence_ops = { + .get_driver_name = amdkfd_fence_get_driver_name, + .get_timeline_name = amdkfd_fence_get_timeline_name, + .enable_signaling = amdkfd_fence_enable_signaling, + .signaled = NULL, + .wait = dma_fence_default_wait, + .release = amdkfd_fence_release, +}; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index 06436c3ebd2b..1a5911882657 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -36,8 +36,9 @@ #define AMDGPU_MAX_UVD_ENC_RINGS 2 /* some special values for the owner field */ -#define AMDGPU_FENCE_OWNER_UNDEFINED ((void*)0ul) -#define AMDGPU_FENCE_OWNER_VM ((void*)1ul) +#define AMDGPU_FENCE_OWNER_UNDEFINED ((void *)0ul) +#define AMDGPU_FENCE_OWNER_VM ((void *)1ul) +#define AMDGPU_FENCE_OWNER_KFD ((void *)2ul) #define AMDGPU_FENCE_FLAG_64BIT (1 << 0) #define AMDGPU_FENCE_FLAG_INT (1 << 1) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index df65c66dc956..b8d3b87fd43e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -31,6 +31,7 @@ #include #include "amdgpu.h" #include "amdgpu_trace.h" +#include "amdgpu_amdkfd.h" struct amdgpu_sync_entry { struct hlist_node node; @@ -85,11 +86,20 @@ static bool amdgpu_sync_same_dev(struct amdgpu_device *adev, */ static void *amdgpu_sync_get_owner(struct dma_fence *f) { - struct drm_sched_fence *s_fence = to_drm_sched_fence(f); + struct drm_sched_fence *s_fence; + struct amdgpu_amdkfd_fence *kfd_fence; + + if (!f) + return AMDGPU_FENCE_OWNER_UNDEFINED; + s_fence = to_drm_sched_fence(f); if (s_fence) return s_fence->owner; + kfd_fence = to_amdgpu_amdkfd_fence(f); + if (kfd_fence) + return AMDGPU_FENCE_OWNER_KFD; + return AMDGPU_FENCE_OWNER_UNDEFINED; } @@ -204,11 +214,18 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, for (i = 0; i < flist->shared_count; ++i) { f = rcu_dereference_protected(flist->shared[i], reservation_object_held(resv)); + /* We only want to trigger KFD eviction fences on + * evict or move jobs. Skip KFD fences otherwise. + */ + fence_owner = amdgpu_sync_get_owner(f); + if (fence_owner == AMDGPU_FENCE_OWNER_KFD && + owner != AMDGPU_FENCE_OWNER_UNDEFINED) + continue; + if (amdgpu_sync_same_dev(adev, f)) { /* VM updates are only interesting * for other VM updates and moves. */ - fence_owner = amdgpu_sync_get_owner(f); if ((owner != AMDGPU_FENCE_OWNER_UNDEFINED) && (fence_owner != AMDGPU_FENCE_OWNER_UNDEFINED) && ((owner == AMDGPU_FENCE_OWNER_VM) != diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 28c33d711bab..5fcb3488a595 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -46,6 +46,7 @@ #include "amdgpu.h" #include "amdgpu_object.h" #include "amdgpu_trace.h" +#include "amdgpu_amdkfd.h" #include "bif/bif_4_1_d.h" #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) @@ -1171,6 +1172,23 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, { unsigned long num_pages = bo->mem.num_pages; struct drm_mm_node *node = bo->mem.mm_node; + struct reservation_object_list *flist; + struct dma_fence *f; + int i; + + /* If bo is a KFD BO, check if the bo belongs to the current process. + * If true, then return false as any KFD process needs all its BOs to + * be resident to run successfully + */ + flist = reservation_object_get_list(bo->resv); + if (flist) { + for (i = 0; i < flist->shared_count; ++i) { + f = rcu_dereference_protected(flist->shared[i], + reservation_object_held(bo->resv)); + if (amdkfd_fence_check_mm(f, current->mm)) + return false; + } + } switch (bo->mem.mem_type) { case TTM_PL_TT: diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 94eab54864bf..9e352499c409 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -30,6 +30,7 @@ #include #include +#include struct pci_dev; @@ -286,6 +287,9 @@ struct kfd2kgd_calls { * * @resume: Notifies amdkfd about a resume action done to a kgd device * + * @schedule_evict_and_restore_process: Schedules work queue that will prepare + * for safe eviction of KFD BOs that belong to the specified process. + * * This structure contains function callback pointers so the kgd driver * will notify to the amdkfd about certain status changes. * @@ -300,6 +304,8 @@ struct kgd2kfd_calls { void (*interrupt)(struct kfd_dev *kfd, const void *ih_ring_entry); void (*suspend)(struct kfd_dev *kfd); int (*resume)(struct kfd_dev *kfd); + int (*schedule_evict_and_restore_process)(struct mm_struct *mm, + struct dma_fence *fence); }; int kgd2kfd_init(unsigned interface_version, -- cgit v1.2.3 From 155494dbbbf4d6d6512b8bc2dc6bc483e47e1c71 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Tue, 6 Feb 2018 20:32:36 -0500 Subject: drm/amdgpu: Update kgd2kfd_shared_resources for dGPU support Add GPUVM size and DRM render node. Also add function to query the VMID mask to avoid hard-coding it in multiple places later. v2: cut off GPUVM size at the VA hole Signed-off-by: Felix Kuehling Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 20 ++++++++++++++++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 2 ++ drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 6 ++++++ 3 files changed, 26 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 141d11dfede0..3ec4bada61d7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -30,6 +30,8 @@ const struct kgd2kfd_calls *kgd2kfd; bool (*kgd2kfd_init_p)(unsigned int, const struct kgd2kfd_calls**); +static const unsigned int compute_vmid_bitmap = 0xFF00; + int amdgpu_amdkfd_init(void) { int ret; @@ -137,9 +139,13 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev) int last_valid_bit; if (adev->kfd) { struct kgd2kfd_shared_resources gpu_resources = { - .compute_vmid_bitmap = 0xFF00, + .compute_vmid_bitmap = compute_vmid_bitmap, .num_pipe_per_mec = adev->gfx.mec.num_pipe_per_mec, - .num_queue_per_pipe = adev->gfx.mec.num_queue_per_pipe + .num_queue_per_pipe = adev->gfx.mec.num_queue_per_pipe, + .gpuvm_size = min(adev->vm_manager.max_pfn + << AMDGPU_GPU_PAGE_SHIFT, + AMDGPU_VA_HOLE_START), + .drm_render_minor = adev->ddev->render->index }; /* this is going to have a few of the MSBs set that we need to @@ -359,3 +365,13 @@ uint64_t amdgpu_amdkfd_get_vram_usage(struct kgd_dev *kgd) return amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); } + +bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid) +{ + if (adev->kfd) { + if ((1 << vmid) & compute_vmid_bitmap) + return true; + } + + return false; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index 833dc26d402f..d1bab32622df 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -66,6 +66,8 @@ void amdgpu_amdkfd_device_fini(struct amdgpu_device *adev); struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void); struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void); +bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid); + /* Shared API */ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, void **mem_obj, uint64_t *gpu_addr, diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 9e352499c409..36c706aff2ac 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -108,6 +108,12 @@ struct kgd2kfd_shared_resources { /* Number of bytes at start of aperture reserved for KGD. */ size_t doorbell_start_offset; + + /* GPUVM address space size in bytes */ + uint64_t gpuvm_size; + + /* Minor device number of the render node */ + int drm_render_minor; }; struct tile_config { -- cgit v1.2.3 From 3c728d3aa1fd5c7c2461835a93ac8fad57813db6 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Tue, 6 Feb 2018 20:32:37 -0500 Subject: drm/amdgpu: add amdgpu_sync_clone Cloning a sync object is useful for waiting for a sync object without locking the original structure indefinitely, blocking other threads. Signed-off-by: Felix Kuehling Acked-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 35 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h | 1 + 2 files changed, 36 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index b8d3b87fd43e..2d6f5ec77a68 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -322,6 +322,41 @@ struct dma_fence *amdgpu_sync_get_fence(struct amdgpu_sync *sync, bool *explicit return NULL; } +/** + * amdgpu_sync_clone - clone a sync object + * + * @source: sync object to clone + * @clone: pointer to destination sync object + * + * Adds references to all unsignaled fences in @source to @clone. Also + * removes signaled fences from @source while at it. + */ +int amdgpu_sync_clone(struct amdgpu_sync *source, struct amdgpu_sync *clone) +{ + struct amdgpu_sync_entry *e; + struct hlist_node *tmp; + struct dma_fence *f; + int i, r; + + hash_for_each_safe(source->fences, i, tmp, e, node) { + f = e->fence; + if (!dma_fence_is_signaled(f)) { + r = amdgpu_sync_fence(NULL, clone, f, e->explicit); + if (r) + return r; + } else { + hash_del(&e->node); + dma_fence_put(f); + kmem_cache_free(amdgpu_sync_slab, e); + } + } + + dma_fence_put(clone->last_vm_update); + clone->last_vm_update = dma_fence_get(source->last_vm_update); + + return 0; +} + int amdgpu_sync_wait(struct amdgpu_sync *sync, bool intr) { struct amdgpu_sync_entry *e; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h index 7aba38d5c9df..10cf23a57f17 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h @@ -50,6 +50,7 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, struct dma_fence *amdgpu_sync_peek_fence(struct amdgpu_sync *sync, struct amdgpu_ring *ring); struct dma_fence *amdgpu_sync_get_fence(struct amdgpu_sync *sync, bool *explicit); +int amdgpu_sync_clone(struct amdgpu_sync *source, struct amdgpu_sync *clone); int amdgpu_sync_wait(struct amdgpu_sync *sync, bool intr); void amdgpu_sync_free(struct amdgpu_sync *sync); int amdgpu_sync_init(void); -- cgit v1.2.3 From a46a2cd103a863724d668c86dca86bd0d93a19e4 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Tue, 6 Feb 2018 20:32:38 -0500 Subject: drm/amdgpu: Add GPUVM memory management functions for KFD v2: * Removed unused flags from struct kgd_mem * Updated some comments * Added a check to unmap_memory_from_gpu whether BO was mapped v3: add mutex_destroy in relevant places Signed-off-by: Felix Kuehling Acked-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdgpu/Makefile | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 91 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 66 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 67 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 1506 +++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 4 + drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 7 + drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 77 ++ 10 files changed, 1818 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 5dd317579e77..8522c2ea1f3e 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -130,6 +130,7 @@ amdgpu-y += \ amdgpu-y += \ amdgpu_amdkfd.o \ amdgpu_amdkfd_fence.o \ + amdgpu_amdkfd_gpuvm.o \ amdgpu_amdkfd_gfx_v8.o # add cgs diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 3ec4bada61d7..5a881107a15a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -58,6 +58,7 @@ int amdgpu_amdkfd_init(void) #else ret = -ENOENT; #endif + amdgpu_amdkfd_gpuvm_init_mem_limits(); return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index d1bab32622df..05a228d60241 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -28,15 +28,41 @@ #include #include #include +#include +#include "amdgpu_sync.h" +#include "amdgpu_vm.h" extern const struct kgd2kfd_calls *kgd2kfd; struct amdgpu_device; +struct kfd_bo_va_list { + struct list_head bo_list; + struct amdgpu_bo_va *bo_va; + void *kgd_dev; + bool is_mapped; + uint64_t va; + uint64_t pte_flags; +}; + struct kgd_mem { + struct mutex lock; struct amdgpu_bo *bo; - uint64_t gpu_addr; - void *cpu_ptr; + struct list_head bo_va_list; + /* protected by amdkfd_process_info.lock */ + struct ttm_validate_buffer validate_list; + struct ttm_validate_buffer resv_list; + uint32_t domain; + unsigned int mapped_to_gpu_memory; + uint64_t va; + + uint32_t mapping_flags; + + struct amdkfd_process_info *process_info; + + struct amdgpu_sync sync; + + bool aql_queue; }; /* KFD Memory Eviction */ @@ -52,6 +78,41 @@ struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context, bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm); struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f); +struct amdkfd_process_info { + /* List head of all VMs that belong to a KFD process */ + struct list_head vm_list_head; + /* List head for all KFD BOs that belong to a KFD process. */ + struct list_head kfd_bo_list; + /* Lock to protect kfd_bo_list */ + struct mutex lock; + + /* Number of VMs */ + unsigned int n_vms; + /* Eviction Fence */ + struct amdgpu_amdkfd_fence *eviction_fence; +}; + +/* struct amdkfd_vm - + * For Memory Eviction KGD requires a mechanism to keep track of all KFD BOs + * belonging to a KFD process. All the VMs belonging to the same process point + * to the same amdkfd_process_info. + */ +struct amdkfd_vm { + /* Keep base as the first parameter for pointer compatibility between + * amdkfd_vm and amdgpu_vm. + */ + struct amdgpu_vm base; + + /* List node in amdkfd_process_info.vm_list_head*/ + struct list_head vm_list_node; + + struct amdgpu_device *adev; + /* Points to the KFD process VM info*/ + struct amdkfd_process_info *process_info; + + uint64_t pd_phys_addr; +}; + int amdgpu_amdkfd_init(void); void amdgpu_amdkfd_fini(void); @@ -96,4 +157,30 @@ uint64_t amdgpu_amdkfd_get_vram_usage(struct kgd_dev *kgd); valid; \ }) +/* GPUVM API */ +int amdgpu_amdkfd_gpuvm_create_process_vm(struct kgd_dev *kgd, void **vm, + void **process_info, + struct dma_fence **ef); +void amdgpu_amdkfd_gpuvm_destroy_process_vm(struct kgd_dev *kgd, void *vm); +uint32_t amdgpu_amdkfd_gpuvm_get_process_page_dir(void *vm); +int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( + struct kgd_dev *kgd, uint64_t va, uint64_t size, + void *vm, struct kgd_mem **mem, + uint64_t *offset, uint32_t flags); +int amdgpu_amdkfd_gpuvm_free_memory_of_gpu( + struct kgd_dev *kgd, struct kgd_mem *mem); +int amdgpu_amdkfd_gpuvm_map_memory_to_gpu( + struct kgd_dev *kgd, struct kgd_mem *mem, void *vm); +int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu( + struct kgd_dev *kgd, struct kgd_mem *mem, void *vm); +int amdgpu_amdkfd_gpuvm_sync_memory( + struct kgd_dev *kgd, struct kgd_mem *mem, bool intr); +int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_dev *kgd, + struct kgd_mem *mem, void **kptr, uint64_t *size); +int amdgpu_amdkfd_gpuvm_restore_process_bos(void *process_info, + struct dma_fence **ef); + +void amdgpu_amdkfd_gpuvm_init_mem_limits(void); +void amdgpu_amdkfd_unreserve_system_memory_limit(struct amdgpu_bo *bo); + #endif /* AMDGPU_AMDKFD_H_INCLUDED */ 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 1362181b10d0..65783d1eddca 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -143,6 +143,10 @@ static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type); static void set_scratch_backing_va(struct kgd_dev *kgd, uint64_t va, uint32_t vmid); +static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid, + uint32_t page_table_base); +static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid); +static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid); /* Because of REG_GET_FIELD() being used, we put this function in the * asic specific file. @@ -199,7 +203,20 @@ static const struct kfd2kgd_calls kfd2kgd = { .set_scratch_backing_va = set_scratch_backing_va, .get_tile_config = get_tile_config, .get_cu_info = get_cu_info, - .get_vram_usage = amdgpu_amdkfd_get_vram_usage + .get_vram_usage = amdgpu_amdkfd_get_vram_usage, + .create_process_vm = amdgpu_amdkfd_gpuvm_create_process_vm, + .destroy_process_vm = amdgpu_amdkfd_gpuvm_destroy_process_vm, + .get_process_page_dir = amdgpu_amdkfd_gpuvm_get_process_page_dir, + .set_vm_context_page_table_base = set_vm_context_page_table_base, + .alloc_memory_of_gpu = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu, + .free_memory_of_gpu = amdgpu_amdkfd_gpuvm_free_memory_of_gpu, + .map_memory_to_gpu = amdgpu_amdkfd_gpuvm_map_memory_to_gpu, + .unmap_memory_to_gpu = amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu, + .sync_memory = amdgpu_amdkfd_gpuvm_sync_memory, + .map_gtt_bo_to_kernel = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel, + .restore_process_bos = amdgpu_amdkfd_gpuvm_restore_process_bos, + .invalidate_tlbs = invalidate_tlbs, + .invalidate_tlbs_vmid = invalidate_tlbs_vmid, }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void) @@ -855,3 +872,50 @@ static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) return hdr->common.ucode_version; } +static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid, + uint32_t page_table_base) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) { + pr_err("trying to set page table base for wrong VMID\n"); + return; + } + WREG32(mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + vmid - 8, page_table_base); +} + +static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid) +{ + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + int vmid; + unsigned int tmp; + + for (vmid = 0; vmid < 16; vmid++) { + if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) + continue; + + tmp = RREG32(mmATC_VMID0_PASID_MAPPING + vmid); + if ((tmp & ATC_VMID0_PASID_MAPPING__VALID_MASK) && + (tmp & ATC_VMID0_PASID_MAPPING__PASID_MASK) == pasid) { + WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); + RREG32(mmVM_INVALIDATE_RESPONSE); + break; + } + } + + return 0; +} + +static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid) +{ + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) { + pr_err("non kfd vmid\n"); + return 0; + } + + WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); + RREG32(mmVM_INVALIDATE_RESPONSE); + return 0; +} 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 5130eac7afdd..1b5bf1353f0c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -101,6 +101,10 @@ static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type); static void set_scratch_backing_va(struct kgd_dev *kgd, uint64_t va, uint32_t vmid); +static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid, + uint32_t page_table_base); +static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid); +static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid); /* Because of REG_GET_FIELD() being used, we put this function in the * asic specific file. @@ -159,7 +163,20 @@ static const struct kfd2kgd_calls kfd2kgd = { .set_scratch_backing_va = set_scratch_backing_va, .get_tile_config = get_tile_config, .get_cu_info = get_cu_info, - .get_vram_usage = amdgpu_amdkfd_get_vram_usage + .get_vram_usage = amdgpu_amdkfd_get_vram_usage, + .create_process_vm = amdgpu_amdkfd_gpuvm_create_process_vm, + .destroy_process_vm = amdgpu_amdkfd_gpuvm_destroy_process_vm, + .get_process_page_dir = amdgpu_amdkfd_gpuvm_get_process_page_dir, + .set_vm_context_page_table_base = set_vm_context_page_table_base, + .alloc_memory_of_gpu = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu, + .free_memory_of_gpu = amdgpu_amdkfd_gpuvm_free_memory_of_gpu, + .map_memory_to_gpu = amdgpu_amdkfd_gpuvm_map_memory_to_gpu, + .unmap_memory_to_gpu = amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu, + .sync_memory = amdgpu_amdkfd_gpuvm_sync_memory, + .map_gtt_bo_to_kernel = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel, + .restore_process_bos = amdgpu_amdkfd_gpuvm_restore_process_bos, + .invalidate_tlbs = invalidate_tlbs, + .invalidate_tlbs_vmid = invalidate_tlbs_vmid, }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void) @@ -816,3 +833,51 @@ static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) /* Only 12 bit in use*/ return hdr->common.ucode_version; } + +static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid, + uint32_t page_table_base) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) { + pr_err("trying to set page table base for wrong VMID\n"); + return; + } + WREG32(mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + vmid - 8, page_table_base); +} + +static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid) +{ + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + int vmid; + unsigned int tmp; + + for (vmid = 0; vmid < 16; vmid++) { + if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) + continue; + + tmp = RREG32(mmATC_VMID0_PASID_MAPPING + vmid); + if ((tmp & ATC_VMID0_PASID_MAPPING__VALID_MASK) && + (tmp & ATC_VMID0_PASID_MAPPING__PASID_MASK) == pasid) { + WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); + RREG32(mmVM_INVALIDATE_RESPONSE); + break; + } + } + + return 0; +} + +static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid) +{ + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) { + pr_err("non kfd vmid %d\n", vmid); + return -EINVAL; + } + + WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); + RREG32(mmVM_INVALIDATE_RESPONSE); + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c new file mode 100644 index 000000000000..e0371a9967b9 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -0,0 +1,1506 @@ +/* + * Copyright 2014-2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#define pr_fmt(fmt) "kfd2kgd: " fmt + +#include +#include +#include "amdgpu_object.h" +#include "amdgpu_vm.h" +#include "amdgpu_amdkfd.h" + +/* Special VM and GART address alignment needed for VI pre-Fiji due to + * a HW bug. + */ +#define VI_BO_SIZE_ALIGN (0x8000) + +/* Impose limit on how much memory KFD can use */ +static struct { + uint64_t max_system_mem_limit; + int64_t system_mem_used; + spinlock_t mem_limit_lock; +} kfd_mem_limit; + +/* Struct used for amdgpu_amdkfd_bo_validate */ +struct amdgpu_vm_parser { + uint32_t domain; + bool wait; +}; + +static const char * const domain_bit_to_string[] = { + "CPU", + "GTT", + "VRAM", + "GDS", + "GWS", + "OA" +}; + +#define domain_string(domain) domain_bit_to_string[ffs(domain)-1] + + + +static inline struct amdgpu_device *get_amdgpu_device(struct kgd_dev *kgd) +{ + return (struct amdgpu_device *)kgd; +} + +static bool check_if_add_bo_to_vm(struct amdgpu_vm *avm, + struct kgd_mem *mem) +{ + struct kfd_bo_va_list *entry; + + list_for_each_entry(entry, &mem->bo_va_list, bo_list) + if (entry->bo_va->base.vm == avm) + return false; + + return true; +} + +/* Set memory usage limits. Current, limits are + * System (kernel) memory - 3/8th System RAM + */ +void amdgpu_amdkfd_gpuvm_init_mem_limits(void) +{ + struct sysinfo si; + uint64_t mem; + + si_meminfo(&si); + mem = si.totalram - si.totalhigh; + mem *= si.mem_unit; + + spin_lock_init(&kfd_mem_limit.mem_limit_lock); + kfd_mem_limit.max_system_mem_limit = (mem >> 1) - (mem >> 3); + pr_debug("Kernel memory limit %lluM\n", + (kfd_mem_limit.max_system_mem_limit >> 20)); +} + +static int amdgpu_amdkfd_reserve_system_mem_limit(struct amdgpu_device *adev, + uint64_t size, u32 domain) +{ + size_t acc_size; + int ret = 0; + + acc_size = ttm_bo_dma_acc_size(&adev->mman.bdev, size, + sizeof(struct amdgpu_bo)); + + spin_lock(&kfd_mem_limit.mem_limit_lock); + if (domain == AMDGPU_GEM_DOMAIN_GTT) { + if (kfd_mem_limit.system_mem_used + (acc_size + size) > + kfd_mem_limit.max_system_mem_limit) { + ret = -ENOMEM; + goto err_no_mem; + } + kfd_mem_limit.system_mem_used += (acc_size + size); + } +err_no_mem: + spin_unlock(&kfd_mem_limit.mem_limit_lock); + return ret; +} + +static void unreserve_system_mem_limit(struct amdgpu_device *adev, + uint64_t size, u32 domain) +{ + size_t acc_size; + + acc_size = ttm_bo_dma_acc_size(&adev->mman.bdev, size, + sizeof(struct amdgpu_bo)); + + spin_lock(&kfd_mem_limit.mem_limit_lock); + if (domain == AMDGPU_GEM_DOMAIN_GTT) + kfd_mem_limit.system_mem_used -= (acc_size + size); + WARN_ONCE(kfd_mem_limit.system_mem_used < 0, + "kfd system memory accounting unbalanced"); + + spin_unlock(&kfd_mem_limit.mem_limit_lock); +} + +void amdgpu_amdkfd_unreserve_system_memory_limit(struct amdgpu_bo *bo) +{ + spin_lock(&kfd_mem_limit.mem_limit_lock); + + if (bo->preferred_domains == AMDGPU_GEM_DOMAIN_GTT) { + kfd_mem_limit.system_mem_used -= + (bo->tbo.acc_size + amdgpu_bo_size(bo)); + } + WARN_ONCE(kfd_mem_limit.system_mem_used < 0, + "kfd system memory accounting unbalanced"); + + spin_unlock(&kfd_mem_limit.mem_limit_lock); +} + + +/* amdgpu_amdkfd_remove_eviction_fence - Removes eviction fence(s) from BO's + * reservation object. + * + * @bo: [IN] Remove eviction fence(s) from this BO + * @ef: [IN] If ef is specified, then this eviction fence is removed if it + * is present in the shared list. + * @ef_list: [OUT] Returns list of eviction fences. These fences are removed + * from BO's reservation object shared list. + * @ef_count: [OUT] Number of fences in ef_list. + * + * NOTE: If called with ef_list, then amdgpu_amdkfd_add_eviction_fence must be + * called to restore the eviction fences and to avoid memory leak. This is + * useful for shared BOs. + * NOTE: Must be called with BO reserved i.e. bo->tbo.resv->lock held. + */ +static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo, + struct amdgpu_amdkfd_fence *ef, + struct amdgpu_amdkfd_fence ***ef_list, + unsigned int *ef_count) +{ + struct reservation_object_list *fobj; + struct reservation_object *resv; + unsigned int i = 0, j = 0, k = 0, shared_count; + unsigned int count = 0; + struct amdgpu_amdkfd_fence **fence_list; + + if (!ef && !ef_list) + return -EINVAL; + + if (ef_list) { + *ef_list = NULL; + *ef_count = 0; + } + + resv = bo->tbo.resv; + fobj = reservation_object_get_list(resv); + + if (!fobj) + return 0; + + preempt_disable(); + write_seqcount_begin(&resv->seq); + + /* Go through all the shared fences in the resevation object. If + * ef is specified and it exists in the list, remove it and reduce the + * count. If ef is not specified, then get the count of eviction fences + * present. + */ + shared_count = fobj->shared_count; + for (i = 0; i < shared_count; ++i) { + struct dma_fence *f; + + f = rcu_dereference_protected(fobj->shared[i], + reservation_object_held(resv)); + + if (ef) { + if (f->context == ef->base.context) { + dma_fence_put(f); + fobj->shared_count--; + } else { + RCU_INIT_POINTER(fobj->shared[j++], f); + } + } else if (to_amdgpu_amdkfd_fence(f)) + count++; + } + write_seqcount_end(&resv->seq); + preempt_enable(); + + if (ef || !count) + return 0; + + /* Alloc memory for count number of eviction fence pointers. Fill the + * ef_list array and ef_count + */ + fence_list = kcalloc(count, sizeof(struct amdgpu_amdkfd_fence *), + GFP_KERNEL); + if (!fence_list) + return -ENOMEM; + + preempt_disable(); + write_seqcount_begin(&resv->seq); + + j = 0; + for (i = 0; i < shared_count; ++i) { + struct dma_fence *f; + struct amdgpu_amdkfd_fence *efence; + + f = rcu_dereference_protected(fobj->shared[i], + reservation_object_held(resv)); + + efence = to_amdgpu_amdkfd_fence(f); + if (efence) { + fence_list[k++] = efence; + fobj->shared_count--; + } else { + RCU_INIT_POINTER(fobj->shared[j++], f); + } + } + + write_seqcount_end(&resv->seq); + preempt_enable(); + + *ef_list = fence_list; + *ef_count = k; + + return 0; +} + +/* amdgpu_amdkfd_add_eviction_fence - Adds eviction fence(s) back into BO's + * reservation object. + * + * @bo: [IN] Add eviction fences to this BO + * @ef_list: [IN] List of eviction fences to be added + * @ef_count: [IN] Number of fences in ef_list. + * + * NOTE: Must call amdgpu_amdkfd_remove_eviction_fence before calling this + * function. + */ +static void amdgpu_amdkfd_add_eviction_fence(struct amdgpu_bo *bo, + struct amdgpu_amdkfd_fence **ef_list, + unsigned int ef_count) +{ + int i; + + if (!ef_list || !ef_count) + return; + + for (i = 0; i < ef_count; i++) { + amdgpu_bo_fence(bo, &ef_list[i]->base, true); + /* Re-adding the fence takes an additional reference. Drop that + * reference. + */ + dma_fence_put(&ef_list[i]->base); + } + + kfree(ef_list); +} + +static int amdgpu_amdkfd_bo_validate(struct amdgpu_bo *bo, uint32_t domain, + bool wait) +{ + struct ttm_operation_ctx ctx = { false, false }; + int ret; + + if (WARN(amdgpu_ttm_tt_get_usermm(bo->tbo.ttm), + "Called with userptr BO")) + return -EINVAL; + + amdgpu_ttm_placement_from_domain(bo, domain); + + ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); + if (ret) + goto validate_fail; + if (wait) { + struct amdgpu_amdkfd_fence **ef_list; + unsigned int ef_count; + + ret = amdgpu_amdkfd_remove_eviction_fence(bo, NULL, &ef_list, + &ef_count); + if (ret) + goto validate_fail; + + ttm_bo_wait(&bo->tbo, false, false); + amdgpu_amdkfd_add_eviction_fence(bo, ef_list, ef_count); + } + +validate_fail: + return ret; +} + +static int amdgpu_amdkfd_validate(void *param, struct amdgpu_bo *bo) +{ + struct amdgpu_vm_parser *p = param; + + return amdgpu_amdkfd_bo_validate(bo, p->domain, p->wait); +} + +/* vm_validate_pt_pd_bos - Validate page table and directory BOs + * + * Page directories are not updated here because huge page handling + * during page table updates can invalidate page directory entries + * again. Page directories are only updated after updating page + * tables. + */ +static int vm_validate_pt_pd_bos(struct amdkfd_vm *vm) +{ + struct amdgpu_bo *pd = vm->base.root.base.bo; + struct amdgpu_device *adev = amdgpu_ttm_adev(pd->tbo.bdev); + struct amdgpu_vm_parser param; + uint64_t addr, flags = AMDGPU_PTE_VALID; + int ret; + + param.domain = AMDGPU_GEM_DOMAIN_VRAM; + param.wait = false; + + ret = amdgpu_vm_validate_pt_bos(adev, &vm->base, amdgpu_amdkfd_validate, + ¶m); + if (ret) { + pr_err("amdgpu: failed to validate PT BOs\n"); + return ret; + } + + ret = amdgpu_amdkfd_validate(¶m, pd); + if (ret) { + pr_err("amdgpu: failed to validate PD\n"); + return ret; + } + + addr = amdgpu_bo_gpu_offset(vm->base.root.base.bo); + amdgpu_gmc_get_vm_pde(adev, -1, &addr, &flags); + vm->pd_phys_addr = addr; + + if (vm->base.use_cpu_for_update) { + ret = amdgpu_bo_kmap(pd, NULL); + if (ret) { + pr_err("amdgpu: failed to kmap PD, ret=%d\n", ret); + return ret; + } + } + + return 0; +} + +static int sync_vm_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync, + struct dma_fence *f) +{ + int ret = amdgpu_sync_fence(adev, sync, f, false); + + /* Sync objects can't handle multiple GPUs (contexts) updating + * sync->last_vm_update. Fortunately we don't need it for + * KFD's purposes, so we can just drop that fence. + */ + if (sync->last_vm_update) { + dma_fence_put(sync->last_vm_update); + sync->last_vm_update = NULL; + } + + return ret; +} + +static int vm_update_pds(struct amdgpu_vm *vm, struct amdgpu_sync *sync) +{ + struct amdgpu_bo *pd = vm->root.base.bo; + struct amdgpu_device *adev = amdgpu_ttm_adev(pd->tbo.bdev); + int ret; + + ret = amdgpu_vm_update_directories(adev, vm); + if (ret) + return ret; + + return sync_vm_fence(adev, sync, vm->last_update); +} + +/* add_bo_to_vm - Add a BO to a VM + * + * Everything that needs to bo done only once when a BO is first added + * to a VM. It can later be mapped and unmapped many times without + * repeating these steps. + * + * 1. Allocate and initialize BO VA entry data structure + * 2. Add BO to the VM + * 3. Determine ASIC-specific PTE flags + * 4. Alloc page tables and directories if needed + * 4a. Validate new page tables and directories + */ +static int add_bo_to_vm(struct amdgpu_device *adev, struct kgd_mem *mem, + struct amdgpu_vm *avm, bool is_aql, + struct kfd_bo_va_list **p_bo_va_entry) +{ + int ret; + struct kfd_bo_va_list *bo_va_entry; + struct amdkfd_vm *kvm = container_of(avm, + struct amdkfd_vm, base); + struct amdgpu_bo *pd = avm->root.base.bo; + struct amdgpu_bo *bo = mem->bo; + uint64_t va = mem->va; + struct list_head *list_bo_va = &mem->bo_va_list; + unsigned long bo_size = bo->tbo.mem.size; + + if (!va) { + pr_err("Invalid VA when adding BO to VM\n"); + return -EINVAL; + } + + if (is_aql) + va += bo_size; + + bo_va_entry = kzalloc(sizeof(*bo_va_entry), GFP_KERNEL); + if (!bo_va_entry) + return -ENOMEM; + + pr_debug("\t add VA 0x%llx - 0x%llx to vm %p\n", va, + va + bo_size, avm); + + /* Add BO to VM internal data structures*/ + bo_va_entry->bo_va = amdgpu_vm_bo_add(adev, avm, bo); + if (!bo_va_entry->bo_va) { + ret = -EINVAL; + pr_err("Failed to add BO object to VM. ret == %d\n", + ret); + goto err_vmadd; + } + + bo_va_entry->va = va; + bo_va_entry->pte_flags = amdgpu_gmc_get_pte_flags(adev, + mem->mapping_flags); + bo_va_entry->kgd_dev = (void *)adev; + list_add(&bo_va_entry->bo_list, list_bo_va); + + if (p_bo_va_entry) + *p_bo_va_entry = bo_va_entry; + + /* Allocate new page tables if needed and validate + * them. Clearing of new page tables and validate need to wait + * on move fences. We don't want that to trigger the eviction + * fence, so remove it temporarily. + */ + amdgpu_amdkfd_remove_eviction_fence(pd, + kvm->process_info->eviction_fence, + NULL, NULL); + + ret = amdgpu_vm_alloc_pts(adev, avm, va, amdgpu_bo_size(bo)); + if (ret) { + pr_err("Failed to allocate pts, err=%d\n", ret); + goto err_alloc_pts; + } + + ret = vm_validate_pt_pd_bos(kvm); + if (ret) { + pr_err("validate_pt_pd_bos() failed\n"); + goto err_alloc_pts; + } + + /* Add the eviction fence back */ + amdgpu_bo_fence(pd, &kvm->process_info->eviction_fence->base, true); + + return 0; + +err_alloc_pts: + amdgpu_bo_fence(pd, &kvm->process_info->eviction_fence->base, true); + amdgpu_vm_bo_rmv(adev, bo_va_entry->bo_va); + list_del(&bo_va_entry->bo_list); +err_vmadd: + kfree(bo_va_entry); + return ret; +} + +static void remove_bo_from_vm(struct amdgpu_device *adev, + struct kfd_bo_va_list *entry, unsigned long size) +{ + pr_debug("\t remove VA 0x%llx - 0x%llx in entry %p\n", + entry->va, + entry->va + size, entry); + amdgpu_vm_bo_rmv(adev, entry->bo_va); + list_del(&entry->bo_list); + kfree(entry); +} + +static void add_kgd_mem_to_kfd_bo_list(struct kgd_mem *mem, + struct amdkfd_process_info *process_info) +{ + struct ttm_validate_buffer *entry = &mem->validate_list; + struct amdgpu_bo *bo = mem->bo; + + INIT_LIST_HEAD(&entry->head); + entry->shared = true; + entry->bo = &bo->tbo; + mutex_lock(&process_info->lock); + list_add_tail(&entry->head, &process_info->kfd_bo_list); + mutex_unlock(&process_info->lock); +} + +/* Reserving a BO and its page table BOs must happen atomically to + * avoid deadlocks. Some operations update multiple VMs at once. Track + * all the reservation info in a context structure. Optionally a sync + * object can track VM updates. + */ +struct bo_vm_reservation_context { + struct amdgpu_bo_list_entry kfd_bo; /* BO list entry for the KFD BO */ + unsigned int n_vms; /* Number of VMs reserved */ + struct amdgpu_bo_list_entry *vm_pd; /* Array of VM BO list entries */ + struct ww_acquire_ctx ticket; /* Reservation ticket */ + struct list_head list, duplicates; /* BO lists */ + struct amdgpu_sync *sync; /* Pointer to sync object */ + bool reserved; /* Whether BOs are reserved */ +}; + +enum bo_vm_match { + BO_VM_NOT_MAPPED = 0, /* Match VMs where a BO is not mapped */ + BO_VM_MAPPED, /* Match VMs where a BO is mapped */ + BO_VM_ALL, /* Match all VMs a BO was added to */ +}; + +/** + * reserve_bo_and_vm - reserve a BO and a VM unconditionally. + * @mem: KFD BO structure. + * @vm: the VM to reserve. + * @ctx: the struct that will be used in unreserve_bo_and_vms(). + */ +static int reserve_bo_and_vm(struct kgd_mem *mem, + struct amdgpu_vm *vm, + struct bo_vm_reservation_context *ctx) +{ + struct amdgpu_bo *bo = mem->bo; + int ret; + + WARN_ON(!vm); + + ctx->reserved = false; + ctx->n_vms = 1; + ctx->sync = &mem->sync; + + INIT_LIST_HEAD(&ctx->list); + INIT_LIST_HEAD(&ctx->duplicates); + + ctx->vm_pd = kcalloc(ctx->n_vms, sizeof(*ctx->vm_pd), GFP_KERNEL); + if (!ctx->vm_pd) + return -ENOMEM; + + ctx->kfd_bo.robj = bo; + ctx->kfd_bo.priority = 0; + ctx->kfd_bo.tv.bo = &bo->tbo; + ctx->kfd_bo.tv.shared = true; + ctx->kfd_bo.user_pages = NULL; + list_add(&ctx->kfd_bo.tv.head, &ctx->list); + + amdgpu_vm_get_pd_bo(vm, &ctx->list, &ctx->vm_pd[0]); + + ret = ttm_eu_reserve_buffers(&ctx->ticket, &ctx->list, + false, &ctx->duplicates); + if (!ret) + ctx->reserved = true; + else { + pr_err("Failed to reserve buffers in ttm\n"); + kfree(ctx->vm_pd); + ctx->vm_pd = NULL; + } + + return ret; +} + +/** + * reserve_bo_and_cond_vms - reserve a BO and some VMs conditionally + * @mem: KFD BO structure. + * @vm: the VM to reserve. If NULL, then all VMs associated with the BO + * is used. Otherwise, a single VM associated with the BO. + * @map_type: the mapping status that will be used to filter the VMs. + * @ctx: the struct that will be used in unreserve_bo_and_vms(). + * + * Returns 0 for success, negative for failure. + */ +static int reserve_bo_and_cond_vms(struct kgd_mem *mem, + struct amdgpu_vm *vm, enum bo_vm_match map_type, + struct bo_vm_reservation_context *ctx) +{ + struct amdgpu_bo *bo = mem->bo; + struct kfd_bo_va_list *entry; + unsigned int i; + int ret; + + ctx->reserved = false; + ctx->n_vms = 0; + ctx->vm_pd = NULL; + ctx->sync = &mem->sync; + + INIT_LIST_HEAD(&ctx->list); + INIT_LIST_HEAD(&ctx->duplicates); + + list_for_each_entry(entry, &mem->bo_va_list, bo_list) { + if ((vm && vm != entry->bo_va->base.vm) || + (entry->is_mapped != map_type + && map_type != BO_VM_ALL)) + continue; + + ctx->n_vms++; + } + + if (ctx->n_vms != 0) { + ctx->vm_pd = kcalloc(ctx->n_vms, sizeof(*ctx->vm_pd), + GFP_KERNEL); + if (!ctx->vm_pd) + return -ENOMEM; + } + + ctx->kfd_bo.robj = bo; + ctx->kfd_bo.priority = 0; + ctx->kfd_bo.tv.bo = &bo->tbo; + ctx->kfd_bo.tv.shared = true; + ctx->kfd_bo.user_pages = NULL; + list_add(&ctx->kfd_bo.tv.head, &ctx->list); + + i = 0; + list_for_each_entry(entry, &mem->bo_va_list, bo_list) { + if ((vm && vm != entry->bo_va->base.vm) || + (entry->is_mapped != map_type + && map_type != BO_VM_ALL)) + continue; + + amdgpu_vm_get_pd_bo(entry->bo_va->base.vm, &ctx->list, + &ctx->vm_pd[i]); + i++; + } + + ret = ttm_eu_reserve_buffers(&ctx->ticket, &ctx->list, + false, &ctx->duplicates); + if (!ret) + ctx->reserved = true; + else + pr_err("Failed to reserve buffers in ttm.\n"); + + if (ret) { + kfree(ctx->vm_pd); + ctx->vm_pd = NULL; + } + + return ret; +} + +/** + * unreserve_bo_and_vms - Unreserve BO and VMs from a reservation context + * @ctx: Reservation context to unreserve + * @wait: Optionally wait for a sync object representing pending VM updates + * @intr: Whether the wait is interruptible + * + * Also frees any resources allocated in + * reserve_bo_and_(cond_)vm(s). Returns the status from + * amdgpu_sync_wait. + */ +static int unreserve_bo_and_vms(struct bo_vm_reservation_context *ctx, + bool wait, bool intr) +{ + int ret = 0; + + if (wait) + ret = amdgpu_sync_wait(ctx->sync, intr); + + if (ctx->reserved) + ttm_eu_backoff_reservation(&ctx->ticket, &ctx->list); + kfree(ctx->vm_pd); + + ctx->sync = NULL; + + ctx->reserved = false; + ctx->vm_pd = NULL; + + return ret; +} + +static int unmap_bo_from_gpuvm(struct amdgpu_device *adev, + struct kfd_bo_va_list *entry, + struct amdgpu_sync *sync) +{ + struct amdgpu_bo_va *bo_va = entry->bo_va; + struct amdgpu_vm *vm = bo_va->base.vm; + struct amdkfd_vm *kvm = container_of(vm, struct amdkfd_vm, base); + struct amdgpu_bo *pd = vm->root.base.bo; + + /* Remove eviction fence from PD (and thereby from PTs too as + * they share the resv. object). Otherwise during PT update + * job (see amdgpu_vm_bo_update_mapping), eviction fence would + * get added to job->sync object and job execution would + * trigger the eviction fence. + */ + amdgpu_amdkfd_remove_eviction_fence(pd, + kvm->process_info->eviction_fence, + NULL, NULL); + amdgpu_vm_bo_unmap(adev, bo_va, entry->va); + + amdgpu_vm_clear_freed(adev, vm, &bo_va->last_pt_update); + + /* Add the eviction fence back */ + amdgpu_bo_fence(pd, &kvm->process_info->eviction_fence->base, true); + + sync_vm_fence(adev, sync, bo_va->last_pt_update); + + return 0; +} + +static int update_gpuvm_pte(struct amdgpu_device *adev, + struct kfd_bo_va_list *entry, + struct amdgpu_sync *sync) +{ + int ret; + struct amdgpu_vm *vm; + struct amdgpu_bo_va *bo_va; + struct amdgpu_bo *bo; + + bo_va = entry->bo_va; + vm = bo_va->base.vm; + bo = bo_va->base.bo; + + /* Update the page tables */ + ret = amdgpu_vm_bo_update(adev, bo_va, false); + if (ret) { + pr_err("amdgpu_vm_bo_update failed\n"); + return ret; + } + + return sync_vm_fence(adev, sync, bo_va->last_pt_update); +} + +static int map_bo_to_gpuvm(struct amdgpu_device *adev, + struct kfd_bo_va_list *entry, struct amdgpu_sync *sync) +{ + int ret; + + /* Set virtual address for the allocation */ + ret = amdgpu_vm_bo_map(adev, entry->bo_va, entry->va, 0, + amdgpu_bo_size(entry->bo_va->base.bo), + entry->pte_flags); + if (ret) { + pr_err("Failed to map VA 0x%llx in vm. ret %d\n", + entry->va, ret); + return ret; + } + + ret = update_gpuvm_pte(adev, entry, sync); + if (ret) { + pr_err("update_gpuvm_pte() failed\n"); + goto update_gpuvm_pte_failed; + } + + return 0; + +update_gpuvm_pte_failed: + unmap_bo_from_gpuvm(adev, entry, sync); + return ret; +} + +static int process_validate_vms(struct amdkfd_process_info *process_info) +{ + struct amdkfd_vm *peer_vm; + int ret; + + list_for_each_entry(peer_vm, &process_info->vm_list_head, + vm_list_node) { + ret = vm_validate_pt_pd_bos(peer_vm); + if (ret) + return ret; + } + + return 0; +} + +static int process_update_pds(struct amdkfd_process_info *process_info, + struct amdgpu_sync *sync) +{ + struct amdkfd_vm *peer_vm; + int ret; + + list_for_each_entry(peer_vm, &process_info->vm_list_head, + vm_list_node) { + ret = vm_update_pds(&peer_vm->base, sync); + if (ret) + return ret; + } + + return 0; +} + +int amdgpu_amdkfd_gpuvm_create_process_vm(struct kgd_dev *kgd, void **vm, + void **process_info, + struct dma_fence **ef) +{ + int ret; + struct amdkfd_vm *new_vm; + struct amdkfd_process_info *info; + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + new_vm = kzalloc(sizeof(*new_vm), GFP_KERNEL); + if (!new_vm) + return -ENOMEM; + + /* Initialize the VM context, allocate the page directory and zero it */ + ret = amdgpu_vm_init(adev, &new_vm->base, AMDGPU_VM_CONTEXT_COMPUTE, 0); + if (ret) { + pr_err("Failed init vm ret %d\n", ret); + goto vm_init_fail; + } + new_vm->adev = adev; + + if (!*process_info) { + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + ret = -ENOMEM; + goto alloc_process_info_fail; + } + + mutex_init(&info->lock); + INIT_LIST_HEAD(&info->vm_list_head); + INIT_LIST_HEAD(&info->kfd_bo_list); + + info->eviction_fence = + amdgpu_amdkfd_fence_create(dma_fence_context_alloc(1), + current->mm); + if (!info->eviction_fence) { + pr_err("Failed to create eviction fence\n"); + goto create_evict_fence_fail; + } + + *process_info = info; + *ef = dma_fence_get(&info->eviction_fence->base); + } + + new_vm->process_info = *process_info; + + mutex_lock(&new_vm->process_info->lock); + list_add_tail(&new_vm->vm_list_node, + &(new_vm->process_info->vm_list_head)); + new_vm->process_info->n_vms++; + mutex_unlock(&new_vm->process_info->lock); + + *vm = (void *) new_vm; + + pr_debug("Created process vm %p\n", *vm); + + return ret; + +create_evict_fence_fail: + mutex_destroy(&info->lock); + kfree(info); +alloc_process_info_fail: + amdgpu_vm_fini(adev, &new_vm->base); +vm_init_fail: + kfree(new_vm); + return ret; + +} + +void amdgpu_amdkfd_gpuvm_destroy_process_vm(struct kgd_dev *kgd, void *vm) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct amdkfd_vm *kfd_vm = (struct amdkfd_vm *) vm; + struct amdgpu_vm *avm = &kfd_vm->base; + struct amdgpu_bo *pd; + struct amdkfd_process_info *process_info; + + if (WARN_ON(!kgd || !vm)) + return; + + pr_debug("Destroying process vm %p\n", vm); + /* Release eviction fence from PD */ + pd = avm->root.base.bo; + amdgpu_bo_reserve(pd, false); + amdgpu_bo_fence(pd, NULL, false); + amdgpu_bo_unreserve(pd); + + process_info = kfd_vm->process_info; + + mutex_lock(&process_info->lock); + process_info->n_vms--; + list_del(&kfd_vm->vm_list_node); + mutex_unlock(&process_info->lock); + + /* Release per-process resources */ + if (!process_info->n_vms) { + WARN_ON(!list_empty(&process_info->kfd_bo_list)); + + dma_fence_put(&process_info->eviction_fence->base); + mutex_destroy(&process_info->lock); + kfree(process_info); + } + + /* Release the VM context */ + amdgpu_vm_fini(adev, avm); + kfree(vm); +} + +uint32_t amdgpu_amdkfd_gpuvm_get_process_page_dir(void *vm) +{ + struct amdkfd_vm *avm = (struct amdkfd_vm *)vm; + + return avm->pd_phys_addr >> AMDGPU_GPU_PAGE_SHIFT; +} + +int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( + struct kgd_dev *kgd, uint64_t va, uint64_t size, + void *vm, struct kgd_mem **mem, + uint64_t *offset, uint32_t flags) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct amdkfd_vm *kfd_vm = (struct amdkfd_vm *)vm; + struct amdgpu_bo *bo; + int byte_align; + u32 alloc_domain; + u64 alloc_flags; + uint32_t mapping_flags; + int ret; + + /* + * Check on which domain to allocate BO + */ + if (flags & ALLOC_MEM_FLAGS_VRAM) { + alloc_domain = AMDGPU_GEM_DOMAIN_VRAM; + alloc_flags = AMDGPU_GEM_CREATE_VRAM_CLEARED; + alloc_flags |= (flags & ALLOC_MEM_FLAGS_PUBLIC) ? + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED : + AMDGPU_GEM_CREATE_NO_CPU_ACCESS; + } else if (flags & ALLOC_MEM_FLAGS_GTT) { + alloc_domain = AMDGPU_GEM_DOMAIN_GTT; + alloc_flags = 0; + } else { + return -EINVAL; + } + + *mem = kzalloc(sizeof(struct kgd_mem), GFP_KERNEL); + if (!*mem) + return -ENOMEM; + INIT_LIST_HEAD(&(*mem)->bo_va_list); + mutex_init(&(*mem)->lock); + (*mem)->aql_queue = !!(flags & ALLOC_MEM_FLAGS_AQL_QUEUE_MEM); + + /* Workaround for AQL queue wraparound bug. Map the same + * memory twice. That means we only actually allocate half + * the memory. + */ + if ((*mem)->aql_queue) + size = size >> 1; + + /* Workaround for TLB bug on older VI chips */ + byte_align = (adev->family == AMDGPU_FAMILY_VI && + adev->asic_type != CHIP_FIJI && + adev->asic_type != CHIP_POLARIS10 && + adev->asic_type != CHIP_POLARIS11) ? + VI_BO_SIZE_ALIGN : 1; + + mapping_flags = AMDGPU_VM_PAGE_READABLE; + if (flags & ALLOC_MEM_FLAGS_WRITABLE) + mapping_flags |= AMDGPU_VM_PAGE_WRITEABLE; + if (flags & ALLOC_MEM_FLAGS_EXECUTABLE) + mapping_flags |= AMDGPU_VM_PAGE_EXECUTABLE; + if (flags & ALLOC_MEM_FLAGS_COHERENT) + mapping_flags |= AMDGPU_VM_MTYPE_UC; + else + mapping_flags |= AMDGPU_VM_MTYPE_NC; + (*mem)->mapping_flags = mapping_flags; + + amdgpu_sync_create(&(*mem)->sync); + + ret = amdgpu_amdkfd_reserve_system_mem_limit(adev, size, alloc_domain); + if (ret) { + pr_debug("Insufficient system memory\n"); + goto err_reserve_system_mem; + } + + pr_debug("\tcreate BO VA 0x%llx size 0x%llx domain %s\n", + va, size, domain_string(alloc_domain)); + + ret = amdgpu_bo_create(adev, size, byte_align, false, + alloc_domain, alloc_flags, NULL, NULL, &bo); + if (ret) { + pr_debug("Failed to create BO on domain %s. ret %d\n", + domain_string(alloc_domain), ret); + goto err_bo_create; + } + bo->kfd_bo = *mem; + (*mem)->bo = bo; + + (*mem)->va = va; + (*mem)->domain = alloc_domain; + (*mem)->mapped_to_gpu_memory = 0; + (*mem)->process_info = kfd_vm->process_info; + add_kgd_mem_to_kfd_bo_list(*mem, kfd_vm->process_info); + + if (offset) + *offset = amdgpu_bo_mmap_offset(bo); + + return 0; + +err_bo_create: + unreserve_system_mem_limit(adev, size, alloc_domain); +err_reserve_system_mem: + mutex_destroy(&(*mem)->lock); + kfree(*mem); + return ret; +} + +int amdgpu_amdkfd_gpuvm_free_memory_of_gpu( + struct kgd_dev *kgd, struct kgd_mem *mem) +{ + struct amdkfd_process_info *process_info = mem->process_info; + unsigned long bo_size = mem->bo->tbo.mem.size; + struct kfd_bo_va_list *entry, *tmp; + struct bo_vm_reservation_context ctx; + struct ttm_validate_buffer *bo_list_entry; + int ret; + + mutex_lock(&mem->lock); + + if (mem->mapped_to_gpu_memory > 0) { + pr_debug("BO VA 0x%llx size 0x%lx is still mapped.\n", + mem->va, bo_size); + mutex_unlock(&mem->lock); + return -EBUSY; + } + + mutex_unlock(&mem->lock); + /* lock is not needed after this, since mem is unused and will + * be freed anyway + */ + + /* Make sure restore workers don't access the BO any more */ + bo_list_entry = &mem->validate_list; + mutex_lock(&process_info->lock); + list_del(&bo_list_entry->head); + mutex_unlock(&process_info->lock); + + ret = reserve_bo_and_cond_vms(mem, NULL, BO_VM_ALL, &ctx); + if (unlikely(ret)) + return ret; + + /* The eviction fence should be removed by the last unmap. + * TODO: Log an error condition if the bo still has the eviction fence + * attached + */ + amdgpu_amdkfd_remove_eviction_fence(mem->bo, + process_info->eviction_fence, + NULL, NULL); + pr_debug("Release VA 0x%llx - 0x%llx\n", mem->va, + mem->va + bo_size * (1 + mem->aql_queue)); + + /* Remove from VM internal data structures */ + list_for_each_entry_safe(entry, tmp, &mem->bo_va_list, bo_list) + remove_bo_from_vm((struct amdgpu_device *)entry->kgd_dev, + entry, bo_size); + + ret = unreserve_bo_and_vms(&ctx, false, false); + + /* Free the sync object */ + amdgpu_sync_free(&mem->sync); + + /* Free the BO*/ + amdgpu_bo_unref(&mem->bo); + mutex_destroy(&mem->lock); + kfree(mem); + + return ret; +} + +int amdgpu_amdkfd_gpuvm_map_memory_to_gpu( + struct kgd_dev *kgd, struct kgd_mem *mem, void *vm) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct amdkfd_vm *kfd_vm = (struct amdkfd_vm *)vm; + int ret; + struct amdgpu_bo *bo; + uint32_t domain; + struct kfd_bo_va_list *entry; + struct bo_vm_reservation_context ctx; + struct kfd_bo_va_list *bo_va_entry = NULL; + struct kfd_bo_va_list *bo_va_entry_aql = NULL; + unsigned long bo_size; + + /* Make sure restore is not running concurrently. + */ + mutex_lock(&mem->process_info->lock); + + mutex_lock(&mem->lock); + + bo = mem->bo; + + if (!bo) { + pr_err("Invalid BO when mapping memory to GPU\n"); + ret = -EINVAL; + goto out; + } + + domain = mem->domain; + bo_size = bo->tbo.mem.size; + + pr_debug("Map VA 0x%llx - 0x%llx to vm %p domain %s\n", + mem->va, + mem->va + bo_size * (1 + mem->aql_queue), + vm, domain_string(domain)); + + ret = reserve_bo_and_vm(mem, vm, &ctx); + if (unlikely(ret)) + goto out; + + if (check_if_add_bo_to_vm((struct amdgpu_vm *)vm, mem)) { + ret = add_bo_to_vm(adev, mem, (struct amdgpu_vm *)vm, false, + &bo_va_entry); + if (ret) + goto add_bo_to_vm_failed; + if (mem->aql_queue) { + ret = add_bo_to_vm(adev, mem, (struct amdgpu_vm *)vm, + true, &bo_va_entry_aql); + if (ret) + goto add_bo_to_vm_failed_aql; + } + } else { + ret = vm_validate_pt_pd_bos((struct amdkfd_vm *)vm); + if (unlikely(ret)) + goto add_bo_to_vm_failed; + } + + if (mem->mapped_to_gpu_memory == 0) { + /* Validate BO only once. The eviction fence gets added to BO + * the first time it is mapped. Validate will wait for all + * background evictions to complete. + */ + ret = amdgpu_amdkfd_bo_validate(bo, domain, true); + if (ret) { + pr_debug("Validate failed\n"); + goto map_bo_to_gpuvm_failed; + } + } + + list_for_each_entry(entry, &mem->bo_va_list, bo_list) { + if (entry->bo_va->base.vm == vm && !entry->is_mapped) { + pr_debug("\t map VA 0x%llx - 0x%llx in entry %p\n", + entry->va, entry->va + bo_size, + entry); + + ret = map_bo_to_gpuvm(adev, entry, ctx.sync); + if (ret) { + pr_err("Failed to map radeon bo to gpuvm\n"); + goto map_bo_to_gpuvm_failed; + } + + ret = vm_update_pds(vm, ctx.sync); + if (ret) { + pr_err("Failed to update page directories\n"); + goto map_bo_to_gpuvm_failed; + } + + entry->is_mapped = true; + mem->mapped_to_gpu_memory++; + pr_debug("\t INC mapping count %d\n", + mem->mapped_to_gpu_memory); + } + } + + if (!amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) && !bo->pin_count) + amdgpu_bo_fence(bo, + &kfd_vm->process_info->eviction_fence->base, + true); + ret = unreserve_bo_and_vms(&ctx, false, false); + + goto out; + +map_bo_to_gpuvm_failed: + if (bo_va_entry_aql) + remove_bo_from_vm(adev, bo_va_entry_aql, bo_size); +add_bo_to_vm_failed_aql: + if (bo_va_entry) + remove_bo_from_vm(adev, bo_va_entry, bo_size); +add_bo_to_vm_failed: + unreserve_bo_and_vms(&ctx, false, false); +out: + mutex_unlock(&mem->process_info->lock); + mutex_unlock(&mem->lock); + return ret; +} + +int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu( + struct kgd_dev *kgd, struct kgd_mem *mem, void *vm) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct amdkfd_process_info *process_info = + ((struct amdkfd_vm *)vm)->process_info; + unsigned long bo_size = mem->bo->tbo.mem.size; + struct kfd_bo_va_list *entry; + struct bo_vm_reservation_context ctx; + int ret; + + mutex_lock(&mem->lock); + + ret = reserve_bo_and_cond_vms(mem, vm, BO_VM_MAPPED, &ctx); + if (unlikely(ret)) + goto out; + /* If no VMs were reserved, it means the BO wasn't actually mapped */ + if (ctx.n_vms == 0) { + ret = -EINVAL; + goto unreserve_out; + } + + ret = vm_validate_pt_pd_bos((struct amdkfd_vm *)vm); + if (unlikely(ret)) + goto unreserve_out; + + pr_debug("Unmap VA 0x%llx - 0x%llx from vm %p\n", + mem->va, + mem->va + bo_size * (1 + mem->aql_queue), + vm); + + list_for_each_entry(entry, &mem->bo_va_list, bo_list) { + if (entry->bo_va->base.vm == vm && entry->is_mapped) { + pr_debug("\t unmap VA 0x%llx - 0x%llx from entry %p\n", + entry->va, + entry->va + bo_size, + entry); + + ret = unmap_bo_from_gpuvm(adev, entry, ctx.sync); + if (ret == 0) { + entry->is_mapped = false; + } else { + pr_err("failed to unmap VA 0x%llx\n", + mem->va); + goto unreserve_out; + } + + mem->mapped_to_gpu_memory--; + pr_debug("\t DEC mapping count %d\n", + mem->mapped_to_gpu_memory); + } + } + + /* If BO is unmapped from all VMs, unfence it. It can be evicted if + * required. + */ + if (mem->mapped_to_gpu_memory == 0 && + !amdgpu_ttm_tt_get_usermm(mem->bo->tbo.ttm) && !mem->bo->pin_count) + amdgpu_amdkfd_remove_eviction_fence(mem->bo, + process_info->eviction_fence, + NULL, NULL); + +unreserve_out: + unreserve_bo_and_vms(&ctx, false, false); +out: + mutex_unlock(&mem->lock); + return ret; +} + +int amdgpu_amdkfd_gpuvm_sync_memory( + struct kgd_dev *kgd, struct kgd_mem *mem, bool intr) +{ + struct amdgpu_sync sync; + int ret; + + amdgpu_sync_create(&sync); + + mutex_lock(&mem->lock); + amdgpu_sync_clone(&mem->sync, &sync); + mutex_unlock(&mem->lock); + + ret = amdgpu_sync_wait(&sync, intr); + amdgpu_sync_free(&sync); + return ret; +} + +int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_dev *kgd, + struct kgd_mem *mem, void **kptr, uint64_t *size) +{ + int ret; + struct amdgpu_bo *bo = mem->bo; + + if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm)) { + pr_err("userptr can't be mapped to kernel\n"); + return -EINVAL; + } + + /* delete kgd_mem from kfd_bo_list to avoid re-validating + * this BO in BO's restoring after eviction. + */ + mutex_lock(&mem->process_info->lock); + + ret = amdgpu_bo_reserve(bo, true); + if (ret) { + pr_err("Failed to reserve bo. ret %d\n", ret); + goto bo_reserve_failed; + } + + ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT, NULL); + if (ret) { + pr_err("Failed to pin bo. ret %d\n", ret); + goto pin_failed; + } + + ret = amdgpu_bo_kmap(bo, kptr); + if (ret) { + pr_err("Failed to map bo to kernel. ret %d\n", ret); + goto kmap_failed; + } + + amdgpu_amdkfd_remove_eviction_fence( + bo, mem->process_info->eviction_fence, NULL, NULL); + list_del_init(&mem->validate_list.head); + + if (size) + *size = amdgpu_bo_size(bo); + + amdgpu_bo_unreserve(bo); + + mutex_unlock(&mem->process_info->lock); + return 0; + +kmap_failed: + amdgpu_bo_unpin(bo); +pin_failed: + amdgpu_bo_unreserve(bo); +bo_reserve_failed: + mutex_unlock(&mem->process_info->lock); + + return ret; +} + +/** amdgpu_amdkfd_gpuvm_restore_process_bos - Restore all BOs for the given + * KFD process identified by process_info + * + * @process_info: amdkfd_process_info of the KFD process + * + * After memory eviction, restore thread calls this function. The function + * should be called when the Process is still valid. BO restore involves - + * + * 1. Release old eviction fence and create new one + * 2. Get two copies of PD BO list from all the VMs. Keep one copy as pd_list. + * 3 Use the second PD list and kfd_bo_list to create a list (ctx.list) of + * BOs that need to be reserved. + * 4. Reserve all the BOs + * 5. Validate of PD and PT BOs. + * 6. Validate all KFD BOs using kfd_bo_list and Map them and add new fence + * 7. Add fence to all PD and PT BOs. + * 8. Unreserve all BOs + */ +int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) +{ + struct amdgpu_bo_list_entry *pd_bo_list; + struct amdkfd_process_info *process_info = info; + struct amdkfd_vm *peer_vm; + struct kgd_mem *mem; + struct bo_vm_reservation_context ctx; + struct amdgpu_amdkfd_fence *new_fence; + int ret = 0, i; + struct list_head duplicate_save; + struct amdgpu_sync sync_obj; + + INIT_LIST_HEAD(&duplicate_save); + INIT_LIST_HEAD(&ctx.list); + INIT_LIST_HEAD(&ctx.duplicates); + + pd_bo_list = kcalloc(process_info->n_vms, + sizeof(struct amdgpu_bo_list_entry), + GFP_KERNEL); + if (!pd_bo_list) + return -ENOMEM; + + i = 0; + mutex_lock(&process_info->lock); + list_for_each_entry(peer_vm, &process_info->vm_list_head, + vm_list_node) + amdgpu_vm_get_pd_bo(&peer_vm->base, &ctx.list, + &pd_bo_list[i++]); + + /* Reserve all BOs and page tables/directory. Add all BOs from + * kfd_bo_list to ctx.list + */ + list_for_each_entry(mem, &process_info->kfd_bo_list, + validate_list.head) { + + list_add_tail(&mem->resv_list.head, &ctx.list); + mem->resv_list.bo = mem->validate_list.bo; + mem->resv_list.shared = mem->validate_list.shared; + } + + ret = ttm_eu_reserve_buffers(&ctx.ticket, &ctx.list, + false, &duplicate_save); + if (ret) { + pr_debug("Memory eviction: TTM Reserve Failed. Try again\n"); + goto ttm_reserve_fail; + } + + amdgpu_sync_create(&sync_obj); + + /* Validate PDs and PTs */ + ret = process_validate_vms(process_info); + if (ret) + goto validate_map_fail; + + /* Wait for PD/PTs validate to finish */ + /* FIXME: I think this isn't needed */ + list_for_each_entry(peer_vm, &process_info->vm_list_head, + vm_list_node) { + struct amdgpu_bo *bo = peer_vm->base.root.base.bo; + + ttm_bo_wait(&bo->tbo, false, false); + } + + /* Validate BOs and map them to GPUVM (update VM page tables). */ + list_for_each_entry(mem, &process_info->kfd_bo_list, + validate_list.head) { + + struct amdgpu_bo *bo = mem->bo; + uint32_t domain = mem->domain; + struct kfd_bo_va_list *bo_va_entry; + + ret = amdgpu_amdkfd_bo_validate(bo, domain, false); + if (ret) { + pr_debug("Memory eviction: Validate BOs failed. Try again\n"); + goto validate_map_fail; + } + + list_for_each_entry(bo_va_entry, &mem->bo_va_list, + bo_list) { + ret = update_gpuvm_pte((struct amdgpu_device *) + bo_va_entry->kgd_dev, + bo_va_entry, + &sync_obj); + if (ret) { + pr_debug("Memory eviction: update PTE failed. Try again\n"); + goto validate_map_fail; + } + } + } + + /* Update page directories */ + ret = process_update_pds(process_info, &sync_obj); + if (ret) { + pr_debug("Memory eviction: update PDs failed. Try again\n"); + goto validate_map_fail; + } + + amdgpu_sync_wait(&sync_obj, false); + + /* Release old eviction fence and create new one, because fence only + * goes from unsignaled to signaled, fence cannot be reused. + * Use context and mm from the old fence. + */ + new_fence = amdgpu_amdkfd_fence_create( + process_info->eviction_fence->base.context, + process_info->eviction_fence->mm); + if (!new_fence) { + pr_err("Failed to create eviction fence\n"); + ret = -ENOMEM; + goto validate_map_fail; + } + dma_fence_put(&process_info->eviction_fence->base); + process_info->eviction_fence = new_fence; + *ef = dma_fence_get(&new_fence->base); + + /* Wait for validate to finish and attach new eviction fence */ + list_for_each_entry(mem, &process_info->kfd_bo_list, + validate_list.head) + ttm_bo_wait(&mem->bo->tbo, false, false); + list_for_each_entry(mem, &process_info->kfd_bo_list, + validate_list.head) + amdgpu_bo_fence(mem->bo, + &process_info->eviction_fence->base, true); + + /* Attach eviction fence to PD / PT BOs */ + list_for_each_entry(peer_vm, &process_info->vm_list_head, + vm_list_node) { + struct amdgpu_bo *bo = peer_vm->base.root.base.bo; + + amdgpu_bo_fence(bo, &process_info->eviction_fence->base, true); + } + +validate_map_fail: + ttm_eu_backoff_reservation(&ctx.ticket, &ctx.list); + amdgpu_sync_free(&sync_obj); +ttm_reserve_fail: + mutex_unlock(&process_info->lock); + kfree(pd_bo_list); + return ret; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 216799ccb545..9157745fce14 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -36,6 +36,7 @@ #include #include "amdgpu.h" #include "amdgpu_trace.h" +#include "amdgpu_amdkfd.h" static bool amdgpu_need_backup(struct amdgpu_device *adev) { @@ -54,6 +55,9 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev); struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); + if (bo->kfd_bo) + amdgpu_amdkfd_unreserve_system_memory_limit(bo); + amdgpu_bo_kunmap(bo); drm_gem_object_release(&bo->gem_base); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 1cef944ef98d..d4dbfe1f842e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -92,6 +92,8 @@ struct amdgpu_bo { struct list_head mn_list; struct list_head shadow_list; }; + + struct kgd_mem *kfd_bo; }; static inline struct amdgpu_bo *ttm_to_amdgpu_bo(struct ttm_buffer_object *tbo) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 5fcb3488a595..c2fae04d769a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -259,6 +259,13 @@ static int amdgpu_verify_access(struct ttm_buffer_object *bo, struct file *filp) { struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo); + /* + * Don't verify access for KFD BOs. They don't have a GEM + * object associated with them. + */ + if (abo->kfd_bo) + return 0; + if (amdgpu_ttm_tt_get_usermm(bo->ttm)) return -EPERM; return drm_vma_node_verify_access(&abo->gem_base.vma_node, diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 36c706aff2ac..5984fec78be4 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -127,6 +127,25 @@ struct tile_config { uint32_t num_ranks; }; + +/* + * Allocation flag domains + */ +#define ALLOC_MEM_FLAGS_VRAM (1 << 0) +#define ALLOC_MEM_FLAGS_GTT (1 << 1) +#define ALLOC_MEM_FLAGS_USERPTR (1 << 2) /* TODO */ +#define ALLOC_MEM_FLAGS_DOORBELL (1 << 3) /* TODO */ + +/* + * Allocation flags attributes/access options. + */ +#define ALLOC_MEM_FLAGS_WRITABLE (1 << 31) +#define ALLOC_MEM_FLAGS_EXECUTABLE (1 << 30) +#define ALLOC_MEM_FLAGS_PUBLIC (1 << 29) +#define ALLOC_MEM_FLAGS_NO_SUBSTITUTE (1 << 28) /* TODO */ +#define ALLOC_MEM_FLAGS_AQL_QUEUE_MEM (1 << 27) +#define ALLOC_MEM_FLAGS_COHERENT (1 << 26) /* For GFXv9 or later */ + /** * struct kfd2kgd_calls * @@ -186,6 +205,41 @@ struct tile_config { * * @get_vram_usage: Returns current VRAM usage * + * @create_process_vm: Create a VM address space for a given process and GPU + * + * @destroy_process_vm: Destroy a VM + * + * @get_process_page_dir: Get physical address of a VM page directory + * + * @set_vm_context_page_table_base: Program page table base for a VMID + * + * @alloc_memory_of_gpu: Allocate GPUVM memory + * + * @free_memory_of_gpu: Free GPUVM memory + * + * @map_memory_to_gpu: Map GPUVM memory into a specific VM address + * space. Allocates and updates page tables and page directories as + * needed. This function may return before all page table updates have + * completed. This allows multiple map operations (on multiple GPUs) + * to happen concurrently. Use sync_memory to synchronize with all + * pending updates. + * + * @unmap_memor_to_gpu: Unmap GPUVM memory from a specific VM address space + * + * @sync_memory: Wait for pending page table updates to complete + * + * @map_gtt_bo_to_kernel: Map a GTT BO for kernel access + * Pins the BO, maps it to kernel address space. Such BOs are never evicted. + * The kernel virtual address remains valid until the BO is freed. + * + * @restore_process_bos: Restore all BOs that belong to the + * process. This is intended for restoring memory mappings after a TTM + * eviction. + * + * @invalidate_tlbs: Invalidate TLBs for a specific PASID + * + * @invalidate_tlbs_vmid: Invalidate TLBs for a specific VMID + * * This structure contains function pointers to services that the kgd driver * provides to amdkfd driver. * @@ -275,6 +329,29 @@ struct kfd2kgd_calls { void (*get_cu_info)(struct kgd_dev *kgd, struct kfd_cu_info *cu_info); uint64_t (*get_vram_usage)(struct kgd_dev *kgd); + + int (*create_process_vm)(struct kgd_dev *kgd, void **vm, + void **process_info, struct dma_fence **ef); + void (*destroy_process_vm)(struct kgd_dev *kgd, void *vm); + uint32_t (*get_process_page_dir)(void *vm); + void (*set_vm_context_page_table_base)(struct kgd_dev *kgd, + uint32_t vmid, uint32_t page_table_base); + int (*alloc_memory_of_gpu)(struct kgd_dev *kgd, uint64_t va, + uint64_t size, void *vm, + struct kgd_mem **mem, uint64_t *offset, + uint32_t flags); + int (*free_memory_of_gpu)(struct kgd_dev *kgd, struct kgd_mem *mem); + int (*map_memory_to_gpu)(struct kgd_dev *kgd, struct kgd_mem *mem, + void *vm); + int (*unmap_memory_to_gpu)(struct kgd_dev *kgd, struct kgd_mem *mem, + void *vm); + int (*sync_memory)(struct kgd_dev *kgd, struct kgd_mem *mem, bool intr); + int (*map_gtt_bo_to_kernel)(struct kgd_dev *kgd, struct kgd_mem *mem, + void **kptr, uint64_t *size); + int (*restore_process_bos)(void *process_info, struct dma_fence **ef); + + int (*invalidate_tlbs)(struct kgd_dev *kgd, uint16_t pasid); + int (*invalidate_tlbs_vmid)(struct kgd_dev *kgd, uint16_t vmid); }; /** -- cgit v1.2.3 From 4c660c8fbbf7b0d65a402f51e5f30a246cf3c44c Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Tue, 6 Feb 2018 20:32:39 -0500 Subject: drm/amdgpu: Add submit IB function for KFD This can be used for flushing caches when not using the HWS. Signed-off-by: Felix Kuehling Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 55 +++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 4 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 1 + drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 8 ++++ 5 files changed, 69 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 5a881107a15a..8a23aa8f9c73 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -367,6 +367,61 @@ uint64_t amdgpu_amdkfd_get_vram_usage(struct kgd_dev *kgd) return amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); } +int amdgpu_amdkfd_submit_ib(struct kgd_dev *kgd, enum kgd_engine_type engine, + uint32_t vmid, uint64_t gpu_addr, + uint32_t *ib_cmd, uint32_t ib_len) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)kgd; + struct amdgpu_job *job; + struct amdgpu_ib *ib; + struct amdgpu_ring *ring; + struct dma_fence *f = NULL; + int ret; + + switch (engine) { + case KGD_ENGINE_MEC1: + ring = &adev->gfx.compute_ring[0]; + break; + case KGD_ENGINE_SDMA1: + ring = &adev->sdma.instance[0].ring; + break; + case KGD_ENGINE_SDMA2: + ring = &adev->sdma.instance[1].ring; + break; + default: + pr_err("Invalid engine in IB submission: %d\n", engine); + ret = -EINVAL; + goto err; + } + + ret = amdgpu_job_alloc(adev, 1, &job, NULL); + if (ret) + goto err; + + ib = &job->ibs[0]; + memset(ib, 0, sizeof(struct amdgpu_ib)); + + ib->gpu_addr = gpu_addr; + ib->ptr = ib_cmd; + ib->length_dw = ib_len; + /* This works for NO_HWS. TODO: need to handle without knowing VMID */ + job->vmid = vmid; + + ret = amdgpu_ib_schedule(ring, 1, ib, job, &f); + if (ret) { + DRM_ERROR("amdgpu: failed to schedule IB.\n"); + goto err_ib_sched; + } + + ret = dma_fence_wait(f, false); + +err_ib_sched: + dma_fence_put(f); + amdgpu_job_free(job); +err: + return ret; +} + bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid) { if (adev->kfd) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index 05a228d60241..d7509b706b26 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -124,6 +124,10 @@ void amdgpu_amdkfd_device_probe(struct amdgpu_device *adev); void amdgpu_amdkfd_device_init(struct amdgpu_device *adev); void amdgpu_amdkfd_device_fini(struct amdgpu_device *adev); +int amdgpu_amdkfd_submit_ib(struct kgd_dev *kgd, enum kgd_engine_type engine, + uint32_t vmid, uint64_t gpu_addr, + uint32_t *ib_cmd, uint32_t ib_len); + struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void); struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void); 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 65783d1eddca..7485c376b90e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -217,6 +217,7 @@ static const struct kfd2kgd_calls kfd2kgd = { .restore_process_bos = amdgpu_amdkfd_gpuvm_restore_process_bos, .invalidate_tlbs = invalidate_tlbs, .invalidate_tlbs_vmid = invalidate_tlbs_vmid, + .submit_ib = amdgpu_amdkfd_submit_ib, }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void) 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 1b5bf1353f0c..7be453494423 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -177,6 +177,7 @@ static const struct kfd2kgd_calls kfd2kgd = { .restore_process_bos = amdgpu_amdkfd_gpuvm_restore_process_bos, .invalidate_tlbs = invalidate_tlbs, .invalidate_tlbs_vmid = invalidate_tlbs_vmid, + .submit_ib = amdgpu_amdkfd_submit_ib, }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void) diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 5984fec78be4..1e5c22ceb256 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -240,6 +240,10 @@ struct tile_config { * * @invalidate_tlbs_vmid: Invalidate TLBs for a specific VMID * + * @submit_ib: Submits an IB to the engine specified by inserting the + * IB to the corresponding ring (ring type). The IB is executed with the + * specified VMID in a user mode context. + * * This structure contains function pointers to services that the kgd driver * provides to amdkfd driver. * @@ -352,6 +356,10 @@ struct kfd2kgd_calls { int (*invalidate_tlbs)(struct kgd_dev *kgd, uint16_t pasid); int (*invalidate_tlbs_vmid)(struct kgd_dev *kgd, uint16_t vmid); + + int (*submit_ib)(struct kgd_dev *kgd, enum kgd_engine_type engine, + uint32_t vmid, uint64_t gpu_addr, + uint32_t *ib_cmd, uint32_t ib_len); }; /** -- cgit v1.2.3 From 64d1c3a43a6fb5cef32a085bc17cbbe31945a651 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Fri, 8 Dec 2017 19:22:12 -0500 Subject: drm/amdkfd: Centralize IOMMUv2 code and make it conditional dGPUs work without IOMMUv2. Make IOMMUv2 initialization dependent on ASIC information. Also allow building KFD without IOMMUv2 support. This is still useful for dGPUs and prepares for enabling KFD on architectures that don't support AMD IOMMUv2. v2: * Centralize IOMMUv2 code to avoid #ifdefs in too many places v3: * Imply AMD_IOMMU_V2 in Kconfig Signed-off-by: Felix Kuehling Acked-by: Christian Konig Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/Kconfig | 3 +- drivers/gpu/drm/amd/amdkfd/Makefile | 4 + drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 14 +- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 127 +++-------- drivers/gpu/drm/amd/amdkfd/kfd_events.c | 3 + drivers/gpu/drm/amd/amdkfd/kfd_iommu.c | 357 ++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_iommu.h | 78 +++++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 14 +- drivers/gpu/drm/amd/amdkfd/kfd_process.c | 138 +----------- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 16 +- drivers/gpu/drm/amd/amdkfd/kfd_topology.h | 6 +- 11 files changed, 495 insertions(+), 265 deletions(-) create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_iommu.c create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_iommu.h (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/Kconfig b/drivers/gpu/drm/amd/amdkfd/Kconfig index bc5a2945bd2b..ed2f06c9f346 100644 --- a/drivers/gpu/drm/amd/amdkfd/Kconfig +++ b/drivers/gpu/drm/amd/amdkfd/Kconfig @@ -4,6 +4,7 @@ config HSA_AMD tristate "HSA kernel driver for AMD GPU devices" - depends on DRM_AMDGPU && AMD_IOMMU_V2 && X86_64 + depends on DRM_AMDGPU && X86_64 + imply AMD_IOMMU_V2 help Enable this if you want to use HSA features on AMD GPU devices. diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile index a317e76ffb5e..0d0242240c47 100644 --- a/drivers/gpu/drm/amd/amdkfd/Makefile +++ b/drivers/gpu/drm/amd/amdkfd/Makefile @@ -37,6 +37,10 @@ amdkfd-y := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \ kfd_interrupt.o kfd_events.o cik_event_interrupt.o \ kfd_dbgdev.o kfd_dbgmgr.o kfd_crat.o +ifneq ($(CONFIG_AMD_IOMMU_V2),) +amdkfd-y += kfd_iommu.o +endif + amdkfd-$(CONFIG_DEBUG_FS) += kfd_debugfs.o obj-$(CONFIG_HSA_AMD) += amdkfd.o diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 2bc2816767a7..7493f47e7fe1 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -22,10 +22,10 @@ #include #include -#include #include "kfd_crat.h" #include "kfd_priv.h" #include "kfd_topology.h" +#include "kfd_iommu.h" /* GPU Processor ID base for dGPUs for which VCRAT needs to be created. * GPU processor ID are expressed with Bit[31]=1. @@ -1037,15 +1037,11 @@ static int kfd_create_vcrat_image_gpu(void *pcrat_image, struct crat_subtype_generic *sub_type_hdr; struct crat_subtype_computeunit *cu; struct kfd_cu_info cu_info; - struct amd_iommu_device_info iommu_info; int avail_size = *size; uint32_t total_num_of_cu; int num_of_cache_entries = 0; int cache_mem_filled = 0; int ret = 0; - const u32 required_iommu_flags = AMD_IOMMU_DEVICE_FLAG_ATS_SUP | - AMD_IOMMU_DEVICE_FLAG_PRI_SUP | - AMD_IOMMU_DEVICE_FLAG_PASID_SUP; struct kfd_local_mem_info local_mem_info; if (!pcrat_image || avail_size < VCRAT_SIZE_FOR_GPU) @@ -1106,12 +1102,8 @@ static int kfd_create_vcrat_image_gpu(void *pcrat_image, /* Check if this node supports IOMMU. During parsing this flag will * translate to HSA_CAP_ATS_PRESENT */ - iommu_info.flags = 0; - if (amd_iommu_device_info(kdev->pdev, &iommu_info) == 0) { - if ((iommu_info.flags & required_iommu_flags) == - required_iommu_flags) - cu->hsa_capability |= CRAT_CU_FLAGS_IOMMU_PRESENT; - } + if (!kfd_iommu_check_device(kdev)) + cu->hsa_capability |= CRAT_CU_FLAGS_IOMMU_PRESENT; crat_table->length += sub_type_hdr->length; crat_table->total_entries++; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 83d6f410890e..4ac2d61b65d5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -20,7 +20,9 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#if defined(CONFIG_AMD_IOMMU_V2_MODULE) || defined(CONFIG_AMD_IOMMU_V2) #include +#endif #include #include #include @@ -28,9 +30,11 @@ #include "kfd_device_queue_manager.h" #include "kfd_pm4_headers_vi.h" #include "cwsr_trap_handler_gfx8.asm" +#include "kfd_iommu.h" #define MQD_SIZE_ALIGNED 768 +#ifdef KFD_SUPPORT_IOMMU_V2 static const struct kfd_device_info kaveri_device_info = { .asic_family = CHIP_KAVERI, .max_pasid_bits = 16, @@ -41,6 +45,7 @@ static const struct kfd_device_info kaveri_device_info = { .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED, .supports_cwsr = false, + .needs_iommu_device = true, .needs_pci_atomics = false, }; @@ -54,8 +59,10 @@ static const struct kfd_device_info carrizo_device_info = { .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED, .supports_cwsr = true, + .needs_iommu_device = true, .needs_pci_atomics = false, }; +#endif static const struct kfd_device_info hawaii_device_info = { .asic_family = CHIP_HAWAII, @@ -67,6 +74,7 @@ static const struct kfd_device_info hawaii_device_info = { .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED, .supports_cwsr = false, + .needs_iommu_device = false, .needs_pci_atomics = false, }; @@ -79,6 +87,7 @@ static const struct kfd_device_info tonga_device_info = { .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED, .supports_cwsr = false, + .needs_iommu_device = false, .needs_pci_atomics = true, }; @@ -91,6 +100,7 @@ static const struct kfd_device_info tonga_vf_device_info = { .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED, .supports_cwsr = false, + .needs_iommu_device = false, .needs_pci_atomics = false, }; @@ -103,6 +113,7 @@ static const struct kfd_device_info fiji_device_info = { .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED, .supports_cwsr = true, + .needs_iommu_device = false, .needs_pci_atomics = true, }; @@ -115,6 +126,7 @@ static const struct kfd_device_info fiji_vf_device_info = { .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED, .supports_cwsr = true, + .needs_iommu_device = false, .needs_pci_atomics = false, }; @@ -128,6 +140,7 @@ static const struct kfd_device_info polaris10_device_info = { .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED, .supports_cwsr = true, + .needs_iommu_device = false, .needs_pci_atomics = true, }; @@ -140,6 +153,7 @@ static const struct kfd_device_info polaris10_vf_device_info = { .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED, .supports_cwsr = true, + .needs_iommu_device = false, .needs_pci_atomics = false, }; @@ -152,6 +166,7 @@ static const struct kfd_device_info polaris11_device_info = { .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED, .supports_cwsr = true, + .needs_iommu_device = false, .needs_pci_atomics = true, }; @@ -162,6 +177,7 @@ struct kfd_deviceid { }; static const struct kfd_deviceid supported_devices[] = { +#ifdef KFD_SUPPORT_IOMMU_V2 { 0x1304, &kaveri_device_info }, /* Kaveri */ { 0x1305, &kaveri_device_info }, /* Kaveri */ { 0x1306, &kaveri_device_info }, /* Kaveri */ @@ -189,6 +205,7 @@ static const struct kfd_deviceid supported_devices[] = { { 0x9875, &carrizo_device_info }, /* Carrizo */ { 0x9876, &carrizo_device_info }, /* Carrizo */ { 0x9877, &carrizo_device_info }, /* Carrizo */ +#endif { 0x67A0, &hawaii_device_info }, /* Hawaii */ { 0x67A1, &hawaii_device_info }, /* Hawaii */ { 0x67A2, &hawaii_device_info }, /* Hawaii */ @@ -302,77 +319,6 @@ struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, return kfd; } -static bool device_iommu_pasid_init(struct kfd_dev *kfd) -{ - const u32 required_iommu_flags = AMD_IOMMU_DEVICE_FLAG_ATS_SUP | - AMD_IOMMU_DEVICE_FLAG_PRI_SUP | - AMD_IOMMU_DEVICE_FLAG_PASID_SUP; - - struct amd_iommu_device_info iommu_info; - unsigned int pasid_limit; - int err; - - err = amd_iommu_device_info(kfd->pdev, &iommu_info); - if (err < 0) { - dev_err(kfd_device, - "error getting iommu info. is the iommu enabled?\n"); - return false; - } - - if ((iommu_info.flags & required_iommu_flags) != required_iommu_flags) { - dev_err(kfd_device, "error required iommu flags ats %i, pri %i, pasid %i\n", - (iommu_info.flags & AMD_IOMMU_DEVICE_FLAG_ATS_SUP) != 0, - (iommu_info.flags & AMD_IOMMU_DEVICE_FLAG_PRI_SUP) != 0, - (iommu_info.flags & AMD_IOMMU_DEVICE_FLAG_PASID_SUP) - != 0); - return false; - } - - pasid_limit = min_t(unsigned int, - (unsigned int)(1 << kfd->device_info->max_pasid_bits), - iommu_info.max_pasids); - - if (!kfd_set_pasid_limit(pasid_limit)) { - dev_err(kfd_device, "error setting pasid limit\n"); - return false; - } - - return true; -} - -static void iommu_pasid_shutdown_callback(struct pci_dev *pdev, int pasid) -{ - struct kfd_dev *dev = kfd_device_by_pci_dev(pdev); - - if (dev) - kfd_process_iommu_unbind_callback(dev, pasid); -} - -/* - * This function called by IOMMU driver on PPR failure - */ -static int iommu_invalid_ppr_cb(struct pci_dev *pdev, int pasid, - unsigned long address, u16 flags) -{ - struct kfd_dev *dev; - - dev_warn(kfd_device, - "Invalid PPR device %x:%x.%x pasid %d address 0x%lX flags 0x%X", - PCI_BUS_NUM(pdev->devfn), - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn), - pasid, - address, - flags); - - dev = kfd_device_by_pci_dev(pdev); - if (!WARN_ON(!dev)) - kfd_signal_iommu_event(dev, pasid, address, - flags & PPR_FAULT_WRITE, flags & PPR_FAULT_EXEC); - - return AMD_IOMMU_INV_PRI_RSP_INVALID; -} - static void kfd_cwsr_init(struct kfd_dev *kfd) { if (cwsr_enable && kfd->device_info->supports_cwsr) { @@ -462,11 +408,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, goto device_queue_manager_error; } - if (!device_iommu_pasid_init(kfd)) { - dev_err(kfd_device, - "Error initializing iommuv2 for device %x:%x\n", - kfd->pdev->vendor, kfd->pdev->device); - goto device_iommu_pasid_error; + if (kfd_iommu_device_init(kfd)) { + dev_err(kfd_device, "Error initializing iommuv2\n"); + goto device_iommu_error; } kfd_cwsr_init(kfd); @@ -486,7 +430,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, goto out; kfd_resume_error: -device_iommu_pasid_error: +device_iommu_error: device_queue_manager_uninit(kfd->dqm); device_queue_manager_error: kfd_interrupt_exit(kfd); @@ -527,11 +471,7 @@ void kgd2kfd_suspend(struct kfd_dev *kfd) kfd->dqm->ops.stop(kfd->dqm); - kfd_unbind_processes_from_device(kfd); - - amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL); - amd_iommu_set_invalid_ppr_cb(kfd->pdev, NULL); - amd_iommu_free_device(kfd->pdev); + kfd_iommu_suspend(kfd); } int kgd2kfd_resume(struct kfd_dev *kfd) @@ -546,19 +486,14 @@ int kgd2kfd_resume(struct kfd_dev *kfd) static int kfd_resume(struct kfd_dev *kfd) { int err = 0; - unsigned int pasid_limit = kfd_get_pasid_limit(); - - err = amd_iommu_init_device(kfd->pdev, pasid_limit); - if (err) - return -ENXIO; - amd_iommu_set_invalidate_ctx_cb(kfd->pdev, - iommu_pasid_shutdown_callback); - amd_iommu_set_invalid_ppr_cb(kfd->pdev, - iommu_invalid_ppr_cb); - err = kfd_bind_processes_to_device(kfd); - if (err) - goto processes_bind_error; + err = kfd_iommu_resume(kfd); + if (err) { + dev_err(kfd_device, + "Failed to resume IOMMU for device %x:%x\n", + kfd->pdev->vendor, kfd->pdev->device); + return err; + } err = kfd->dqm->ops.start(kfd->dqm); if (err) { @@ -571,9 +506,7 @@ static int kfd_resume(struct kfd_dev *kfd) return err; dqm_start_error: -processes_bind_error: - amd_iommu_free_device(kfd->pdev); - + kfd_iommu_suspend(kfd); return err; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 93aae5c1e78b..6fb9c0d46d63 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -30,6 +30,7 @@ #include #include "kfd_priv.h" #include "kfd_events.h" +#include "kfd_iommu.h" #include /* @@ -837,6 +838,7 @@ static void lookup_events_by_type_and_signal(struct kfd_process *p, } } +#ifdef KFD_SUPPORT_IOMMU_V2 void kfd_signal_iommu_event(struct kfd_dev *dev, unsigned int pasid, unsigned long address, bool is_write_requested, bool is_execute_requested) @@ -905,6 +907,7 @@ void kfd_signal_iommu_event(struct kfd_dev *dev, unsigned int pasid, mutex_unlock(&p->event_mutex); kfd_unref_process(p); } +#endif /* KFD_SUPPORT_IOMMU_V2 */ void kfd_signal_hw_exception_event(unsigned int pasid) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c new file mode 100644 index 000000000000..c71817963eea --- /dev/null +++ b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c @@ -0,0 +1,357 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include "kfd_priv.h" +#include "kfd_dbgmgr.h" +#include "kfd_topology.h" +#include "kfd_iommu.h" + +static const u32 required_iommu_flags = AMD_IOMMU_DEVICE_FLAG_ATS_SUP | + AMD_IOMMU_DEVICE_FLAG_PRI_SUP | + AMD_IOMMU_DEVICE_FLAG_PASID_SUP; + +/** kfd_iommu_check_device - Check whether IOMMU is available for device + */ +int kfd_iommu_check_device(struct kfd_dev *kfd) +{ + struct amd_iommu_device_info iommu_info; + int err; + + if (!kfd->device_info->needs_iommu_device) + return -ENODEV; + + iommu_info.flags = 0; + err = amd_iommu_device_info(kfd->pdev, &iommu_info); + if (err) + return err; + + if ((iommu_info.flags & required_iommu_flags) != required_iommu_flags) + return -ENODEV; + + return 0; +} + +/** kfd_iommu_device_init - Initialize IOMMU for device + */ +int kfd_iommu_device_init(struct kfd_dev *kfd) +{ + struct amd_iommu_device_info iommu_info; + unsigned int pasid_limit; + int err; + + if (!kfd->device_info->needs_iommu_device) + return 0; + + iommu_info.flags = 0; + err = amd_iommu_device_info(kfd->pdev, &iommu_info); + if (err < 0) { + dev_err(kfd_device, + "error getting iommu info. is the iommu enabled?\n"); + return -ENODEV; + } + + if ((iommu_info.flags & required_iommu_flags) != required_iommu_flags) { + dev_err(kfd_device, + "error required iommu flags ats %i, pri %i, pasid %i\n", + (iommu_info.flags & AMD_IOMMU_DEVICE_FLAG_ATS_SUP) != 0, + (iommu_info.flags & AMD_IOMMU_DEVICE_FLAG_PRI_SUP) != 0, + (iommu_info.flags & AMD_IOMMU_DEVICE_FLAG_PASID_SUP) + != 0); + return -ENODEV; + } + + pasid_limit = min_t(unsigned int, + (unsigned int)(1 << kfd->device_info->max_pasid_bits), + iommu_info.max_pasids); + + if (!kfd_set_pasid_limit(pasid_limit)) { + dev_err(kfd_device, "error setting pasid limit\n"); + return -EBUSY; + } + + return 0; +} + +/** kfd_iommu_bind_process_to_device - Have the IOMMU bind a process + * + * Binds the given process to the given device using its PASID. This + * enables IOMMUv2 address translation for the process on the device. + * + * This function assumes that the process mutex is held. + */ +int kfd_iommu_bind_process_to_device(struct kfd_process_device *pdd) +{ + struct kfd_dev *dev = pdd->dev; + struct kfd_process *p = pdd->process; + int err; + + if (!dev->device_info->needs_iommu_device || pdd->bound == PDD_BOUND) + return 0; + + if (unlikely(pdd->bound == PDD_BOUND_SUSPENDED)) { + pr_err("Binding PDD_BOUND_SUSPENDED pdd is unexpected!\n"); + return -EINVAL; + } + + err = amd_iommu_bind_pasid(dev->pdev, p->pasid, p->lead_thread); + if (!err) + pdd->bound = PDD_BOUND; + + return err; +} + +/** kfd_iommu_unbind_process - Unbind process from all devices + * + * This removes all IOMMU device bindings of the process. To be used + * before process termination. + */ +void kfd_iommu_unbind_process(struct kfd_process *p) +{ + struct kfd_process_device *pdd; + + list_for_each_entry(pdd, &p->per_device_data, per_device_list) + if (pdd->bound == PDD_BOUND) + amd_iommu_unbind_pasid(pdd->dev->pdev, p->pasid); +} + +/* Callback for process shutdown invoked by the IOMMU driver */ +static void iommu_pasid_shutdown_callback(struct pci_dev *pdev, int pasid) +{ + struct kfd_dev *dev = kfd_device_by_pci_dev(pdev); + struct kfd_process *p; + struct kfd_process_device *pdd; + + if (!dev) + return; + + /* + * Look for the process that matches the pasid. If there is no such + * process, we either released it in amdkfd's own notifier, or there + * is a bug. Unfortunately, there is no way to tell... + */ + p = kfd_lookup_process_by_pasid(pasid); + if (!p) + return; + + pr_debug("Unbinding process %d from IOMMU\n", pasid); + + mutex_lock(kfd_get_dbgmgr_mutex()); + + if (dev->dbgmgr && dev->dbgmgr->pasid == p->pasid) { + if (!kfd_dbgmgr_unregister(dev->dbgmgr, p)) { + kfd_dbgmgr_destroy(dev->dbgmgr); + dev->dbgmgr = NULL; + } + } + + mutex_unlock(kfd_get_dbgmgr_mutex()); + + mutex_lock(&p->mutex); + + pdd = kfd_get_process_device_data(dev, p); + if (pdd) + /* For GPU relying on IOMMU, we need to dequeue here + * when PASID is still bound. + */ + kfd_process_dequeue_from_device(pdd); + + mutex_unlock(&p->mutex); + + kfd_unref_process(p); +} + +/* This function called by IOMMU driver on PPR failure */ +static int iommu_invalid_ppr_cb(struct pci_dev *pdev, int pasid, + unsigned long address, u16 flags) +{ + struct kfd_dev *dev; + + dev_warn(kfd_device, + "Invalid PPR device %x:%x.%x pasid %d address 0x%lX flags 0x%X", + PCI_BUS_NUM(pdev->devfn), + PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), + pasid, + address, + flags); + + dev = kfd_device_by_pci_dev(pdev); + if (!WARN_ON(!dev)) + kfd_signal_iommu_event(dev, pasid, address, + flags & PPR_FAULT_WRITE, flags & PPR_FAULT_EXEC); + + return AMD_IOMMU_INV_PRI_RSP_INVALID; +} + +/* + * Bind processes do the device that have been temporarily unbound + * (PDD_BOUND_SUSPENDED) in kfd_unbind_processes_from_device. + */ +static int kfd_bind_processes_to_device(struct kfd_dev *kfd) +{ + struct kfd_process_device *pdd; + struct kfd_process *p; + unsigned int temp; + int err = 0; + + int idx = srcu_read_lock(&kfd_processes_srcu); + + hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { + mutex_lock(&p->mutex); + pdd = kfd_get_process_device_data(kfd, p); + + if (WARN_ON(!pdd) || pdd->bound != PDD_BOUND_SUSPENDED) { + mutex_unlock(&p->mutex); + continue; + } + + err = amd_iommu_bind_pasid(kfd->pdev, p->pasid, + p->lead_thread); + if (err < 0) { + pr_err("Unexpected pasid %d binding failure\n", + p->pasid); + mutex_unlock(&p->mutex); + break; + } + + pdd->bound = PDD_BOUND; + mutex_unlock(&p->mutex); + } + + srcu_read_unlock(&kfd_processes_srcu, idx); + + return err; +} + +/* + * Mark currently bound processes as PDD_BOUND_SUSPENDED. These + * processes will be restored to PDD_BOUND state in + * kfd_bind_processes_to_device. + */ +static void kfd_unbind_processes_from_device(struct kfd_dev *kfd) +{ + struct kfd_process_device *pdd; + struct kfd_process *p; + unsigned int temp; + + int idx = srcu_read_lock(&kfd_processes_srcu); + + hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { + mutex_lock(&p->mutex); + pdd = kfd_get_process_device_data(kfd, p); + + if (WARN_ON(!pdd)) { + mutex_unlock(&p->mutex); + continue; + } + + if (pdd->bound == PDD_BOUND) + pdd->bound = PDD_BOUND_SUSPENDED; + mutex_unlock(&p->mutex); + } + + srcu_read_unlock(&kfd_processes_srcu, idx); +} + +/** kfd_iommu_suspend - Prepare IOMMU for suspend + * + * This unbinds processes from the device and disables the IOMMU for + * the device. + */ +void kfd_iommu_suspend(struct kfd_dev *kfd) +{ + if (!kfd->device_info->needs_iommu_device) + return; + + kfd_unbind_processes_from_device(kfd); + + amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL); + amd_iommu_set_invalid_ppr_cb(kfd->pdev, NULL); + amd_iommu_free_device(kfd->pdev); +} + +/** kfd_iommu_resume - Restore IOMMU after resume + * + * This reinitializes the IOMMU for the device and re-binds previously + * suspended processes to the device. + */ +int kfd_iommu_resume(struct kfd_dev *kfd) +{ + unsigned int pasid_limit; + int err; + + if (!kfd->device_info->needs_iommu_device) + return 0; + + pasid_limit = kfd_get_pasid_limit(); + + err = amd_iommu_init_device(kfd->pdev, pasid_limit); + if (err) + return -ENXIO; + + amd_iommu_set_invalidate_ctx_cb(kfd->pdev, + iommu_pasid_shutdown_callback); + amd_iommu_set_invalid_ppr_cb(kfd->pdev, + iommu_invalid_ppr_cb); + + err = kfd_bind_processes_to_device(kfd); + if (err) { + amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL); + amd_iommu_set_invalid_ppr_cb(kfd->pdev, NULL); + amd_iommu_free_device(kfd->pdev); + return err; + } + + return 0; +} + +extern bool amd_iommu_pc_supported(void); +extern u8 amd_iommu_pc_get_max_banks(u16 devid); +extern u8 amd_iommu_pc_get_max_counters(u16 devid); + +/** kfd_iommu_add_perf_counters - Add IOMMU performance counters to topology + */ +int kfd_iommu_add_perf_counters(struct kfd_topology_device *kdev) +{ + struct kfd_perf_properties *props; + + if (!(kdev->node_props.capability & HSA_CAP_ATS_PRESENT)) + return 0; + + if (!amd_iommu_pc_supported()) + return 0; + + props = kfd_alloc_struct(props); + if (!props) + return -ENOMEM; + strcpy(props->block_name, "iommu"); + props->max_concurrent = amd_iommu_pc_get_max_banks(0) * + amd_iommu_pc_get_max_counters(0); /* assume one iommu */ + list_add_tail(&props->list, &kdev->perf_props); + + return 0; +} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.h b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.h new file mode 100644 index 000000000000..dd23d9fdf6a8 --- /dev/null +++ b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.h @@ -0,0 +1,78 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __KFD_IOMMU_H__ +#define __KFD_IOMMU_H__ + +#if defined(CONFIG_AMD_IOMMU_V2_MODULE) || defined(CONFIG_AMD_IOMMU_V2) + +#define KFD_SUPPORT_IOMMU_V2 + +int kfd_iommu_check_device(struct kfd_dev *kfd); +int kfd_iommu_device_init(struct kfd_dev *kfd); + +int kfd_iommu_bind_process_to_device(struct kfd_process_device *pdd); +void kfd_iommu_unbind_process(struct kfd_process *p); + +void kfd_iommu_suspend(struct kfd_dev *kfd); +int kfd_iommu_resume(struct kfd_dev *kfd); + +int kfd_iommu_add_perf_counters(struct kfd_topology_device *kdev); + +#else + +static inline int kfd_iommu_check_device(struct kfd_dev *kfd) +{ + return -ENODEV; +} +static inline int kfd_iommu_device_init(struct kfd_dev *kfd) +{ + return 0; +} + +static inline int kfd_iommu_bind_process_to_device( + struct kfd_process_device *pdd) +{ + return 0; +} +static inline void kfd_iommu_unbind_process(struct kfd_process *p) +{ + /* empty */ +} + +static inline void kfd_iommu_suspend(struct kfd_dev *kfd) +{ + /* empty */ +} +static inline int kfd_iommu_resume(struct kfd_dev *kfd) +{ + return 0; +} + +static inline int kfd_iommu_add_perf_counters(struct kfd_topology_device *kdev) +{ + return 0; +} + +#endif /* defined(CONFIG_AMD_IOMMU_V2) */ + +#endif /* __KFD_IOMMU_H__ */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 594f85355397..f12eb5d98be8 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -158,6 +158,7 @@ struct kfd_device_info { uint8_t num_of_watch_points; uint16_t mqd_size_aligned; bool supports_cwsr; + bool needs_iommu_device; bool needs_pci_atomics; }; @@ -517,15 +518,15 @@ struct kfd_process_device { uint64_t scratch_base; uint64_t scratch_limit; - /* Is this process/pasid bound to this device? (amd_iommu_bind_pasid) */ - enum kfd_pdd_bound bound; - /* Flag used to tell the pdd has dequeued from the dqm. * This is used to prevent dev->dqm->ops.process_termination() from * being called twice when it is already called in IOMMU callback * function. */ bool already_dequeued; + + /* Is this process/pasid bound to this device? (amd_iommu_bind_pasid) */ + enum kfd_pdd_bound bound; }; #define qpd_to_pdd(x) container_of(x, struct kfd_process_device, qpd) @@ -590,6 +591,10 @@ struct kfd_process { bool signal_event_limit_reached; }; +#define KFD_PROCESS_TABLE_SIZE 5 /* bits: 32 entries */ +extern DECLARE_HASHTABLE(kfd_processes_table, KFD_PROCESS_TABLE_SIZE); +extern struct srcu_struct kfd_processes_srcu; + /** * Ioctl function type. * @@ -617,9 +622,6 @@ void kfd_unref_process(struct kfd_process *p); struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev, struct kfd_process *p); -int kfd_bind_processes_to_device(struct kfd_dev *dev); -void kfd_unbind_processes_from_device(struct kfd_dev *dev); -void kfd_process_iommu_unbind_callback(struct kfd_dev *dev, unsigned int pasid); struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev, struct kfd_process *p); struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 4ff5f0fe6db8..e9aee76ceba9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -35,16 +35,16 @@ struct mm_struct; #include "kfd_priv.h" #include "kfd_dbgmgr.h" +#include "kfd_iommu.h" /* * List of struct kfd_process (field kfd_process). * Unique/indexed by mm_struct* */ -#define KFD_PROCESS_TABLE_SIZE 5 /* bits: 32 entries */ -static DEFINE_HASHTABLE(kfd_processes_table, KFD_PROCESS_TABLE_SIZE); +DEFINE_HASHTABLE(kfd_processes_table, KFD_PROCESS_TABLE_SIZE); static DEFINE_MUTEX(kfd_processes_mutex); -DEFINE_STATIC_SRCU(kfd_processes_srcu); +DEFINE_SRCU(kfd_processes_srcu); static struct workqueue_struct *kfd_process_wq; @@ -173,14 +173,8 @@ static void kfd_process_wq_release(struct work_struct *work) { struct kfd_process *p = container_of(work, struct kfd_process, release_work); - struct kfd_process_device *pdd; - pr_debug("Releasing process (pasid %d) in workqueue\n", p->pasid); - - list_for_each_entry(pdd, &p->per_device_data, per_device_list) { - if (pdd->bound == PDD_BOUND) - amd_iommu_unbind_pasid(pdd->dev->pdev, p->pasid); - } + kfd_iommu_unbind_process(p); kfd_process_destroy_pdds(p); @@ -429,133 +423,13 @@ struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev, return ERR_PTR(-ENOMEM); } - if (pdd->bound == PDD_BOUND) { - return pdd; - } else if (unlikely(pdd->bound == PDD_BOUND_SUSPENDED)) { - pr_err("Binding PDD_BOUND_SUSPENDED pdd is unexpected!\n"); - return ERR_PTR(-EINVAL); - } - - err = amd_iommu_bind_pasid(dev->pdev, p->pasid, p->lead_thread); - if (err < 0) + err = kfd_iommu_bind_process_to_device(pdd); + if (err) return ERR_PTR(err); - pdd->bound = PDD_BOUND; - return pdd; } -/* - * Bind processes do the device that have been temporarily unbound - * (PDD_BOUND_SUSPENDED) in kfd_unbind_processes_from_device. - */ -int kfd_bind_processes_to_device(struct kfd_dev *dev) -{ - struct kfd_process_device *pdd; - struct kfd_process *p; - unsigned int temp; - int err = 0; - - int idx = srcu_read_lock(&kfd_processes_srcu); - - hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { - mutex_lock(&p->mutex); - pdd = kfd_get_process_device_data(dev, p); - - if (WARN_ON(!pdd) || pdd->bound != PDD_BOUND_SUSPENDED) { - mutex_unlock(&p->mutex); - continue; - } - - err = amd_iommu_bind_pasid(dev->pdev, p->pasid, - p->lead_thread); - if (err < 0) { - pr_err("Unexpected pasid %d binding failure\n", - p->pasid); - mutex_unlock(&p->mutex); - break; - } - - pdd->bound = PDD_BOUND; - mutex_unlock(&p->mutex); - } - - srcu_read_unlock(&kfd_processes_srcu, idx); - - return err; -} - -/* - * Mark currently bound processes as PDD_BOUND_SUSPENDED. These - * processes will be restored to PDD_BOUND state in - * kfd_bind_processes_to_device. - */ -void kfd_unbind_processes_from_device(struct kfd_dev *dev) -{ - struct kfd_process_device *pdd; - struct kfd_process *p; - unsigned int temp; - - int idx = srcu_read_lock(&kfd_processes_srcu); - - hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { - mutex_lock(&p->mutex); - pdd = kfd_get_process_device_data(dev, p); - - if (WARN_ON(!pdd)) { - mutex_unlock(&p->mutex); - continue; - } - - if (pdd->bound == PDD_BOUND) - pdd->bound = PDD_BOUND_SUSPENDED; - mutex_unlock(&p->mutex); - } - - srcu_read_unlock(&kfd_processes_srcu, idx); -} - -void kfd_process_iommu_unbind_callback(struct kfd_dev *dev, unsigned int pasid) -{ - struct kfd_process *p; - struct kfd_process_device *pdd; - - /* - * Look for the process that matches the pasid. If there is no such - * process, we either released it in amdkfd's own notifier, or there - * is a bug. Unfortunately, there is no way to tell... - */ - p = kfd_lookup_process_by_pasid(pasid); - if (!p) - return; - - pr_debug("Unbinding process %d from IOMMU\n", pasid); - - mutex_lock(kfd_get_dbgmgr_mutex()); - - if (dev->dbgmgr && dev->dbgmgr->pasid == p->pasid) { - if (!kfd_dbgmgr_unregister(dev->dbgmgr, p)) { - kfd_dbgmgr_destroy(dev->dbgmgr); - dev->dbgmgr = NULL; - } - } - - mutex_unlock(kfd_get_dbgmgr_mutex()); - - mutex_lock(&p->mutex); - - pdd = kfd_get_process_device_data(dev, p); - if (pdd) - /* For GPU relying on IOMMU, we need to dequeue here - * when PASID is still bound. - */ - kfd_process_dequeue_from_device(pdd); - - mutex_unlock(&p->mutex); - - kfd_unref_process(p); -} - struct kfd_process_device *kfd_get_first_process_device_data( struct kfd_process *p) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 7783250e1c6d..250615535563 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -35,6 +35,7 @@ #include "kfd_crat.h" #include "kfd_topology.h" #include "kfd_device_queue_manager.h" +#include "kfd_iommu.h" /* topology_device_list - Master list of all topology devices */ static struct list_head topology_device_list; @@ -875,19 +876,8 @@ static void find_system_memory(const struct dmi_header *dm, */ static int kfd_add_perf_to_topology(struct kfd_topology_device *kdev) { - struct kfd_perf_properties *props; - - if (amd_iommu_pc_supported()) { - props = kfd_alloc_struct(props); - if (!props) - return -ENOMEM; - strcpy(props->block_name, "iommu"); - props->max_concurrent = amd_iommu_pc_get_max_banks(0) * - amd_iommu_pc_get_max_counters(0); /* assume one iommu */ - list_add_tail(&props->list, &kdev->perf_props); - } - - return 0; + /* These are the only counters supported so far */ + return kfd_iommu_add_perf_counters(kdev); } /* kfd_add_non_crat_information - Add information that is not currently diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h index 53fca1f45401..c0be2be6dca5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h @@ -25,7 +25,7 @@ #include #include -#include "kfd_priv.h" +#include "kfd_crat.h" #define KFD_TOPOLOGY_PUBLIC_NAME_SIZE 128 @@ -183,8 +183,4 @@ struct kfd_topology_device *kfd_create_topology_device( struct list_head *device_list); void kfd_release_topology_device_list(struct list_head *device_list); -extern bool amd_iommu_pc_supported(void); -extern u8 amd_iommu_pc_get_max_banks(u16 devid); -extern u8 amd_iommu_pc_get_max_counters(u16 devid); - #endif /* __KFD_TOPOLOGY_H__ */ -- cgit v1.2.3 From 787e1853ae8a951233ceab1b01c862d9c668358b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 8 Jan 2018 07:47:36 +0100 Subject: iio: adc: aspeed: Fix error handling path The labels and branching order of the error path of 'aspeed_adc_probe()' are broken. Re-order the labels and goto statements. Signed-off-by: Christophe JAILLET Signed-off-by: Jonathan Cameron --- drivers/iio/adc/aspeed_adc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c index 327a49ba1991..9515ca165dfd 100644 --- a/drivers/iio/adc/aspeed_adc.c +++ b/drivers/iio/adc/aspeed_adc.c @@ -243,7 +243,7 @@ static int aspeed_adc_probe(struct platform_device *pdev) ASPEED_ADC_INIT_POLLING_TIME, ASPEED_ADC_INIT_TIMEOUT); if (ret) - goto scaler_error; + goto poll_timeout_error; } /* Start all channels in normal mode. */ @@ -274,9 +274,10 @@ iio_register_error: writel(ASPEED_OPERATION_MODE_POWER_DOWN, data->base + ASPEED_REG_ENGINE_CONTROL); clk_disable_unprepare(data->clk_scaler->clk); -reset_error: - reset_control_assert(data->rst); clk_enable_error: +poll_timeout_error: + reset_control_assert(data->rst); +reset_error: clk_hw_unregister_divider(data->clk_scaler); scaler_error: clk_hw_unregister_divider(data->clk_prescaler); -- cgit v1.2.3 From e31b617d0a63c6558485aaa730fd162faa95a766 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 22 Jan 2018 11:53:12 +0200 Subject: staging: iio: adc: ad7192: fix external frequency setting The external clock frequency was set only when selecting the internal clock, which is fixed at 4.9152 Mhz. This is incorrect, since it should be set when any of the external clock or crystal settings is selected. Added range validation for the external (crystal/clock) frequency setting. Valid values are between 2.4576 and 5.12 Mhz. Signed-off-by: Alexandru Ardelean Cc: Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7192.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index f01595593ce2..425e8b82533b 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -141,6 +141,8 @@ #define AD7192_GPOCON_P1DAT BIT(1) /* P1 state */ #define AD7192_GPOCON_P0DAT BIT(0) /* P0 state */ +#define AD7192_EXT_FREQ_MHZ_MIN 2457600 +#define AD7192_EXT_FREQ_MHZ_MAX 5120000 #define AD7192_INT_FREQ_MHZ 4915200 /* NOTE: @@ -218,6 +220,12 @@ static int ad7192_calibrate_all(struct ad7192_state *st) ARRAY_SIZE(ad7192_calib_arr)); } +static inline bool ad7192_valid_external_frequency(u32 freq) +{ + return (freq >= AD7192_EXT_FREQ_MHZ_MIN && + freq <= AD7192_EXT_FREQ_MHZ_MAX); +} + static int ad7192_setup(struct ad7192_state *st, const struct ad7192_platform_data *pdata) { @@ -243,17 +251,20 @@ static int ad7192_setup(struct ad7192_state *st, id); switch (pdata->clock_source_sel) { - case AD7192_CLK_EXT_MCLK1_2: - case AD7192_CLK_EXT_MCLK2: - st->mclk = AD7192_INT_FREQ_MHZ; - break; case AD7192_CLK_INT: case AD7192_CLK_INT_CO: - if (pdata->ext_clk_hz) - st->mclk = pdata->ext_clk_hz; - else - st->mclk = AD7192_INT_FREQ_MHZ; + st->mclk = AD7192_INT_FREQ_MHZ; break; + case AD7192_CLK_EXT_MCLK1_2: + case AD7192_CLK_EXT_MCLK2: + if (ad7192_valid_external_frequency(pdata->ext_clk_hz)) { + st->mclk = pdata->ext_clk_hz; + break; + } + dev_err(&st->sd.spi->dev, "Invalid frequency setting %u\n", + pdata->ext_clk_hz); + ret = -EINVAL; + goto out; default: ret = -EINVAL; goto out; -- cgit v1.2.3 From a3b5655ebdb501a98a45c0d3265dca9f2fe0218a Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Tue, 23 Jan 2018 17:04:56 +0100 Subject: iio: adc: stm32: fix stm32h7_adc_enable error handling Error handling in stm32h7_adc_enable routine doesn't unwind enable sequence correctly. ADEN can only be cleared by hardware (e.g. by writing one to ADDIS). It's also better to clear ADRDY just after it's been set by hardware. Fixes: 95e339b6e85d ("iio: adc: stm32: add support for STM32H7") Signed-off-by: Fabrice Gasnier Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 7f5def465340..9a2583caedaa 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -722,8 +722,6 @@ static int stm32h7_adc_enable(struct stm32_adc *adc) int ret; u32 val; - /* Clear ADRDY by writing one, then enable ADC */ - stm32_adc_set_bits(adc, STM32H7_ADC_ISR, STM32H7_ADRDY); stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADEN); /* Poll for ADRDY to be set (after adc startup time) */ @@ -731,8 +729,11 @@ static int stm32h7_adc_enable(struct stm32_adc *adc) val & STM32H7_ADRDY, 100, STM32_ADC_TIMEOUT_US); if (ret) { - stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADEN); + stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADDIS); dev_err(&indio_dev->dev, "Failed to enable ADC\n"); + } else { + /* Clear ADRDY by writing one */ + stm32_adc_set_bits(adc, STM32H7_ADC_ISR, STM32H7_ADRDY); } return ret; -- cgit v1.2.3 From 7d2b8e6aaf9ee87910c2337e1c59bb5d3e3ba8c5 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 25 Jan 2018 14:30:45 +0200 Subject: staging: iio: ad5933: switch buffer mode to software Since commit 152a6a884ae1 ("staging:iio:accel:sca3000 move to hybrid hard / soft buffer design.") the buffer mechanism has changed and the INDIO_BUFFER_HARDWARE flag has been unused. Since commit 2d6ca60f3284 ("iio: Add a DMAengine framework based buffer") the INDIO_BUFFER_HARDWARE flag has been re-purposed for DMA buffers. This driver has lagged behind these changes, and in order for buffers to work, the INDIO_BUFFER_SOFTWARE needs to be used. Signed-off-by: Alexandru Ardelean Fixes: 2d6ca60f3284 ("iio: Add a DMAengine framework based buffer") Cc: Signed-off-by: Jonathan Cameron --- drivers/staging/iio/impedance-analyzer/ad5933.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 2b28fb9c0048..3bcf49466361 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -648,8 +648,6 @@ static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev) /* Ring buffer functions - here trigger setup related */ indio_dev->setup_ops = &ad5933_ring_setup_ops; - indio_dev->modes |= INDIO_BUFFER_HARDWARE; - return 0; } @@ -762,7 +760,7 @@ static int ad5933_probe(struct i2c_client *client, indio_dev->dev.parent = &client->dev; indio_dev->info = &ad5933_info; indio_dev->name = id->name; - indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE); indio_dev->channels = ad5933_channels; indio_dev->num_channels = ARRAY_SIZE(ad5933_channels); -- cgit v1.2.3 From 4a8842de8db4953fdda7866626b78b12fb8adb97 Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Fri, 19 Jan 2018 16:22:05 +0100 Subject: scsi: mpt3sas: fix an out of bound write cpu_msix_table is allocated to store online cpus, but pci_irq_get_affinity may return cpu_possible_mask which is then used to access cpu_msix_table. That causes bad user experience. Fix limits access to only online cpus, I've also added an additional test to protect from an unlikely change in cpu_online_mask. [mkp: checkpatch] Fixes: 1d55abc0e98a ("scsi: mpt3sas: switch to pci_alloc_irq_vectors") Signed-off-by: Tomas Henzl Acked-by: Suganath Prabu Subramani Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 13d6e4ec3022..59a87ca328d3 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2410,8 +2410,11 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) continue; } - for_each_cpu(cpu, mask) + for_each_cpu_and(cpu, mask, cpu_online_mask) { + if (cpu >= ioc->cpu_msix_table_sz) + break; ioc->cpu_msix_table[cpu] = reply_q->msix_index; + } } return; } -- cgit v1.2.3 From 2ce87cc5b269510de9ca1185ca8a6e10ec78c069 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 23 Jan 2018 11:05:21 -0800 Subject: scsi: qla2xxx: Fix memory corruption during hba reset test This patch fixes memory corrpution while performing HBA Reset test. Following stack trace is seen: [ 466.397219] BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 [ 466.433669] IP: [] qlt_free_session_done+0x260/0x5f0 [qla2xxx] [ 466.467731] PGD 0 [ 466.476718] Oops: 0000 [#1] SMP Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 12ee6e02d146..afcb5567998a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3625,6 +3625,8 @@ qla2x00_remove_one(struct pci_dev *pdev) } qla2x00_wait_for_hba_ready(base_vha); + qla2x00_wait_for_sess_deletion(base_vha); + /* * if UNLOAD flag is already set, then continue unload, * where it was set first. -- cgit v1.2.3 From c39813652700f3df552b6557530f1e5f782dbe2f Mon Sep 17 00:00:00 2001 From: Tyrel Datwyler Date: Tue, 23 Jan 2018 20:11:32 -0600 Subject: scsi: ibmvfc: fix misdefined reserved field in ibmvfc_fcp_rsp_info The fcp_rsp_info structure as defined in the FC spec has an initial 3 bytes reserved field. The ibmvfc driver mistakenly defined this field as 4 bytes resulting in the rsp_code field being defined in what should be the start of the second reserved field and thus always being reported as zero by the driver. Ideally, we should wire ibmvfc up with libfc for the sake of code deduplication, and ease of maintaining standardized structures in a single place. However, for now simply fixup the definition in ibmvfc for backporting to distros on older kernels. Wiring up with libfc will be done in a followup patch. Cc: Reported-by: Hannes Reinecke Signed-off-by: Tyrel Datwyler Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvfc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 9a0696f68f37..b81a53c4a9a8 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -367,7 +367,7 @@ enum ibmvfc_fcp_rsp_info_codes { }; struct ibmvfc_fcp_rsp_info { - __be16 reserved; + u8 reserved[3]; u8 rsp_code; u8 reserved2[4]; }__attribute__((packed, aligned (2))); -- cgit v1.2.3 From 84af7e8b895088d89f246d6b0f82717fafdebf61 Mon Sep 17 00:00:00 2001 From: Sujit Reddy Thumma Date: Wed, 24 Jan 2018 09:52:35 +0530 Subject: scsi: ufs: Enable quirk to ignore sending WRITE_SAME command WRITE_SAME command is not supported by UFS. Enable a quirk for the upper level drivers to not send WRITE SAME command. [mkp: botched patch, applied by hand] Signed-off-by: Sujit Reddy Thumma Signed-off-by: Subhash Jadavani Signed-off-by: Asutosh Das Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 011c3369082c..8196976182c9 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4352,6 +4352,8 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev) /* REPORT SUPPORTED OPERATION CODES is not supported */ sdev->no_report_opcodes = 1; + /* WRITE_SAME command is not supported */ + sdev->no_write_same = 1; ufshcd_set_queue_depth(sdev); -- cgit v1.2.3 From 52797a1d4b39716ddd300a3c463ffaf1330600a0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 24 Jan 2018 14:58:01 +0000 Subject: scsi: csiostor: remove redundant assignment to pointer 'ln' The pointer ln is assigned a value that is never read, it is re-assigned a new value in the list_for_each loop hence the initialization is redundant and can be removed. Cleans up clang warning: drivers/scsi/csiostor/csio_lnode.c:117:21: warning: Value stored to 'ln' during its initialization is never read Signed-off-by: Colin Ian King Acked-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_lnode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c index be5ee2d37815..7dbbbb81a1e7 100644 --- a/drivers/scsi/csiostor/csio_lnode.c +++ b/drivers/scsi/csiostor/csio_lnode.c @@ -114,7 +114,7 @@ static enum csio_ln_ev fwevt_to_lnevt[] = { static struct csio_lnode * csio_ln_lookup_by_portid(struct csio_hw *hw, uint8_t portid) { - struct csio_lnode *ln = hw->rln; + struct csio_lnode *ln; struct list_head *tmp; /* Match siblings lnode with portid */ -- cgit v1.2.3 From ecf7ff49945f5741fa1da112f994939f942031d3 Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Wed, 24 Jan 2018 08:07:06 -0800 Subject: scsi: bnx2fc: Fix check in SCSI completion handler for timed out request When a request times out we set the io_req flag BNX2FC_FLAG_IO_COMPL so that if a subsequent completion comes in on that task ID we will ignore it. The issue is that in the check for this flag there is a missing return so we will continue to process a request which may have already been returned to the ownership of the SCSI layer. This can cause unpredictable results. Solution is to add in the missing return. [mkp: typo plus title shortening] Signed-off-by: Chad Dupuis Reviewed-by: Laurence Oberman Tested-by: Laurence Oberman Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc_io.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 8e2f767147cb..5a645b8b9af1 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1889,6 +1889,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, /* we will not receive ABTS response for this IO */ BNX2FC_IO_DBG(io_req, "Timer context finished processing " "this scsi cmd\n"); + return; } /* Cancel the timeout_work, as we received IO completion */ -- cgit v1.2.3 From e6f791d95313c85f3dd4a26141e28e50ae9aa0ae Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 25 Jan 2018 17:13:40 +0300 Subject: scsi: sym53c8xx_2: iterator underflow in sym_getsync() We wanted to exit the loop with "div" set to zero, but instead, if we don't hit the break then "div" is -1 when we finish the loop. It leads to an array underflow a few lines later. Signed-off-by: Dan Carpenter Reviewed-by: Johannes Thumshirn Acked-by: Matthew Wilcox Signed-off-by: Martin K. Petersen --- drivers/scsi/sym53c8xx_2/sym_hipd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index ca360daa6a25..378af306fda1 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -536,7 +536,7 @@ sym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fa * Look for the greatest clock divisor that allows an * input speed faster than the period. */ - while (div-- > 0) + while (--div > 0) if (kpc >= (div_10M[div] << 2)) break; /* -- cgit v1.2.3 From a7043e9529f3c367cc4d82997e00be034cbe57ca Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 25 Jan 2018 17:27:27 +0300 Subject: scsi: mptfusion: Add bounds check in mptctl_hp_targetinfo() My static checker complains about an out of bounds read: drivers/message/fusion/mptctl.c:2786 mptctl_hp_targetinfo() error: buffer overflow 'hd->sel_timeout' 255 <= u32max. It's true that we probably should have a bounds check here. Signed-off-by: Dan Carpenter Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/message/fusion/mptctl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 8d12017b9893..4470630dd545 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -2687,6 +2687,8 @@ mptctl_hp_targetinfo(unsigned long arg) __FILE__, __LINE__, iocnum); return -ENODEV; } + if (karg.hdr.id >= MPT_MAX_FC_DEVICES) + return -EINVAL; dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n", ioc->name)); -- cgit v1.2.3 From c02189e12ce3bf3808cb880569d3b10249f50bd9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 25 Jan 2018 08:24:29 -0800 Subject: scsi: qla2xxx: Avoid triggering undefined behavior in qla2x00_mbx_completion() A left shift must shift less than the bit width of the left argument. Avoid triggering undefined behavior if ha->mbx_count == 32. This patch avoids that UBSAN reports the following complaint: UBSAN: Undefined behaviour in drivers/scsi/qla2xxx/qla_isr.c:275:14 shift exponent 32 is too large for 32-bit type 'int' Call Trace: dump_stack+0x4e/0x6c ubsan_epilogue+0xd/0x3b __ubsan_handle_shift_out_of_bounds+0x112/0x14c qla2x00_mbx_completion+0x1c5/0x25d [qla2xxx] qla2300_intr_handler+0x1ea/0x3bb [qla2xxx] qla2x00_mailbox_command+0x77b/0x139a [qla2xxx] qla2x00_mbx_reg_test+0x83/0x114 [qla2xxx] qla2x00_chip_diag+0x354/0x45f [qla2xxx] qla2x00_initialize_adapter+0x2c2/0xa4e [qla2xxx] qla2x00_probe_one+0x1681/0x392e [qla2xxx] pci_device_probe+0x10b/0x1f1 driver_probe_device+0x21f/0x3a4 __driver_attach+0xa9/0xe1 bus_for_each_dev+0x6e/0xb5 driver_attach+0x22/0x3c bus_add_driver+0x1d1/0x2ae driver_register+0x78/0x130 __pci_register_driver+0x75/0xa8 qla2x00_module_init+0x21b/0x267 [qla2xxx] do_one_initcall+0x5a/0x1e2 do_init_module+0x9d/0x285 load_module+0x20db/0x38e3 SYSC_finit_module+0xa8/0xbc SyS_finit_module+0x9/0xb do_syscall_64+0x77/0x271 entry_SYSCALL64_slow_path+0x25/0x25 Reported-by: Meelis Roos Signed-off-by: Bart Van Assche Cc: Himanshu Madhani Reviewed-by: Laurence Oberman Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_isr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 14109d86c3f6..89f93ebd819d 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -272,7 +272,8 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; /* Read all mbox registers? */ - mboxes = (1 << ha->mbx_count) - 1; + WARN_ON_ONCE(ha->mbx_count > 32); + mboxes = (1ULL << ha->mbx_count) - 1; if (!ha->mcp) ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n"); else @@ -2880,7 +2881,8 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; /* Read all mbox registers? */ - mboxes = (1 << ha->mbx_count) - 1; + WARN_ON_ONCE(ha->mbx_count > 32); + mboxes = (1ULL << ha->mbx_count) - 1; if (!ha->mcp) ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n"); else -- cgit v1.2.3 From 7c0dde2b3d99fe3c54edada408d10dcd6ee0c1f7 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Sun, 28 Jan 2018 07:23:54 +0000 Subject: scsi: aic7xxx: remove aiclib.c aiclib.c is unused (and contains no code) since commit 1ff927306e08 ("[SCSI] aic7xxx: remove aiclib.c") 13 years later, finish the cleaning by removing it from tree. [mkp: tweaked patch description] Signed-off-by: Corentin Labbe Signed-off-by: Martin K. Petersen --- drivers/scsi/aic7xxx/aiclib.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 drivers/scsi/aic7xxx/aiclib.c (limited to 'drivers') diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c deleted file mode 100644 index 828ae3d9a510..000000000000 --- a/drivers/scsi/aic7xxx/aiclib.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Implementation of Utility functions for all SCSI device types. - * - * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs. - * Copyright (c) 1997, 1998 Kenneth D. Merry. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - * - * $FreeBSD: src/sys/cam/scsi/scsi_all.c,v 1.38 2002/09/23 04:56:35 mjacob Exp $ - * $Id$ - */ - -#include "aiclib.h" - -- cgit v1.2.3 From 2e8233ab17411920bee87c0dd71790f11904f3b8 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Mon, 29 Jan 2018 12:30:16 +0000 Subject: scsi: Remove Makefile entry for oktagon files Remove line using non-existent files which were removed in commit 642978beb483 ("[SCSI] remove m68k NCR53C9x based drivers") [mkp: tweaked patch description] Signed-off-by: Corentin Labbe Acked-by: Geert Uytterhoeven Signed-off-by: Martin K. Petersen --- drivers/scsi/Makefile | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index fcfd28d2884c..de1b3fce936d 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -185,7 +185,6 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \ CFLAGS_ncr53c8xx.o := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m) zalon7xx-objs := zalon.o ncr53c8xx.o NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o -oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o # Files generated that shall be removed upon make clean clean-files := 53c700_d.h 53c700_u.h -- cgit v1.2.3 From f5572475e999a1e9cd44f8704023a815f611d377 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 Jan 2018 15:50:03 -0800 Subject: scsi: scsi_dh: Document alua_rtpg_queue() arguments Since commit 3a025e1d1c2e ("Add optional check for bad kernel-doc comments") building with W=1 causes warnings to appear for issues in kernel-doc headers. This patch avoids that the following warnings are reported when building with W=1: drivers/scsi/device_handler/scsi_dh_alua.c:867: warning: No description found for parameter 'pg' drivers/scsi/device_handler/scsi_dh_alua.c:867: warning: No description found for parameter 'sdev' drivers/scsi/device_handler/scsi_dh_alua.c:867: warning: No description found for parameter 'qdata' drivers/scsi/device_handler/scsi_dh_alua.c:867: warning: No description found for parameter 'force' Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Johannes Thumshirn Reviewed-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/device_handler/scsi_dh_alua.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 022e421c2185..4b44325d1a82 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -876,6 +876,11 @@ static void alua_rtpg_work(struct work_struct *work) /** * alua_rtpg_queue() - cause RTPG to be submitted asynchronously + * @pg: ALUA port group associated with @sdev. + * @sdev: SCSI device for which to submit an RTPG. + * @qdata: Information about the callback to invoke after the RTPG. + * @force: Whether or not to submit an RTPG if a work item that will submit an + * RTPG already has been scheduled. * * Returns true if and only if alua_rtpg_work() will be called asynchronously. * That function is responsible for calling @qdata->fn(). -- cgit v1.2.3 From 745fd50f3b044db6a3922e1718306555613164b0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 31 Jan 2018 12:04:50 +0100 Subject: drm/cirrus: Load lut in crtc_commit In the past the ast driver relied upon the fbdev emulation helpers to call ->load_lut at boot-up. But since commit b8e2b0199cc377617dc238f5106352c06dcd3fa2 Author: Peter Rosin Date: Tue Jul 4 12:36:57 2017 +0200 drm/fb-helper: factor out pseudo-palette that's cleaned up and drivers are expected to boot into a consistent lut state. This patch fixes that. Fixes: b8e2b0199cc3 ("drm/fb-helper: factor out pseudo-palette") Cc: Peter Rosin Cc: Daniel Vetter Cc: # v4.14+ References: https://bugzilla.kernel.org/show_bug.cgi?id=198123 Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20180131110450.22153-1-daniel.vetter@ffwll.ch Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/cirrus/cirrus_mode.c | 40 +++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index cd23b1b28259..c91b9b054e3f 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -294,22 +294,7 @@ static void cirrus_crtc_prepare(struct drm_crtc *crtc) { } -/* - * This is called after a mode is programmed. It should reverse anything done - * by the prepare function - */ -static void cirrus_crtc_commit(struct drm_crtc *crtc) -{ -} - -/* - * The core can pass us a set of gamma values to program. We actually only - * use this for 8-bit mode so can't perform smooth fades on deeper modes, - * but it's a requirement that we provide the function - */ -static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size, - struct drm_modeset_acquire_ctx *ctx) +static void cirrus_crtc_load_lut(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct cirrus_device *cdev = dev->dev_private; @@ -317,7 +302,7 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, int i; if (!crtc->enabled) - return 0; + return; r = crtc->gamma_store; g = r + crtc->gamma_size; @@ -330,6 +315,27 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, WREG8(PALETTE_DATA, *g++ >> 8); WREG8(PALETTE_DATA, *b++ >> 8); } +} + +/* + * This is called after a mode is programmed. It should reverse anything done + * by the prepare function + */ +static void cirrus_crtc_commit(struct drm_crtc *crtc) +{ + cirrus_crtc_load_lut(crtc); +} + +/* + * The core can pass us a set of gamma values to program. We actually only + * use this for 8-bit mode so can't perform smooth fades on deeper modes, + * but it's a requirement that we provide the function + */ +static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) +{ + cirrus_crtc_load_lut(crtc); return 0; } -- cgit v1.2.3 From 54f809cfbd6b4a43959039f5d33596ed3297ce16 Mon Sep 17 00:00:00 2001 From: "Leo (Sunpeng) Li" Date: Wed, 17 Jan 2018 12:51:08 +0100 Subject: drm/atomic: Fix memleak on ERESTARTSYS during non-blocking commits During a non-blocking commit, it is possible to return before the commit_tail work is queued (-ERESTARTSYS, for example). Since a reference on the crtc commit object is obtained for the pending vblank event when preparing the commit, the above situation will leave us with an extra reference. Therefore, if the commit_tail worker has not consumed the event at the end of a commit, release it's reference. Changes since v1: - Also check for state->event->base.completion being set, to handle the case where stall_checks() fails in setup_crtc_commit(). Changes since v2: - Add a flag to drm_crtc_commit, to prevent dereferencing a freed event. i915 may unreference the state in a worker. Fixes: 24835e442f28 ("drm: reference count event->completion") Cc: # v4.11+ Signed-off-by: Leo (Sunpeng) Li Acked-by: Harry Wentland #v1 Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20180117115108.29608-1-maarten.lankhorst@linux.intel.com Reviewed-by: Sean Paul --- drivers/gpu/drm/drm_atomic_helper.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index b16f1d69a0bb..e8c249361d7e 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1778,6 +1778,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, new_crtc_state->event->base.completion = &commit->flip_done; new_crtc_state->event->base.completion_release = release_crtc_commit; drm_crtc_commit_get(commit); + + commit->abort_completion = true; } for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) { @@ -3327,8 +3329,21 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) { if (state->commit) { + /* + * In the event that a non-blocking commit returns + * -ERESTARTSYS before the commit_tail work is queued, we will + * have an extra reference to the commit object. Release it, if + * the event has not been consumed by the worker. + * + * state->event may be freed, so we can't directly look at + * state->event->base.completion. + */ + if (state->event && state->commit->abort_completion) + drm_crtc_commit_put(state->commit); + kfree(state->commit->event); state->commit->event = NULL; + drm_crtc_commit_put(state->commit); } -- cgit v1.2.3 From 498e7e7ed1fd72c275a682f0903c4a20cc538658 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Thu, 1 Feb 2018 10:18:59 -0800 Subject: Input: mms114 - fix license module information The driver has been released with GNU Public License v2 as stated in the header, but the module license information has been tagged as "GPL" (GNU Public License v2 or later). Fix the module license information so that it matches the one in the header as "GPL v2". Fixes: 07b8481d4aff ("Input: add MELFAS mms114 touchscreen driver") Reported-by: Marcus Folkesson Signed-off-by: Andi Shyti Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/mms114.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index db4f6bb502e3..68236743632e 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -624,4 +624,4 @@ module_i2c_driver(mms114_driver); /* Module information */ MODULE_AUTHOR("Joonyoung Shim "); MODULE_DESCRIPTION("MELFAS mms114 Touchscreen driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 0004520af32fca8b40abe78c11654be4e9e20fdf Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Thu, 1 Feb 2018 10:22:20 -0800 Subject: Input: mms114 - add SPDX identifier Replace the original license statement with the SPDX identifier. Add also one line of description as recommended by the COPYING file. Signed-off-by: Andi Shyti Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/mms114.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 68236743632e..a5ab774da4cc 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -1,11 +1,8 @@ -/* - * Copyright (C) 2012 Samsung Electronics Co.Ltd - * Author: Joonyoung Shim - * - * 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 +// Melfas MMS114/MMS152 touchscreen device driver +// +// Copyright (c) 2012 Samsung Electronics Co., Ltd. +// Author: Joonyoung Shim #include #include -- cgit v1.2.3 From 511051d509ec54642dd6d30fdf2caa33c23619cc Mon Sep 17 00:00:00 2001 From: Andreas Klinger Date: Thu, 1 Feb 2018 21:49:24 +0100 Subject: iio: srf08: fix link error "devm_iio_triggered_buffer_setup" undefined Functions for triggered buffer support are needed by this module. If they are not defined accidentally by another driver, there's an error thrown out while linking. Add a select of IIO_BUFFER and IIO_TRIGGERED_BUFFER in the Kconfig file. Signed-off-by: Andreas Klinger Fixes: a83195937151 ("iio: srf08: add triggered buffer support") Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index fcb1c4ba5e41..f726f9427602 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -68,6 +68,8 @@ config SX9500 config SRF08 tristate "Devantech SRF02/SRF08/SRF10 ultrasonic ranger sensor" + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER depends on I2C help Say Y here to build a driver for Devantech SRF02/SRF08/SRF10 -- cgit v1.2.3 From 50dbd09c56db0555813aa2824dc4fe8f1fc06aaa Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 Jan 2018 16:33:46 -0800 Subject: scsi: qla2xxx: Fix a locking imbalance in qlt_24xx_handle_els() Ensure that upon return the tgt->ha->tgt.sess_lock spin lock is unlocked no matter which code path is taken through this function. This was detected by sparse. Fixes: 82abdcaf3ede ("scsi: qla2xxx: Allow target mode to accept PRLI in dual mode") Signed-off-by: Bart Van Assche Cc: Himanshu Madhani Cc: Quinn Tran Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_target.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index fc89af8fe256..896b2d8bd803 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -4871,8 +4871,6 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, sess); qlt_send_term_imm_notif(vha, iocb, 1); res = 0; - spin_lock_irqsave(&tgt->ha->tgt.sess_lock, - flags); break; } -- cgit v1.2.3 From 4252bf686622f6c71958c4fabbcb6a64deba1cf7 Mon Sep 17 00:00:00 2001 From: Harish Kasiviswanathan Date: Tue, 6 Feb 2018 20:32:42 -0500 Subject: drm/amdkfd: Remove unaligned memory access Unaligned atomic operations can cause problems on some CPU architectures. Use simpler bitmask operations instead. Atomic bit manipulations are not necessary since dqm->lock is held during these operations. Signed-off-by: Harish Kasiviswanathan Signed-off-by: Felix Kuehling Acked-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 25 ++++++++-------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 47d493ea8e4f..1a28dc2c661e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -118,9 +118,8 @@ static int allocate_vmid(struct device_queue_manager *dqm, if (dqm->vmid_bitmap == 0) return -ENOMEM; - bit = find_first_bit((unsigned long *)&dqm->vmid_bitmap, - dqm->dev->vm_info.vmid_num_kfd); - clear_bit(bit, (unsigned long *)&dqm->vmid_bitmap); + bit = ffs(dqm->vmid_bitmap) - 1; + dqm->vmid_bitmap &= ~(1 << bit); allocated_vmid = bit + dqm->dev->vm_info.first_vmid_kfd; pr_debug("vmid allocation %d\n", allocated_vmid); @@ -142,7 +141,7 @@ static void deallocate_vmid(struct device_queue_manager *dqm, /* Release the vmid mapping */ set_pasid_vmid_mapping(dqm, 0, qpd->vmid); - set_bit(bit, (unsigned long *)&dqm->vmid_bitmap); + dqm->vmid_bitmap |= (1 << bit); qpd->vmid = 0; q->properties.vmid = 0; } @@ -223,12 +222,8 @@ static int allocate_hqd(struct device_queue_manager *dqm, struct queue *q) continue; if (dqm->allocated_queues[pipe] != 0) { - bit = find_first_bit( - (unsigned long *)&dqm->allocated_queues[pipe], - get_queues_per_pipe(dqm)); - - clear_bit(bit, - (unsigned long *)&dqm->allocated_queues[pipe]); + bit = ffs(dqm->allocated_queues[pipe]) - 1; + dqm->allocated_queues[pipe] &= ~(1 << bit); q->pipe = pipe; q->queue = bit; set = true; @@ -249,7 +244,7 @@ static int allocate_hqd(struct device_queue_manager *dqm, struct queue *q) static inline void deallocate_hqd(struct device_queue_manager *dqm, struct queue *q) { - set_bit(q->queue, (unsigned long *)&dqm->allocated_queues[q->pipe]); + dqm->allocated_queues[q->pipe] |= (1 << q->queue); } static int create_compute_queue_nocpsch(struct device_queue_manager *dqm, @@ -589,10 +584,8 @@ static int allocate_sdma_queue(struct device_queue_manager *dqm, if (dqm->sdma_bitmap == 0) return -ENOMEM; - bit = find_first_bit((unsigned long *)&dqm->sdma_bitmap, - CIK_SDMA_QUEUES); - - clear_bit(bit, (unsigned long *)&dqm->sdma_bitmap); + bit = ffs(dqm->sdma_bitmap) - 1; + dqm->sdma_bitmap &= ~(1 << bit); *sdma_queue_id = bit; return 0; @@ -603,7 +596,7 @@ static void deallocate_sdma_queue(struct device_queue_manager *dqm, { if (sdma_queue_id >= CIK_SDMA_QUEUES) return; - set_bit(sdma_queue_id, (unsigned long *)&dqm->sdma_bitmap); + dqm->sdma_bitmap |= (1 << sdma_queue_id); } static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm, -- cgit v1.2.3 From 403575c44e61722ae443b47df66e188b367d7324 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Tue, 6 Feb 2018 20:32:44 -0500 Subject: drm/amdkfd: Add GPUVM virtual address space to PDD Create/destroy the GPUVM context during PDD creation/destruction. Get VM page table base and program it during process registration (HWS) or VMID allocation (non-HWS). v2: * Used dev instead of pdd->dev in kfd_flush_tlb Signed-off-by: Felix Kuehling Acked-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 20 +++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 13 +++++++++ drivers/gpu/drm/amd/amdkfd/kfd_process.c | 33 ++++++++++++++++++++++ 3 files changed, 66 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 1a28dc2c661e..b7d06395d592 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -129,6 +129,15 @@ static int allocate_vmid(struct device_queue_manager *dqm, set_pasid_vmid_mapping(dqm, q->process->pasid, q->properties.vmid); program_sh_mem_settings(dqm, qpd); + /* qpd->page_table_base is set earlier when register_process() + * is called, i.e. when the first queue is created. + */ + dqm->dev->kfd2kgd->set_vm_context_page_table_base(dqm->dev->kgd, + qpd->vmid, + qpd->page_table_base); + /* invalidate the VM context after pasid and vmid mapping is set up */ + kfd_flush_tlb(qpd_to_pdd(qpd)); + return 0; } @@ -138,6 +147,8 @@ static void deallocate_vmid(struct device_queue_manager *dqm, { int bit = qpd->vmid - dqm->dev->vm_info.first_vmid_kfd; + kfd_flush_tlb(qpd_to_pdd(qpd)); + /* Release the vmid mapping */ set_pasid_vmid_mapping(dqm, 0, qpd->vmid); @@ -450,6 +461,8 @@ static int register_process(struct device_queue_manager *dqm, struct qcm_process_device *qpd) { struct device_process_node *n; + struct kfd_process_device *pdd; + uint32_t pd_base; int retval; n = kzalloc(sizeof(*n), GFP_KERNEL); @@ -458,9 +471,16 @@ static int register_process(struct device_queue_manager *dqm, n->qpd = qpd; + pdd = qpd_to_pdd(qpd); + /* Retrieve PD base */ + pd_base = dqm->dev->kfd2kgd->get_process_page_dir(pdd->vm); + mutex_lock(&dqm->lock); list_add(&n->list, &dqm->queues); + /* Update PD Base in QPD */ + qpd->page_table_base = pd_base; + retval = dqm->asic_ops.update_qpd(dqm, qpd); dqm->processes_count++; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index f12eb5d98be8..56c2e368f702 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -518,6 +518,9 @@ struct kfd_process_device { uint64_t scratch_base; uint64_t scratch_limit; + /* VM context for GPUVM allocations */ + void *vm; + /* Flag used to tell the pdd has dequeued from the dqm. * This is used to prevent dev->dqm->ops.process_termination() from * being called twice when it is already called in IOMMU callback @@ -589,6 +592,14 @@ struct kfd_process { size_t signal_mapped_size; size_t signal_event_count; bool signal_event_limit_reached; + + /* Information used for memory eviction */ + void *kgd_process_info; + /* Eviction fence that is attached to all the BOs of this process. The + * fence will be triggered during eviction and new one will be created + * during restore + */ + struct dma_fence *ef; }; #define KFD_PROCESS_TABLE_SIZE 5 /* bits: 32 entries */ @@ -802,6 +813,8 @@ int kfd_event_create(struct file *devkfd, struct kfd_process *p, uint64_t *event_page_offset, uint32_t *event_slot_index); int kfd_event_destroy(struct kfd_process *p, uint32_t event_id); +void kfd_flush_tlb(struct kfd_process_device *pdd); + int dbgdev_wave_reset_wavefronts(struct kfd_dev *dev, struct kfd_process *p); /* Debugfs */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index e9aee76ceba9..cf4fa25cc430 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -34,6 +34,7 @@ struct mm_struct; #include "kfd_priv.h" +#include "kfd_device_queue_manager.h" #include "kfd_dbgmgr.h" #include "kfd_iommu.h" @@ -154,6 +155,10 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) pr_debug("Releasing pdd (topology id %d) for process (pasid %d)\n", pdd->dev->id, p->pasid); + if (pdd->vm) + pdd->dev->kfd2kgd->destroy_process_vm( + pdd->dev->kgd, pdd->vm); + list_del(&pdd->per_device_list); if (pdd->qpd.cwsr_kaddr) @@ -177,6 +182,7 @@ static void kfd_process_wq_release(struct work_struct *work) kfd_iommu_unbind_process(p); kfd_process_destroy_pdds(p); + dma_fence_put(p->ef); kfd_event_free_process(p); @@ -401,7 +407,18 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev, pdd->already_dequeued = false; list_add(&pdd->per_device_list, &p->per_device_data); + /* Create the GPUVM context for this specific device */ + if (dev->kfd2kgd->create_process_vm(dev->kgd, &pdd->vm, + &p->kgd_process_info, &p->ef)) { + pr_err("Failed to create process VM object\n"); + goto err_create_pdd; + } return pdd; + +err_create_pdd: + list_del(&pdd->per_device_list); + kfree(pdd); + return NULL; } /* @@ -507,6 +524,22 @@ int kfd_reserved_mem_mmap(struct kfd_process *process, KFD_CWSR_TBA_TMA_SIZE, vma->vm_page_prot); } +void kfd_flush_tlb(struct kfd_process_device *pdd) +{ + struct kfd_dev *dev = pdd->dev; + const struct kfd2kgd_calls *f2g = dev->kfd2kgd; + + if (dev->dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) { + /* Nothing to flush until a VMID is assigned, which + * only happens when the first queue is created. + */ + if (pdd->qpd.vmid) + f2g->invalidate_tlbs_vmid(dev->kgd, pdd->qpd.vmid); + } else { + f2g->invalidate_tlbs(dev->kgd, pdd->process->pasid); + } +} + #if defined(CONFIG_DEBUG_FS) int kfd_debugfs_mqds_by_process(struct seq_file *m, void *data) -- cgit v1.2.3 From 26103436da003327017af325483b6150a3b855cc Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Tue, 6 Feb 2018 20:32:45 -0500 Subject: drm/amdkfd: Implement KFD process eviction/restore When the TTM memory manager in KGD evicts BOs, all user mode queues potentially accessing these BOs must be evicted temporarily. Once user mode queues are evicted, the eviction fence is signaled, allowing the migration of the BO to proceed. A delayed worker is scheduled to restore all the BOs belonging to the evicted process and restart its queues. During suspend/resume of the GPU we also evict all processes to allow KGD to save BOs in system memory, since VRAM will be lost. v2: * Account for eviction when updating of q->is_active in MQD manager Signed-off-by: Harish Kasiviswanathan Signed-off-by: Felix Kuehling Acked-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 65 +++++- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 219 ++++++++++++++++++++- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | 9 + drivers/gpu/drm/amd/amdkfd/kfd_module.c | 2 + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c | 9 +- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 6 +- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 32 ++- drivers/gpu/drm/amd/amdkfd/kfd_process.c | 213 ++++++++++++++++++++ 8 files changed, 547 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 4ac2d61b65d5..3346699960dd 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -33,6 +33,7 @@ #include "kfd_iommu.h" #define MQD_SIZE_ALIGNED 768 +static atomic_t kfd_device_suspended = ATOMIC_INIT(0); #ifdef KFD_SUPPORT_IOMMU_V2 static const struct kfd_device_info kaveri_device_info = { @@ -469,6 +470,10 @@ void kgd2kfd_suspend(struct kfd_dev *kfd) if (!kfd->init_complete) return; + /* For first KFD device suspend all the KFD processes */ + if (atomic_inc_return(&kfd_device_suspended) == 1) + kfd_suspend_all_processes(); + kfd->dqm->ops.stop(kfd->dqm); kfd_iommu_suspend(kfd); @@ -476,11 +481,21 @@ void kgd2kfd_suspend(struct kfd_dev *kfd) int kgd2kfd_resume(struct kfd_dev *kfd) { + int ret, count; + if (!kfd->init_complete) return 0; - return kfd_resume(kfd); + ret = kfd_resume(kfd); + if (ret) + return ret; + + count = atomic_dec_return(&kfd_device_suspended); + WARN_ONCE(count < 0, "KFD suspend / resume ref. error"); + if (count == 0) + ret = kfd_resume_all_processes(); + return ret; } static int kfd_resume(struct kfd_dev *kfd) @@ -526,6 +541,54 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry) spin_unlock(&kfd->interrupt_lock); } +/** kgd2kfd_schedule_evict_and_restore_process - Schedules work queue that will + * prepare for safe eviction of KFD BOs that belong to the specified + * process. + * + * @mm: mm_struct that identifies the specified KFD process + * @fence: eviction fence attached to KFD process BOs + * + */ +int kgd2kfd_schedule_evict_and_restore_process(struct mm_struct *mm, + struct dma_fence *fence) +{ + struct kfd_process *p; + unsigned long active_time; + unsigned long delay_jiffies = msecs_to_jiffies(PROCESS_ACTIVE_TIME_MS); + + if (!fence) + return -EINVAL; + + if (dma_fence_is_signaled(fence)) + return 0; + + p = kfd_lookup_process_by_mm(mm); + if (!p) + return -ENODEV; + + if (fence->seqno == p->last_eviction_seqno) + goto out; + + p->last_eviction_seqno = fence->seqno; + + /* Avoid KFD process starvation. Wait for at least + * PROCESS_ACTIVE_TIME_MS before evicting the process again + */ + active_time = get_jiffies_64() - p->last_restore_timestamp; + if (delay_jiffies > active_time) + delay_jiffies -= active_time; + else + delay_jiffies = 0; + + /* During process initialization eviction_work.dwork is initialized + * to kfd_evict_bo_worker + */ + schedule_delayed_work(&p->eviction_work, delay_jiffies); +out: + kfd_unref_process(p); + return 0; +} + static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size, unsigned int chunk_size) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index b7d06395d592..b3b6dab71638 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -21,10 +21,11 @@ * */ +#include +#include #include #include #include -#include #include #include #include "kfd_priv.h" @@ -180,6 +181,14 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm, goto out_unlock; } q->properties.vmid = qpd->vmid; + /* + * Eviction state logic: we only mark active queues as evicted + * to avoid the overhead of restoring inactive queues later + */ + if (qpd->evicted) + q->properties.is_evicted = (q->properties.queue_size > 0 && + q->properties.queue_percent > 0 && + q->properties.queue_address != 0); q->properties.tba_addr = qpd->tba_addr; q->properties.tma_addr = qpd->tma_addr; @@ -377,15 +386,29 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) { int retval; struct mqd_manager *mqd; + struct kfd_process_device *pdd; bool prev_active = false; mutex_lock(&dqm->lock); + pdd = kfd_get_process_device_data(q->device, q->process); + if (!pdd) { + retval = -ENODEV; + goto out_unlock; + } mqd = dqm->ops.get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); if (!mqd) { retval = -ENOMEM; goto out_unlock; } + /* + * Eviction state logic: we only mark active queues as evicted + * to avoid the overhead of restoring inactive queues later + */ + if (pdd->qpd.evicted) + q->properties.is_evicted = (q->properties.queue_size > 0 && + q->properties.queue_percent > 0 && + q->properties.queue_address != 0); /* Save previous activity state for counters */ prev_active = q->properties.is_active; @@ -457,6 +480,187 @@ static struct mqd_manager *get_mqd_manager( return mqd; } +static int evict_process_queues_nocpsch(struct device_queue_manager *dqm, + struct qcm_process_device *qpd) +{ + struct queue *q; + struct mqd_manager *mqd; + struct kfd_process_device *pdd; + int retval = 0; + + mutex_lock(&dqm->lock); + if (qpd->evicted++ > 0) /* already evicted, do nothing */ + goto out; + + pdd = qpd_to_pdd(qpd); + pr_info_ratelimited("Evicting PASID %u queues\n", + pdd->process->pasid); + + /* unactivate all active queues on the qpd */ + list_for_each_entry(q, &qpd->queues_list, list) { + if (!q->properties.is_active) + continue; + mqd = dqm->ops.get_mqd_manager(dqm, + get_mqd_type_from_queue_type(q->properties.type)); + if (!mqd) { /* should not be here */ + pr_err("Cannot evict queue, mqd mgr is NULL\n"); + retval = -ENOMEM; + goto out; + } + q->properties.is_evicted = true; + q->properties.is_active = false; + retval = mqd->destroy_mqd(mqd, q->mqd, + KFD_PREEMPT_TYPE_WAVEFRONT_DRAIN, + KFD_UNMAP_LATENCY_MS, q->pipe, q->queue); + if (retval) + goto out; + dqm->queue_count--; + } + +out: + mutex_unlock(&dqm->lock); + return retval; +} + +static int evict_process_queues_cpsch(struct device_queue_manager *dqm, + struct qcm_process_device *qpd) +{ + struct queue *q; + struct kfd_process_device *pdd; + int retval = 0; + + mutex_lock(&dqm->lock); + if (qpd->evicted++ > 0) /* already evicted, do nothing */ + goto out; + + pdd = qpd_to_pdd(qpd); + pr_info_ratelimited("Evicting PASID %u queues\n", + pdd->process->pasid); + + /* unactivate all active queues on the qpd */ + list_for_each_entry(q, &qpd->queues_list, list) { + if (!q->properties.is_active) + continue; + q->properties.is_evicted = true; + q->properties.is_active = false; + dqm->queue_count--; + } + retval = execute_queues_cpsch(dqm, + qpd->is_debug ? + KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES : + KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0); + +out: + mutex_unlock(&dqm->lock); + return retval; +} + +static int restore_process_queues_nocpsch(struct device_queue_manager *dqm, + struct qcm_process_device *qpd) +{ + struct queue *q; + struct mqd_manager *mqd; + struct kfd_process_device *pdd; + uint32_t pd_base; + int retval = 0; + + pdd = qpd_to_pdd(qpd); + /* Retrieve PD base */ + pd_base = dqm->dev->kfd2kgd->get_process_page_dir(pdd->vm); + + mutex_lock(&dqm->lock); + if (WARN_ON_ONCE(!qpd->evicted)) /* already restored, do nothing */ + goto out; + if (qpd->evicted > 1) { /* ref count still > 0, decrement & quit */ + qpd->evicted--; + goto out; + } + + pr_info_ratelimited("Restoring PASID %u queues\n", + pdd->process->pasid); + + /* Update PD Base in QPD */ + qpd->page_table_base = pd_base; + pr_debug("Updated PD address to 0x%08x\n", pd_base); + + if (!list_empty(&qpd->queues_list)) { + dqm->dev->kfd2kgd->set_vm_context_page_table_base( + dqm->dev->kgd, + qpd->vmid, + qpd->page_table_base); + kfd_flush_tlb(pdd); + } + + /* activate all active queues on the qpd */ + list_for_each_entry(q, &qpd->queues_list, list) { + if (!q->properties.is_evicted) + continue; + mqd = dqm->ops.get_mqd_manager(dqm, + get_mqd_type_from_queue_type(q->properties.type)); + if (!mqd) { /* should not be here */ + pr_err("Cannot restore queue, mqd mgr is NULL\n"); + retval = -ENOMEM; + goto out; + } + q->properties.is_evicted = false; + q->properties.is_active = true; + retval = mqd->load_mqd(mqd, q->mqd, q->pipe, + q->queue, &q->properties, + q->process->mm); + if (retval) + goto out; + dqm->queue_count++; + } + qpd->evicted = 0; +out: + mutex_unlock(&dqm->lock); + return retval; +} + +static int restore_process_queues_cpsch(struct device_queue_manager *dqm, + struct qcm_process_device *qpd) +{ + struct queue *q; + struct kfd_process_device *pdd; + uint32_t pd_base; + int retval = 0; + + pdd = qpd_to_pdd(qpd); + /* Retrieve PD base */ + pd_base = dqm->dev->kfd2kgd->get_process_page_dir(pdd->vm); + + mutex_lock(&dqm->lock); + if (WARN_ON_ONCE(!qpd->evicted)) /* already restored, do nothing */ + goto out; + if (qpd->evicted > 1) { /* ref count still > 0, decrement & quit */ + qpd->evicted--; + goto out; + } + + pr_info_ratelimited("Restoring PASID %u queues\n", + pdd->process->pasid); + + /* Update PD Base in QPD */ + qpd->page_table_base = pd_base; + pr_debug("Updated PD address to 0x%08x\n", pd_base); + + /* activate all active queues on the qpd */ + list_for_each_entry(q, &qpd->queues_list, list) { + if (!q->properties.is_evicted) + continue; + q->properties.is_evicted = false; + q->properties.is_active = true; + dqm->queue_count++; + } + retval = execute_queues_cpsch(dqm, + KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0); + if (!retval) + qpd->evicted = 0; +out: + mutex_unlock(&dqm->lock); + return retval; +} + static int register_process(struct device_queue_manager *dqm, struct qcm_process_device *qpd) { @@ -853,6 +1057,14 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, retval = -ENOMEM; goto out; } + /* + * Eviction state logic: we only mark active queues as evicted + * to avoid the overhead of restoring inactive queues later + */ + if (qpd->evicted) + q->properties.is_evicted = (q->properties.queue_size > 0 && + q->properties.queue_percent > 0 && + q->properties.queue_address != 0); dqm->asic_ops.init_sdma_vm(dqm, q, qpd); @@ -1291,6 +1503,8 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) dqm->ops.set_cache_memory_policy = set_cache_memory_policy; dqm->ops.set_trap_handler = set_trap_handler; dqm->ops.process_termination = process_termination_cpsch; + dqm->ops.evict_process_queues = evict_process_queues_cpsch; + dqm->ops.restore_process_queues = restore_process_queues_cpsch; break; case KFD_SCHED_POLICY_NO_HWS: /* initialize dqm for no cp scheduling */ @@ -1307,6 +1521,9 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) dqm->ops.set_cache_memory_policy = set_cache_memory_policy; dqm->ops.set_trap_handler = set_trap_handler; dqm->ops.process_termination = process_termination_nocpsch; + dqm->ops.evict_process_queues = evict_process_queues_nocpsch; + dqm->ops.restore_process_queues = + restore_process_queues_nocpsch; break; default: pr_err("Invalid scheduling policy %d\n", dqm->sched_policy); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index 68be0aaff3f4..412beff3281d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -79,6 +79,10 @@ struct device_process_node { * * @process_termination: Clears all process queues belongs to that device. * + * @evict_process_queues: Evict all active queues of a process + * + * @restore_process_queues: Restore all evicted queues queues of a process + * */ struct device_queue_manager_ops { @@ -129,6 +133,11 @@ struct device_queue_manager_ops { int (*process_termination)(struct device_queue_manager *dqm, struct qcm_process_device *qpd); + + int (*evict_process_queues)(struct device_queue_manager *dqm, + struct qcm_process_device *qpd); + int (*restore_process_queues)(struct device_queue_manager *dqm, + struct qcm_process_device *qpd); }; struct device_queue_manager_asic_ops { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c index 3ac72bed4f31..65574c6a10b3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c @@ -43,6 +43,8 @@ static const struct kgd2kfd_calls kgd2kfd = { .interrupt = kgd2kfd_interrupt, .suspend = kgd2kfd_suspend, .resume = kgd2kfd_resume, + .schedule_evict_and_restore_process = + kgd2kfd_schedule_evict_and_restore_process, }; int sched_policy = KFD_SCHED_POLICY_HWS; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c index fbe3f83ba685..c00c325ed3c9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -202,7 +202,8 @@ static int __update_mqd(struct mqd_manager *mm, void *mqd, q->is_active = (q->queue_size > 0 && q->queue_address != 0 && - q->queue_percent > 0); + q->queue_percent > 0 && + !q->is_evicted); return 0; } @@ -245,7 +246,8 @@ static int update_mqd_sdma(struct mqd_manager *mm, void *mqd, q->is_active = (q->queue_size > 0 && q->queue_address != 0 && - q->queue_percent > 0); + q->queue_percent > 0 && + !q->is_evicted); return 0; } @@ -377,7 +379,8 @@ static int update_mqd_hiq(struct mqd_manager *mm, void *mqd, q->is_active = (q->queue_size > 0 && q->queue_address != 0 && - q->queue_percent > 0); + q->queue_percent > 0 && + !q->is_evicted); return 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index 58221c1fc917..89e4242e43e7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -198,7 +198,8 @@ static int __update_mqd(struct mqd_manager *mm, void *mqd, q->is_active = (q->queue_size > 0 && q->queue_address != 0 && - q->queue_percent > 0); + q->queue_percent > 0 && + !q->is_evicted); return 0; } @@ -342,7 +343,8 @@ static int update_mqd_sdma(struct mqd_manager *mm, void *mqd, q->is_active = (q->queue_size > 0 && q->queue_address != 0 && - q->queue_percent > 0); + q->queue_percent > 0 && + !q->is_evicted); return 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 56c2e368f702..cac7aa258162 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -335,7 +335,11 @@ enum kfd_queue_format { * @is_interop: Defines if this is a interop queue. Interop queue means that * the queue can access both graphics and compute resources. * - * @is_active: Defines if the queue is active or not. + * @is_evicted: Defines if the queue is evicted. Only active queues + * are evicted, rendering them inactive. + * + * @is_active: Defines if the queue is active or not. @is_active and + * @is_evicted are protected by the DQM lock. * * @vmid: If the scheduling mode is no cp scheduling the field defines the vmid * of the queue. @@ -357,6 +361,7 @@ struct queue_properties { uint32_t __iomem *doorbell_ptr; uint32_t doorbell_off; bool is_interop; + bool is_evicted; bool is_active; /* Not relevant for user mode queues in cp scheduling */ unsigned int vmid; @@ -460,6 +465,7 @@ struct qcm_process_device { unsigned int queue_count; unsigned int vmid; bool is_debug; + unsigned int evicted; /* eviction counter, 0=active */ /* This flag tells if we should reset all wavefronts on * process termination @@ -486,6 +492,17 @@ struct qcm_process_device { uint64_t tma_addr; }; +/* KFD Memory Eviction */ + +/* Approx. wait time before attempting to restore evicted BOs */ +#define PROCESS_RESTORE_TIME_MS 100 +/* Approx. back off time if restore fails due to lack of memory */ +#define PROCESS_BACK_OFF_TIME_MS 100 +/* Approx. time before evicting the process again */ +#define PROCESS_ACTIVE_TIME_MS 10 + +int kgd2kfd_schedule_evict_and_restore_process(struct mm_struct *mm, + struct dma_fence *fence); enum kfd_pdd_bound { PDD_UNBOUND = 0, @@ -600,6 +617,16 @@ struct kfd_process { * during restore */ struct dma_fence *ef; + + /* Work items for evicting and restoring BOs */ + struct delayed_work eviction_work; + struct delayed_work restore_work; + /* seqno of the last scheduled eviction */ + unsigned int last_eviction_seqno; + /* Approx. the last timestamp (in jiffies) when the process was + * restored after an eviction + */ + unsigned long last_restore_timestamp; }; #define KFD_PROCESS_TABLE_SIZE 5 /* bits: 32 entries */ @@ -629,7 +656,10 @@ void kfd_process_destroy_wq(void); struct kfd_process *kfd_create_process(struct file *filep); struct kfd_process *kfd_get_process(const struct task_struct *); struct kfd_process *kfd_lookup_process_by_pasid(unsigned int pasid); +struct kfd_process *kfd_lookup_process_by_mm(const struct mm_struct *mm); void kfd_unref_process(struct kfd_process *p); +void kfd_suspend_all_processes(void); +int kfd_resume_all_processes(void); struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev, struct kfd_process *p); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index cf4fa25cc430..18b2b86ad503 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -55,6 +55,9 @@ static struct kfd_process *create_process(const struct task_struct *thread, struct file *filep); static int kfd_process_init_cwsr(struct kfd_process *p, struct file *filep); +static void evict_process_worker(struct work_struct *work); +static void restore_process_worker(struct work_struct *work); + void kfd_process_create_wq(void) { @@ -230,6 +233,9 @@ static void kfd_process_notifier_release(struct mmu_notifier *mn, mutex_unlock(&kfd_processes_mutex); synchronize_srcu(&kfd_processes_srcu); + cancel_delayed_work_sync(&p->eviction_work); + cancel_delayed_work_sync(&p->restore_work); + mutex_lock(&p->mutex); /* Iterate over all process device data structures and if the @@ -351,6 +357,10 @@ static struct kfd_process *create_process(const struct task_struct *thread, if (err != 0) goto err_init_apertures; + INIT_DELAYED_WORK(&process->eviction_work, evict_process_worker); + INIT_DELAYED_WORK(&process->restore_work, restore_process_worker); + process->last_restore_timestamp = get_jiffies_64(); + err = kfd_process_init_cwsr(process, filep); if (err) goto err_init_cwsr; @@ -402,6 +412,7 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev, INIT_LIST_HEAD(&pdd->qpd.priv_queue_list); pdd->qpd.dqm = dev->dqm; pdd->qpd.pqm = &p->pqm; + pdd->qpd.evicted = 0; pdd->process = p; pdd->bound = PDD_UNBOUND; pdd->already_dequeued = false; @@ -490,6 +501,208 @@ struct kfd_process *kfd_lookup_process_by_pasid(unsigned int pasid) return ret_p; } +/* This increments the process->ref counter. */ +struct kfd_process *kfd_lookup_process_by_mm(const struct mm_struct *mm) +{ + struct kfd_process *p; + + int idx = srcu_read_lock(&kfd_processes_srcu); + + p = find_process_by_mm(mm); + if (p) + kref_get(&p->ref); + + srcu_read_unlock(&kfd_processes_srcu, idx); + + return p; +} + +/* process_evict_queues - Evict all user queues of a process + * + * Eviction is reference-counted per process-device. This means multiple + * evictions from different sources can be nested safely. + */ +static int process_evict_queues(struct kfd_process *p) +{ + struct kfd_process_device *pdd; + int r = 0; + unsigned int n_evicted = 0; + + list_for_each_entry(pdd, &p->per_device_data, per_device_list) { + r = pdd->dev->dqm->ops.evict_process_queues(pdd->dev->dqm, + &pdd->qpd); + if (r) { + pr_err("Failed to evict process queues\n"); + goto fail; + } + n_evicted++; + } + + return r; + +fail: + /* To keep state consistent, roll back partial eviction by + * restoring queues + */ + list_for_each_entry(pdd, &p->per_device_data, per_device_list) { + if (n_evicted == 0) + break; + if (pdd->dev->dqm->ops.restore_process_queues(pdd->dev->dqm, + &pdd->qpd)) + pr_err("Failed to restore queues\n"); + + n_evicted--; + } + + return r; +} + +/* process_restore_queues - Restore all user queues of a process */ +static int process_restore_queues(struct kfd_process *p) +{ + struct kfd_process_device *pdd; + int r, ret = 0; + + list_for_each_entry(pdd, &p->per_device_data, per_device_list) { + r = pdd->dev->dqm->ops.restore_process_queues(pdd->dev->dqm, + &pdd->qpd); + if (r) { + pr_err("Failed to restore process queues\n"); + if (!ret) + ret = r; + } + } + + return ret; +} + +static void evict_process_worker(struct work_struct *work) +{ + int ret; + struct kfd_process *p; + struct delayed_work *dwork; + + dwork = to_delayed_work(work); + + /* Process termination destroys this worker thread. So during the + * lifetime of this thread, kfd_process p will be valid + */ + p = container_of(dwork, struct kfd_process, eviction_work); + WARN_ONCE(p->last_eviction_seqno != p->ef->seqno, + "Eviction fence mismatch\n"); + + /* Narrow window of overlap between restore and evict work + * item is possible. Once amdgpu_amdkfd_gpuvm_restore_process_bos + * unreserves KFD BOs, it is possible to evicted again. But + * restore has few more steps of finish. So lets wait for any + * previous restore work to complete + */ + flush_delayed_work(&p->restore_work); + + pr_debug("Started evicting pasid %d\n", p->pasid); + ret = process_evict_queues(p); + if (!ret) { + dma_fence_signal(p->ef); + dma_fence_put(p->ef); + p->ef = NULL; + schedule_delayed_work(&p->restore_work, + msecs_to_jiffies(PROCESS_RESTORE_TIME_MS)); + + pr_debug("Finished evicting pasid %d\n", p->pasid); + } else + pr_err("Failed to evict queues of pasid %d\n", p->pasid); +} + +static void restore_process_worker(struct work_struct *work) +{ + struct delayed_work *dwork; + struct kfd_process *p; + struct kfd_process_device *pdd; + int ret = 0; + + dwork = to_delayed_work(work); + + /* Process termination destroys this worker thread. So during the + * lifetime of this thread, kfd_process p will be valid + */ + p = container_of(dwork, struct kfd_process, restore_work); + + /* Call restore_process_bos on the first KGD device. This function + * takes care of restoring the whole process including other devices. + * Restore can fail if enough memory is not available. If so, + * reschedule again. + */ + pdd = list_first_entry(&p->per_device_data, + struct kfd_process_device, + per_device_list); + + pr_debug("Started restoring pasid %d\n", p->pasid); + + /* Setting last_restore_timestamp before successful restoration. + * Otherwise this would have to be set by KGD (restore_process_bos) + * before KFD BOs are unreserved. If not, the process can be evicted + * again before the timestamp is set. + * If restore fails, the timestamp will be set again in the next + * attempt. This would mean that the minimum GPU quanta would be + * PROCESS_ACTIVE_TIME_MS - (time to execute the following two + * functions) + */ + + p->last_restore_timestamp = get_jiffies_64(); + ret = pdd->dev->kfd2kgd->restore_process_bos(p->kgd_process_info, + &p->ef); + if (ret) { + pr_debug("Failed to restore BOs of pasid %d, retry after %d ms\n", + p->pasid, PROCESS_BACK_OFF_TIME_MS); + ret = schedule_delayed_work(&p->restore_work, + msecs_to_jiffies(PROCESS_BACK_OFF_TIME_MS)); + WARN(!ret, "reschedule restore work failed\n"); + return; + } + + ret = process_restore_queues(p); + if (!ret) + pr_debug("Finished restoring pasid %d\n", p->pasid); + else + pr_err("Failed to restore queues of pasid %d\n", p->pasid); +} + +void kfd_suspend_all_processes(void) +{ + struct kfd_process *p; + unsigned int temp; + int idx = srcu_read_lock(&kfd_processes_srcu); + + hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { + cancel_delayed_work_sync(&p->eviction_work); + cancel_delayed_work_sync(&p->restore_work); + + if (process_evict_queues(p)) + pr_err("Failed to suspend process %d\n", p->pasid); + dma_fence_signal(p->ef); + dma_fence_put(p->ef); + p->ef = NULL; + } + srcu_read_unlock(&kfd_processes_srcu, idx); +} + +int kfd_resume_all_processes(void) +{ + struct kfd_process *p; + unsigned int temp; + int ret = 0, idx = srcu_read_lock(&kfd_processes_srcu); + + hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { + if (!schedule_delayed_work(&p->restore_work, 0)) { + pr_err("Restore process %d failed during resume\n", + p->pasid); + ret = -EFAULT; + } + } + srcu_read_unlock(&kfd_processes_srcu, idx); + return ret; +} + int kfd_reserved_mem_mmap(struct kfd_process *process, struct vm_area_struct *vma) { -- cgit v1.2.3 From 87a81dce53b1ea61acaeefa5191a0376a2d1d721 Mon Sep 17 00:00:00 2001 From: LEROY Christophe Date: Fri, 26 Jan 2018 17:09:59 +0100 Subject: crypto: talitos - fix Kernel Oops on hashing an empty file Performing the hash of an empty file leads to a kernel Oops [ 44.504600] Unable to handle kernel paging request for data at address 0x0000000c [ 44.512819] Faulting instruction address: 0xc02d2be8 [ 44.524088] Oops: Kernel access of bad area, sig: 11 [#1] [ 44.529171] BE PREEMPT CMPC885 [ 44.532232] CPU: 0 PID: 491 Comm: md5sum Not tainted 4.15.0-rc8-00211-g3a968610b6ea #81 [ 44.540814] NIP: c02d2be8 LR: c02d2984 CTR: 00000000 [ 44.545812] REGS: c6813c90 TRAP: 0300 Not tainted (4.15.0-rc8-00211-g3a968610b6ea) [ 44.554223] MSR: 00009032 CR: 48222822 XER: 20000000 [ 44.560855] DAR: 0000000c DSISR: c0000000 [ 44.560855] GPR00: c02d28fc c6813d40 c6828000 c646fa40 00000001 00000001 00000001 00000000 [ 44.560855] GPR08: 0000004c 00000000 c000bfcc 00000000 28222822 100280d4 00000000 10020008 [ 44.560855] GPR16: 00000000 00000020 00000000 00000000 10024008 00000000 c646f9f0 c6179a10 [ 44.560855] GPR24: 00000000 00000001 c62f0018 c6179a10 00000000 c6367a30 c62f0000 c646f9c0 [ 44.598542] NIP [c02d2be8] ahash_process_req+0x448/0x700 [ 44.603751] LR [c02d2984] ahash_process_req+0x1e4/0x700 [ 44.608868] Call Trace: [ 44.611329] [c6813d40] [c02d28fc] ahash_process_req+0x15c/0x700 (unreliable) [ 44.618302] [c6813d90] [c02060c4] hash_recvmsg+0x11c/0x210 [ 44.623716] [c6813db0] [c0331354] ___sys_recvmsg+0x98/0x138 [ 44.629226] [c6813eb0] [c03332c0] __sys_recvmsg+0x40/0x84 [ 44.634562] [c6813f10] [c03336c0] SyS_socketcall+0xb8/0x1d4 [ 44.640073] [c6813f40] [c000d1ac] ret_from_syscall+0x0/0x38 [ 44.645530] Instruction dump: [ 44.648465] 38c00001 7f63db78 4e800421 7c791b78 54690ffe 0f090000 80ff0190 2f870000 [ 44.656122] 40befe50 2f990001 409e0210 813f01bc <8129000c> b39e003a 7d29c214 913e003c This patch fixes that Oops by checking if src is NULL. Fixes: 6a1e8d14156d4 ("crypto: talitos - making mapping helpers more generic") Cc: Signed-off-by: Christophe Leroy Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 9c80e0cb1664..6882fa2f8bad 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1138,6 +1138,10 @@ static int talitos_sg_map(struct device *dev, struct scatterlist *src, struct talitos_private *priv = dev_get_drvdata(dev); bool is_sec1 = has_ftr_sec1(priv); + if (!src) { + to_talitos_ptr(ptr, 0, 0, is_sec1); + return 1; + } if (sg_count == 1) { to_talitos_ptr(ptr, sg_dma_address(src) + offset, len, is_sec1); return sg_count; -- cgit v1.2.3 From 225ece3e7dad4cfc44cca38ce7a3a80f255ea8f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Mon, 5 Feb 2018 11:15:52 +0200 Subject: crypto: caam - fix endless loop when DECO acquire fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case DECO0 cannot be acquired - i.e. run_descriptor_deco0() fails with -ENODEV, caam_probe() enters an endless loop: run_descriptor_deco0 ret -ENODEV -> instantiate_rng -ENODEV, overwritten by -EAGAIN ret -EAGAIN -> caam_probe -EAGAIN results in endless loop It turns out the error path in instantiate_rng() is incorrect, the checks are done in the wrong order. Cc: # 3.13+ Fixes: 1005bccd7a4a6 ("crypto: caam - enable instantiation of all RNG4 state handles") Reported-by: Bryan O'Donoghue Suggested-by: Auer Lukas Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/ctrl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 75d280cb2dc0..e843cf410373 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -228,12 +228,16 @@ static int instantiate_rng(struct device *ctrldev, int state_handle_mask, * without any error (HW optimizations for later * CAAM eras), then try again. */ + if (ret) + break; + rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK; if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) || - !(rdsta_val & (1 << sh_idx))) + !(rdsta_val & (1 << sh_idx))) { ret = -EAGAIN; - if (ret) break; + } + dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx); /* Clear the contents before recreating the descriptor */ memset(desc, 0x00, CAAM_CMD_SZ * 7); -- cgit v1.2.3 From dd78c832ffaf86eb6434e56de4bc3bc31f03f771 Mon Sep 17 00:00:00 2001 From: Artem Savkov Date: Tue, 6 Feb 2018 22:20:21 +0100 Subject: crypto: sun4i_ss_prng - fix return value of sun4i_ss_prng_generate According to crypto/rng.h generate function should return 0 on success and < 0 on error. Fixes: b8ae5c7387ad ("crypto: sun4i-ss - support the Security System PRNG") Signed-off-by: Artem Savkov Acked-by: Corentin Labbe Signed-off-by: Herbert Xu --- drivers/crypto/sunxi-ss/sun4i-ss-prng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-prng.c b/drivers/crypto/sunxi-ss/sun4i-ss-prng.c index 0d01d1624252..5754e0b92fb0 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-prng.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-prng.c @@ -52,5 +52,5 @@ int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src, writel(0, ss->base + SS_CTL); spin_unlock(&ss->slock); - return dlen; + return 0; } -- cgit v1.2.3 From 2e7d1d61ea6c0f1c4da5eb82cafac750d55637a7 Mon Sep 17 00:00:00 2001 From: Artem Savkov Date: Tue, 6 Feb 2018 22:20:22 +0100 Subject: crypto: sun4i_ss_prng - convert lock to _bh in sun4i_ss_prng_generate Lockdep detects a possible deadlock in sun4i_ss_prng_generate() and throws an "inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage" warning. Disabling softirqs to fix this. Fixes: b8ae5c7387ad ("crypto: sun4i-ss - support the Security System PRNG") Signed-off-by: Artem Savkov Signed-off-by: Herbert Xu --- drivers/crypto/sunxi-ss/sun4i-ss-prng.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-prng.c b/drivers/crypto/sunxi-ss/sun4i-ss-prng.c index 5754e0b92fb0..63d636424161 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-prng.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-prng.c @@ -28,7 +28,7 @@ int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src, algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng); ss = algt->ss; - spin_lock(&ss->slock); + spin_lock_bh(&ss->slock); writel(mode, ss->base + SS_CTL); @@ -51,6 +51,6 @@ int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src, } writel(0, ss->base + SS_CTL); - spin_unlock(&ss->slock); + spin_unlock_bh(&ss->slock); return 0; } -- cgit v1.2.3 From dedab7f0d3137441a97fe7cf9b9ca5dbd20ca9a5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 30 Jan 2018 15:11:44 +0000 Subject: ocxl: fix signed comparison with less than zero Currently the comparison of used < 0 is always false because uses is a size_t. Fix this by making used a ssize_t type. Detected by Coccinelle: drivers/misc/ocxl/file.c:320:6-10: WARNING: Unsigned expression compared with zero: used < 0 Fixes: 5ef3166e8a32 ("ocxl: Driver code for 'generic' opencapi devices") Signed-off-by: Colin Ian King Acked-by: Andrew Donnellan Acked-by: Frederic Barrat Signed-off-by: Michael Ellerman --- drivers/misc/ocxl/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c index c90c1a578d2f..1287e4430e6b 100644 --- a/drivers/misc/ocxl/file.c +++ b/drivers/misc/ocxl/file.c @@ -277,7 +277,7 @@ static ssize_t afu_read(struct file *file, char __user *buf, size_t count, struct ocxl_context *ctx = file->private_data; struct ocxl_kernel_event_header header; ssize_t rc; - size_t used = 0; + ssize_t used = 0; DEFINE_WAIT(event_wait); memset(&header, 0, sizeof(header)); -- cgit v1.2.3 From f63248fac563125fd5a2f0bc780ce7a299872cab Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 8 Feb 2018 14:43:05 +0100 Subject: regulator: stm32-vrefbuf: fix check on ready flag stm32_vrefbuf_enable() wrongly checks VRR bit: 0 stands for not ready, 1 for ready. It currently checks the opposite. This makes enable routine to exit immediately without waiting for ready flag. Fixes: 0cdbf481e927 ("regulator: Add support for stm32-vrefbuf") Signed-off-by: Fabrice Gasnier Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/regulator/stm32-vrefbuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c index 72c8b3e1022b..e0a9c445ed67 100644 --- a/drivers/regulator/stm32-vrefbuf.c +++ b/drivers/regulator/stm32-vrefbuf.c @@ -51,7 +51,7 @@ static int stm32_vrefbuf_enable(struct regulator_dev *rdev) * arbitrary timeout. */ ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val, - !(val & STM32_VRR), 650, 10000); + val & STM32_VRR, 650, 10000); if (ret) { dev_err(&rdev->dev, "stm32 vrefbuf timed out!\n"); val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); -- cgit v1.2.3 From ad6a0a52e6de3d1161b7999c7903db906ba4cf79 Mon Sep 17 00:00:00 2001 From: Max Gurtovoy Date: Wed, 31 Jan 2018 18:31:24 +0200 Subject: nvme: rename NVME_CTRL_RECONNECTING state to NVME_CTRL_CONNECTING In pci transport, this state is used to mark the initialization process. This should be also used in other transports as well. Signed-off-by: Max Gurtovoy Reviewed-by: James Smart Signed-off-by: Sagi Grimberg --- drivers/nvme/host/core.c | 10 +++++----- drivers/nvme/host/fabrics.h | 9 +++++---- drivers/nvme/host/fc.c | 14 +++++++------- drivers/nvme/host/nvme.h | 2 +- drivers/nvme/host/pci.c | 8 ++++---- drivers/nvme/host/rdma.c | 6 +++--- 6 files changed, 25 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index f431c32774f3..1033de4136e0 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -265,7 +265,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, switch (new_state) { case NVME_CTRL_ADMIN_ONLY: switch (old_state) { - case NVME_CTRL_RECONNECTING: + case NVME_CTRL_CONNECTING: changed = true; /* FALLTHRU */ default: @@ -276,7 +276,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, switch (old_state) { case NVME_CTRL_NEW: case NVME_CTRL_RESETTING: - case NVME_CTRL_RECONNECTING: + case NVME_CTRL_CONNECTING: changed = true; /* FALLTHRU */ default: @@ -294,7 +294,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, break; } break; - case NVME_CTRL_RECONNECTING: + case NVME_CTRL_CONNECTING: switch (old_state) { case NVME_CTRL_LIVE: case NVME_CTRL_RESETTING: @@ -309,7 +309,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, case NVME_CTRL_LIVE: case NVME_CTRL_ADMIN_ONLY: case NVME_CTRL_RESETTING: - case NVME_CTRL_RECONNECTING: + case NVME_CTRL_CONNECTING: changed = true; /* FALLTHRU */ default: @@ -2687,7 +2687,7 @@ static ssize_t nvme_sysfs_show_state(struct device *dev, [NVME_CTRL_LIVE] = "live", [NVME_CTRL_ADMIN_ONLY] = "only-admin", [NVME_CTRL_RESETTING] = "resetting", - [NVME_CTRL_RECONNECTING]= "reconnecting", + [NVME_CTRL_CONNECTING] = "connecting", [NVME_CTRL_DELETING] = "deleting", [NVME_CTRL_DEAD] = "dead", }; diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h index 25b19f722f5b..a3145d90c1d2 100644 --- a/drivers/nvme/host/fabrics.h +++ b/drivers/nvme/host/fabrics.h @@ -171,13 +171,14 @@ static inline blk_status_t nvmf_check_init_req(struct nvme_ctrl *ctrl, cmd->common.opcode != nvme_fabrics_command || cmd->fabrics.fctype != nvme_fabrics_type_connect) { /* - * Reconnecting state means transport disruption, which can take - * a long time and even might fail permanently, fail fast to - * give upper layers a chance to failover. + * Connecting state means transport disruption or initial + * establishment, which can take a long time and even might + * fail permanently, fail fast to give upper layers a chance + * to failover. * Deleting state means that the ctrl will never accept commands * again, fail it permanently. */ - if (ctrl->state == NVME_CTRL_RECONNECTING || + if (ctrl->state == NVME_CTRL_CONNECTING || ctrl->state == NVME_CTRL_DELETING) { nvme_req(rq)->status = NVME_SC_ABORT_REQ; return BLK_STS_IOERR; diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index b856d7c919d2..e2df22d56b2a 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -532,7 +532,7 @@ nvme_fc_resume_controller(struct nvme_fc_ctrl *ctrl) { switch (ctrl->ctrl.state) { case NVME_CTRL_NEW: - case NVME_CTRL_RECONNECTING: + case NVME_CTRL_CONNECTING: /* * As all reconnects were suppressed, schedule a * connect. @@ -777,7 +777,7 @@ nvme_fc_ctrl_connectivity_loss(struct nvme_fc_ctrl *ctrl) } break; - case NVME_CTRL_RECONNECTING: + case NVME_CTRL_CONNECTING: /* * The association has already been terminated and the * controller is attempting reconnects. No need to do anything @@ -1722,7 +1722,7 @@ done: if (status && (blk_queue_dying(rq->q) || ctrl->ctrl.state == NVME_CTRL_NEW || - ctrl->ctrl.state == NVME_CTRL_RECONNECTING)) + ctrl->ctrl.state == NVME_CTRL_CONNECTING)) status |= cpu_to_le16(NVME_SC_DNR << 1); if (__nvme_fc_fcpop_chk_teardowns(ctrl, op)) @@ -2943,7 +2943,7 @@ nvme_fc_reconnect_or_delete(struct nvme_fc_ctrl *ctrl, int status) unsigned long recon_delay = ctrl->ctrl.opts->reconnect_delay * HZ; bool recon = true; - if (ctrl->ctrl.state != NVME_CTRL_RECONNECTING) + if (ctrl->ctrl.state != NVME_CTRL_CONNECTING) return; if (portptr->port_state == FC_OBJSTATE_ONLINE) @@ -2991,10 +2991,10 @@ nvme_fc_reset_ctrl_work(struct work_struct *work) /* will block will waiting for io to terminate */ nvme_fc_delete_association(ctrl); - if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) { + if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) { dev_err(ctrl->ctrl.device, "NVME-FC{%d}: error_recovery: Couldn't change state " - "to RECONNECTING\n", ctrl->cnum); + "to CONNECTING\n", ctrl->cnum); return; } @@ -3195,7 +3195,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, * transport errors (frame drop, LS failure) inherently must kill * the association. The transport is coded so that any command used * to create the association (prior to a LIVE state transition - * while NEW or RECONNECTING) will fail if it completes in error or + * while NEW or CONNECTING) will fail if it completes in error or * times out. * * As such: as the connect request was mostly likely due to a diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 8e4550fa08f8..27e31c00b306 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -123,7 +123,7 @@ enum nvme_ctrl_state { NVME_CTRL_LIVE, NVME_CTRL_ADMIN_ONLY, /* Only admin queue live */ NVME_CTRL_RESETTING, - NVME_CTRL_RECONNECTING, + NVME_CTRL_CONNECTING, NVME_CTRL_DELETING, NVME_CTRL_DEAD, }; diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 6fe7af00a1f4..ab9c19525fa8 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1141,7 +1141,7 @@ static bool nvme_should_reset(struct nvme_dev *dev, u32 csts) /* If there is a reset/reinit ongoing, we shouldn't reset again. */ switch (dev->ctrl.state) { case NVME_CTRL_RESETTING: - case NVME_CTRL_RECONNECTING: + case NVME_CTRL_CONNECTING: return false; default: break; @@ -2288,12 +2288,12 @@ static void nvme_reset_work(struct work_struct *work) nvme_dev_disable(dev, false); /* - * Introduce RECONNECTING state from nvme-fc/rdma transports to mark the + * Introduce CONNECTING state from nvme-fc/rdma transports to mark the * initializing procedure here. */ - if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RECONNECTING)) { + if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_CONNECTING)) { dev_warn(dev->ctrl.device, - "failed to mark controller RECONNECTING\n"); + "failed to mark controller CONNECTING\n"); goto out; } diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 2bc059f7d73c..050eaa24cc7d 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -887,7 +887,7 @@ free_ctrl: static void nvme_rdma_reconnect_or_remove(struct nvme_rdma_ctrl *ctrl) { /* If we are resetting/deleting then do nothing */ - if (ctrl->ctrl.state != NVME_CTRL_RECONNECTING) { + if (ctrl->ctrl.state != NVME_CTRL_CONNECTING) { WARN_ON_ONCE(ctrl->ctrl.state == NVME_CTRL_NEW || ctrl->ctrl.state == NVME_CTRL_LIVE); return; @@ -973,7 +973,7 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work) blk_mq_unquiesce_queue(ctrl->ctrl.admin_q); nvme_start_queues(&ctrl->ctrl); - if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) { + if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) { /* state change failure should never happen */ WARN_ON_ONCE(1); return; @@ -1756,7 +1756,7 @@ static void nvme_rdma_reset_ctrl_work(struct work_struct *work) nvme_stop_ctrl(&ctrl->ctrl); nvme_rdma_shutdown_ctrl(ctrl, false); - if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) { + if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) { /* state change failure should never happen */ WARN_ON_ONCE(1); return; -- cgit v1.2.3 From b754a32c66772e6510acd92237aadd4cf227ae39 Mon Sep 17 00:00:00 2001 From: Max Gurtovoy Date: Wed, 31 Jan 2018 18:31:25 +0200 Subject: nvme-rdma: use NVME_CTRL_CONNECTING state to mark init process In order to avoid concurrent error recovery during initialization process (allowed by the NVME_CTRL_NEW --> NVME_CTRL_RESETTING transition) we must mark the ctrl as CONNECTING before initial connection establisment. Signed-off-by: Max Gurtovoy Reviewed-by: James Smart Signed-off-by: Sagi Grimberg --- drivers/nvme/host/core.c | 1 + drivers/nvme/host/rdma.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 1033de4136e0..86dca2919e19 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -296,6 +296,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, break; case NVME_CTRL_CONNECTING: switch (old_state) { + case NVME_CTRL_NEW: case NVME_CTRL_LIVE: case NVME_CTRL_RESETTING: changed = true; diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 050eaa24cc7d..5e2cc4f0d207 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -1942,6 +1942,9 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev, if (!ctrl->queues) goto out_uninit_ctrl; + changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING); + WARN_ON_ONCE(!changed); + ret = nvme_rdma_configure_admin_queue(ctrl, true); if (ret) goto out_kfree_queues; -- cgit v1.2.3 From 3096a739d2ccbfd6a626e388228a16558f76d79d Mon Sep 17 00:00:00 2001 From: Max Gurtovoy Date: Wed, 31 Jan 2018 18:31:26 +0200 Subject: nvme: delete NVME_CTRL_LIVE --> NVME_CTRL_CONNECTING transition There is no logical reason to move from live state to connecting state. In case of initial connection establishment, the transition should be NVME_CTRL_NEW --> NVME_CTRL_CONNECTING --> NVME_CTRL_LIVE. In case of error recovery or reset, the transition should be NVME_CTRL_LIVE --> NVME_CTRL_RESETTING --> NVME_CTRL_CONNECTING --> NVME_CTRL_LIVE. Signed-off-by: Max Gurtovoy Reviewed-by: James Smart Signed-off-by: Sagi Grimberg --- drivers/nvme/host/core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 86dca2919e19..1f9278364196 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -297,7 +297,6 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, case NVME_CTRL_CONNECTING: switch (old_state) { case NVME_CTRL_NEW: - case NVME_CTRL_LIVE: case NVME_CTRL_RESETTING: changed = true; /* FALLTHRU */ -- cgit v1.2.3 From 8cb6af7b3a6d47f95ecb461a3f8d39cf6a64e4ae Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Wed, 31 Jan 2018 17:01:58 -0700 Subject: nvme: Fix discard buffer overrun This patch checks the discard range array bounds before setting it in case the driver gets a badly formed request. Signed-off-by: Keith Busch Reviewed-by: Jens Axboe Signed-off-by: Sagi Grimberg --- drivers/nvme/host/core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 1f9278364196..2fd8688cfa47 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -518,9 +518,11 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req, u64 slba = nvme_block_nr(ns, bio->bi_iter.bi_sector); u32 nlb = bio->bi_iter.bi_size >> ns->lba_shift; - range[n].cattr = cpu_to_le32(0); - range[n].nlb = cpu_to_le32(nlb); - range[n].slba = cpu_to_le64(slba); + if (n < segments) { + range[n].cattr = cpu_to_le32(0); + range[n].nlb = cpu_to_le32(nlb); + range[n].slba = cpu_to_le64(slba); + } n++; } -- cgit v1.2.3 From 6e59de2048eb375a9bfcd39461ef841cd2a78962 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Thu, 8 Feb 2018 17:46:01 +0800 Subject: drm/amdgpu: add new device to use atpx quirk The affected system (0x0813) is pretty similar to another one (0x0812), it also needs to use ATPX power control. Signed-off-by: Kai-Heng Feng Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index e2c3c5ec42d1..c53095b3b0fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -568,6 +568,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = { /* HG _PR3 doesn't seem to work on this A+A weston board */ { 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 }, { 0, 0, 0, 0, 0 }, }; -- cgit v1.2.3 From ea4f7bd2aca9f68470e9aac0fc9432fd180b1fe7 Mon Sep 17 00:00:00 2001 From: Zhang Bo Date: Mon, 5 Feb 2018 14:56:21 -0800 Subject: Input: matrix_keypad - fix race when disabling interrupts If matrix_keypad_stop() is executing and the keypad interrupt is triggered, disable_row_irqs() may be called by both matrix_keypad_interrupt() and matrix_keypad_stop() at the same time, causing interrupts to be disabled twice and the keypad being "stuck" after resuming. Take lock when setting keypad->stopped to ensure that ISR will not race with matrix_keypad_stop() disabling interrupts. Signed-off-by: Zhang Bo Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/matrix_keypad.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 1f316d66e6f7..41614c185918 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -218,8 +218,10 @@ static void matrix_keypad_stop(struct input_dev *dev) { struct matrix_keypad *keypad = input_get_drvdata(dev); + spin_lock_irq(&keypad->lock); keypad->stopped = true; - mb(); + spin_unlock_irq(&keypad->lock); + flush_work(&keypad->work.work); /* * matrix_keypad_scan() will leave IRQs enabled; -- cgit v1.2.3 From 3efd6e8ebe19f0774c82de582849539b60cc4d97 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 6 Feb 2018 06:48:29 -0800 Subject: nvme_fc: correct abort race condition on resets During reset handling, there is live io completing while the reset is taking place. The reset path attempts to abort all outstanding io, counting the number of ios that were reset. It then waits for those ios to be reclaimed from the lldd before continuing. The transport's logic on io state and flag setting was poor, allowing ios to complete simultaneous to the abort request. The completed ios were counted, but as the completion had already occurred, the completion never reduced the count. As the count never zeros, the reset/delete never completes. Tighten it up by unconditionally changing the op state to completed when the io done handler is called. The reset/abort path now changes the op state to aborted, but the abort only continues if the op state was live priviously. If complete, the abort is backed out. Thus proper counting of io aborts and their completions is working again. Also removed the TERMIO state on the op as it's redundant with the op's aborted state. Reviewed-by: Johannes Thumshirn Signed-off-by: James Smart Signed-off-by: Sagi Grimberg --- drivers/nvme/host/fc.c | 98 ++++++++++++++------------------------------------ 1 file changed, 26 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index e2df22d56b2a..4673882ce152 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -1512,13 +1512,19 @@ nvme_fc_exit_request(struct blk_mq_tag_set *set, struct request *rq, static int __nvme_fc_abort_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_fcp_op *op) { - int state; + unsigned long flags; + int opstate; + + spin_lock_irqsave(&ctrl->lock, flags); + opstate = atomic_xchg(&op->state, FCPOP_STATE_ABORTED); + if (opstate != FCPOP_STATE_ACTIVE) + atomic_set(&op->state, opstate); + else if (ctrl->flags & FCCTRL_TERMIO) + ctrl->iocnt++; + spin_unlock_irqrestore(&ctrl->lock, flags); - state = atomic_xchg(&op->state, FCPOP_STATE_ABORTED); - if (state != FCPOP_STATE_ACTIVE) { - atomic_set(&op->state, state); + if (opstate != FCPOP_STATE_ACTIVE) return -ECANCELED; - } ctrl->lport->ops->fcp_abort(&ctrl->lport->localport, &ctrl->rport->remoteport, @@ -1532,52 +1538,23 @@ static void nvme_fc_abort_aen_ops(struct nvme_fc_ctrl *ctrl) { struct nvme_fc_fcp_op *aen_op = ctrl->aen_ops; - unsigned long flags; - int i, ret; - - for (i = 0; i < NVME_NR_AEN_COMMANDS; i++, aen_op++) { - if (atomic_read(&aen_op->state) != FCPOP_STATE_ACTIVE) - continue; - - spin_lock_irqsave(&ctrl->lock, flags); - if (ctrl->flags & FCCTRL_TERMIO) { - ctrl->iocnt++; - aen_op->flags |= FCOP_FLAGS_TERMIO; - } - spin_unlock_irqrestore(&ctrl->lock, flags); - - ret = __nvme_fc_abort_op(ctrl, aen_op); - if (ret) { - /* - * if __nvme_fc_abort_op failed the io wasn't - * active. Thus this call path is running in - * parallel to the io complete. Treat as non-error. - */ + int i; - /* back out the flags/counters */ - spin_lock_irqsave(&ctrl->lock, flags); - if (ctrl->flags & FCCTRL_TERMIO) - ctrl->iocnt--; - aen_op->flags &= ~FCOP_FLAGS_TERMIO; - spin_unlock_irqrestore(&ctrl->lock, flags); - return; - } - } + for (i = 0; i < NVME_NR_AEN_COMMANDS; i++, aen_op++) + __nvme_fc_abort_op(ctrl, aen_op); } static inline int __nvme_fc_fcpop_chk_teardowns(struct nvme_fc_ctrl *ctrl, - struct nvme_fc_fcp_op *op) + struct nvme_fc_fcp_op *op, int opstate) { unsigned long flags; bool complete_rq = false; spin_lock_irqsave(&ctrl->lock, flags); - if (unlikely(op->flags & FCOP_FLAGS_TERMIO)) { - if (ctrl->flags & FCCTRL_TERMIO) { - if (!--ctrl->iocnt) - wake_up(&ctrl->ioabort_wait); - } + if (opstate == FCPOP_STATE_ABORTED && ctrl->flags & FCCTRL_TERMIO) { + if (!--ctrl->iocnt) + wake_up(&ctrl->ioabort_wait); } if (op->flags & FCOP_FLAGS_RELEASED) complete_rq = true; @@ -1601,6 +1578,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) __le16 status = cpu_to_le16(NVME_SC_SUCCESS << 1); union nvme_result result; bool terminate_assoc = true; + int opstate; /* * WARNING: @@ -1639,11 +1617,12 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) * association to be terminated. */ + opstate = atomic_xchg(&op->state, FCPOP_STATE_COMPLETE); + fc_dma_sync_single_for_cpu(ctrl->lport->dev, op->fcp_req.rspdma, sizeof(op->rsp_iu), DMA_FROM_DEVICE); - if (atomic_read(&op->state) == FCPOP_STATE_ABORTED || - op->flags & FCOP_FLAGS_TERMIO) + if (opstate == FCPOP_STATE_ABORTED) status = cpu_to_le16(NVME_SC_ABORT_REQ << 1); else if (freq->status) status = cpu_to_le16(NVME_SC_INTERNAL << 1); @@ -1708,7 +1687,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) done: if (op->flags & FCOP_FLAGS_AEN) { nvme_complete_async_event(&queue->ctrl->ctrl, status, &result); - __nvme_fc_fcpop_chk_teardowns(ctrl, op); + __nvme_fc_fcpop_chk_teardowns(ctrl, op, opstate); atomic_set(&op->state, FCPOP_STATE_IDLE); op->flags = FCOP_FLAGS_AEN; /* clear other flags */ nvme_fc_ctrl_put(ctrl); @@ -1725,7 +1704,7 @@ done: ctrl->ctrl.state == NVME_CTRL_CONNECTING)) status |= cpu_to_le16(NVME_SC_DNR << 1); - if (__nvme_fc_fcpop_chk_teardowns(ctrl, op)) + if (__nvme_fc_fcpop_chk_teardowns(ctrl, op, opstate)) __nvme_fc_final_op_cleanup(rq); else nvme_end_request(rq, status, result); @@ -2421,8 +2400,7 @@ __nvme_fc_final_op_cleanup(struct request *rq) struct nvme_fc_ctrl *ctrl = op->ctrl; atomic_set(&op->state, FCPOP_STATE_IDLE); - op->flags &= ~(FCOP_FLAGS_TERMIO | FCOP_FLAGS_RELEASED | - FCOP_FLAGS_COMPLETE); + op->flags &= ~(FCOP_FLAGS_RELEASED | FCOP_FLAGS_COMPLETE); nvme_fc_unmap_data(ctrl, rq, op); nvme_complete_rq(rq); @@ -2476,35 +2454,11 @@ nvme_fc_terminate_exchange(struct request *req, void *data, bool reserved) struct nvme_ctrl *nctrl = data; struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl); struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(req); - unsigned long flags; - int status; if (!blk_mq_request_started(req)) return; - spin_lock_irqsave(&ctrl->lock, flags); - if (ctrl->flags & FCCTRL_TERMIO) { - ctrl->iocnt++; - op->flags |= FCOP_FLAGS_TERMIO; - } - spin_unlock_irqrestore(&ctrl->lock, flags); - - status = __nvme_fc_abort_op(ctrl, op); - if (status) { - /* - * if __nvme_fc_abort_op failed the io wasn't - * active. Thus this call path is running in - * parallel to the io complete. Treat as non-error. - */ - - /* back out the flags/counters */ - spin_lock_irqsave(&ctrl->lock, flags); - if (ctrl->flags & FCCTRL_TERMIO) - ctrl->iocnt--; - op->flags &= ~FCOP_FLAGS_TERMIO; - spin_unlock_irqrestore(&ctrl->lock, flags); - return; - } + __nvme_fc_abort_op(ctrl, op); } -- cgit v1.2.3 From c3aedd225f8bcc3b3e61df074bc045b80542b38a Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 6 Feb 2018 06:48:30 -0800 Subject: nvme_fc: cleanup io completion There was some old cold that dealt with complete_rq being called prior to the lldd returning the io completion. This is garbage code. The complete_rq routine was being called after eh_timeouts were called and it was due to eh_timeouts not being handled properly. The timeouts were fixed in prior patches so that in general, a timeout will initiate an abort and the reset timer restarted as the abort operation will take care of completing things. Given the reset timer restarted, the erroneous complete_rq calls were eliminated. So remove the work that was synchronizing complete_rq with io completion. Reviewed-by: Johannes Thumshirn Signed-off-by: James Smart Signed-off-by: Sagi Grimberg --- drivers/nvme/host/fc.c | 63 ++++++++++---------------------------------------- 1 file changed, 12 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 4673882ce152..7f51f8414b97 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -55,9 +55,7 @@ struct nvme_fc_queue { enum nvme_fcop_flags { FCOP_FLAGS_TERMIO = (1 << 0), - FCOP_FLAGS_RELEASED = (1 << 1), - FCOP_FLAGS_COMPLETE = (1 << 2), - FCOP_FLAGS_AEN = (1 << 3), + FCOP_FLAGS_AEN = (1 << 1), }; struct nvmefc_ls_req_op { @@ -1470,7 +1468,6 @@ nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl) /* *********************** NVME Ctrl Routines **************************** */ -static void __nvme_fc_final_op_cleanup(struct request *rq); static void nvme_fc_error_recovery(struct nvme_fc_ctrl *ctrl, char *errmsg); static int @@ -1544,25 +1541,20 @@ nvme_fc_abort_aen_ops(struct nvme_fc_ctrl *ctrl) __nvme_fc_abort_op(ctrl, aen_op); } -static inline int +static inline void __nvme_fc_fcpop_chk_teardowns(struct nvme_fc_ctrl *ctrl, struct nvme_fc_fcp_op *op, int opstate) { unsigned long flags; - bool complete_rq = false; - spin_lock_irqsave(&ctrl->lock, flags); - if (opstate == FCPOP_STATE_ABORTED && ctrl->flags & FCCTRL_TERMIO) { - if (!--ctrl->iocnt) - wake_up(&ctrl->ioabort_wait); + if (opstate == FCPOP_STATE_ABORTED) { + spin_lock_irqsave(&ctrl->lock, flags); + if (ctrl->flags & FCCTRL_TERMIO) { + if (!--ctrl->iocnt) + wake_up(&ctrl->ioabort_wait); + } + spin_unlock_irqrestore(&ctrl->lock, flags); } - if (op->flags & FCOP_FLAGS_RELEASED) - complete_rq = true; - else - op->flags |= FCOP_FLAGS_COMPLETE; - spin_unlock_irqrestore(&ctrl->lock, flags); - - return complete_rq; } static void @@ -1704,10 +1696,8 @@ done: ctrl->ctrl.state == NVME_CTRL_CONNECTING)) status |= cpu_to_le16(NVME_SC_DNR << 1); - if (__nvme_fc_fcpop_chk_teardowns(ctrl, op, opstate)) - __nvme_fc_final_op_cleanup(rq); - else - nvme_end_request(rq, status, result); + __nvme_fc_fcpop_chk_teardowns(ctrl, op, opstate); + nvme_end_request(rq, status, result); check_error: if (terminate_assoc) @@ -2394,45 +2384,16 @@ nvme_fc_submit_async_event(struct nvme_ctrl *arg) } static void -__nvme_fc_final_op_cleanup(struct request *rq) +nvme_fc_complete_rq(struct request *rq) { struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq); struct nvme_fc_ctrl *ctrl = op->ctrl; atomic_set(&op->state, FCPOP_STATE_IDLE); - op->flags &= ~(FCOP_FLAGS_RELEASED | FCOP_FLAGS_COMPLETE); nvme_fc_unmap_data(ctrl, rq, op); nvme_complete_rq(rq); nvme_fc_ctrl_put(ctrl); - -} - -static void -nvme_fc_complete_rq(struct request *rq) -{ - struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq); - struct nvme_fc_ctrl *ctrl = op->ctrl; - unsigned long flags; - bool completed = false; - - /* - * the core layer, on controller resets after calling - * nvme_shutdown_ctrl(), calls complete_rq without our - * calling blk_mq_complete_request(), thus there may still - * be live i/o outstanding with the LLDD. Means transport has - * to track complete calls vs fcpio_done calls to know what - * path to take on completes and dones. - */ - spin_lock_irqsave(&ctrl->lock, flags); - if (op->flags & FCOP_FLAGS_COMPLETE) - completed = true; - else - op->flags |= FCOP_FLAGS_RELEASED; - spin_unlock_irqrestore(&ctrl->lock, flags); - - if (completed) - __nvme_fc_final_op_cleanup(rq); } /* -- cgit v1.2.3 From 7ac8ff95f48cbfa609a060fd6a1e361dd62feeb3 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 11 Feb 2018 18:10:28 -0500 Subject: mvpp2: fix multicast address filter IPv6 doesn't work on the MacchiatoBIN board. It is caused by broken multicast address filter in the mvpp2 driver. The driver loads doesn't load any multicast entries if "allmulti" is not set. This condition should be reversed. The condition !netdev_mc_empty(dev) is useless (because netdev_for_each_mc_addr is nop if the list is empty). This patch also fixes a possible overflow of the multicast list - if mvpp2_prs_mac_da_accept fails, we set the allmulti flag and retry. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index a1d7b88cf083..5a1668cdb461 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -7137,6 +7137,7 @@ static void mvpp2_set_rx_mode(struct net_device *dev) int id = port->id; bool allmulti = dev->flags & IFF_ALLMULTI; +retry: mvpp2_prs_mac_promisc_set(priv, id, dev->flags & IFF_PROMISC); mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_ALL, allmulti); mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_IP6, allmulti); @@ -7144,9 +7145,13 @@ static void mvpp2_set_rx_mode(struct net_device *dev) /* Remove all port->id's mcast enries */ mvpp2_prs_mcast_del_all(priv, id); - if (allmulti && !netdev_mc_empty(dev)) { - netdev_for_each_mc_addr(ha, dev) - mvpp2_prs_mac_da_accept(priv, id, ha->addr, true); + if (!allmulti) { + netdev_for_each_mc_addr(ha, dev) { + if (mvpp2_prs_mac_da_accept(priv, id, ha->addr, true)) { + allmulti = true; + goto retry; + } + } } } -- cgit v1.2.3 From bff52352e0ccc2481f2b6b0d612ff8ff56c50f3a Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 18 Dec 2017 16:14:36 +0100 Subject: usb: dwc3: of-simple: fix oops by unbalanced clk disable call dwc3_of_simple_dev_pm_ops has never been used since commit a0d8c4cfdf31 ("usb: dwc3: of-simple: set dev_pm_ops"), but this commit has brought and oops when unbind the device due this sequence: dwc3_of_simple_remove -> clk_disable ... -> pm_runtime_put_sync -> dwc3_of_simple_runtime_suspend -> clk_disable (again) This double call to clk_core_disable causes a kernel oops like this: WARNING: CPU: 1 PID: 4022 at drivers/clk/clk.c:656 clk_core_disable+0x78/0x80 CPU: 1 PID: 4022 Comm: bash Not tainted 4.15.0-rc4+ #44 Hardware name: Google Kevin (DT) pstate: 80000085 (Nzcv daIf -PAN -UAO) pc : clk_core_disable+0x78/0x80 lr : clk_core_disable_lock+0x20/0x38 sp : ffff00000bbf3a90 ... Call trace: clk_core_disable+0x78/0x80 clk_disable+0x1c/0x30 dwc3_of_simple_runtime_suspend+0x30/0x50 pm_generic_runtime_suspend+0x28/0x40 This patch fixes the unbalanced clk disable call by setting the num_clocks variable to zero once the clocks were disabled. Fixes: a0d8c4cfdf31 ("usb: dwc3: of-simple: set dev_pm_ops") Signed-off-by: Enric Balletbo i Serra Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-of-simple.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index 7ae0eefc7cc7..e54c3622eb28 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -143,6 +143,7 @@ static int dwc3_of_simple_remove(struct platform_device *pdev) clk_disable_unprepare(simple->clks[i]); clk_put(simple->clks[i]); } + simple->num_clocks = 0; reset_control_assert(simple->resets); reset_control_put(simple->resets); -- cgit v1.2.3 From e3190868e5f52fb26544f16463593d54ce46ce61 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 12 Jan 2018 20:00:56 +0900 Subject: usb: gadget: udc: renesas_usb3: fix oops in renesas_usb3_remove() This patch fixes an issue that the renesas_usb3_remove() causes NULL pointer dereference because the usb3_to_dev() macro will use the gadget instance and it will be deleted before. Fixes: cf06df3fae28 ("usb: gadget: udc: renesas_usb3: move pm_runtime_{en,dis}able()") Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/renesas_usb3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 6e87af248367..409cde4e6a51 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2410,7 +2410,7 @@ static int renesas_usb3_remove(struct platform_device *pdev) __renesas_usb3_ep_free_request(usb3->ep0_req); if (usb3->phy) phy_put(usb3->phy); - pm_runtime_disable(usb3_to_dev(usb3)); + pm_runtime_disable(&pdev->dev); return 0; } -- cgit v1.2.3 From 6180026341e852a250e1f97ebdcf71684a3c81b9 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Fri, 12 Jan 2018 18:18:05 -0800 Subject: usb: dwc3: gadget: Set maxpacket size for ep0 IN There are 2 control endpoint structures for DWC3. However, the driver only updates the OUT direction control endpoint structure during ConnectDone event. DWC3 driver needs to update the endpoint max packet size for control IN endpoint as well. If the max packet size is not properly set, then the driver will incorrectly calculate the data transfer size and fail to send ZLP for HS/FS 3-stage control read transfer. The fix is simply to update the max packet size for the ep0 IN direction during ConnectDone event. Cc: stable@vger.kernel.org Fixes: 72246da40f37 ("usb: Introduce DesignWare USB3 DRD Driver") Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 616ef49ccb49..2bda4eb1e9ac 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2745,6 +2745,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) break; } + dwc->eps[1]->endpoint.maxpacket = dwc->gadget.ep0->maxpacket; + /* Enable USB2 LPM Capability */ if ((dwc->revision > DWC3_REVISION_194A) && -- cgit v1.2.3 From f035d139ffece7b6a7b8bfb17bd0ba715ee57a04 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Fri, 12 Jan 2018 18:18:27 -0800 Subject: usb: dwc3: ep0: Reset TRB counter for ep0 IN DWC3 tracks TRB counter for each ep0 direction separately. In control read transfer completion handler, the driver needs to reset the TRB enqueue counter for ep0 IN direction. Currently the driver only resets the TRB counter for control OUT endpoint. Check for the data direction and properly reset the TRB counter from correct control endpoint. Cc: stable@vger.kernel.org Fixes: c2da2ff00606 ("usb: dwc3: ep0: don't use ep0in for transfers") Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 9c2e4a17918e..18be31d5743a 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -854,7 +854,12 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, trb++; trb->ctrl &= ~DWC3_TRB_CTRL_HWO; trace_dwc3_complete_trb(ep0, trb); - ep0->trb_enqueue = 0; + + if (r->direction) + dwc->eps[1]->trb_enqueue = 0; + else + dwc->eps[0]->trb_enqueue = 0; + dwc->ep0_bounced = false; } -- cgit v1.2.3 From 8813a59ed892305b5ac1b5b901740b1ad4b5fefa Mon Sep 17 00:00:00 2001 From: John Keeping Date: Fri, 12 Jan 2018 18:43:32 +0000 Subject: usb: gadget: f_uac2: fix bFirstInterface in composite gadget If there are multiple functions associated with a configuration, then the UAC2 interfaces may not start at zero. Set the correct first interface number in the association descriptor so that the audio interfaces are enumerated correctly in this case. Reviewed-by: Krzysztof Opasiak Signed-off-by: John Keeping Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uac2.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 11fe788b4308..d2dc1f00180b 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -524,6 +524,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); return ret; } + iad_desc.bFirstInterface = ret; + std_ac_if_desc.bInterfaceNumber = ret; uac2->ac_intf = ret; uac2->ac_alt = 0; -- cgit v1.2.3 From 00b42170c86f90ac9dea83a7dfcd3f0c38098fe2 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 17 Jan 2018 13:22:49 -0800 Subject: usb: dwc3: Undo PHY init if soft reset fails In this function, we init the USB2 and USB3 PHYs, but if soft reset times out, we don't unwind this. Noticed by inspection. Signed-off-by: Brian Norris Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ade2ab00d37a..bc2467f0e6a7 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -234,6 +234,9 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) udelay(1); } while (--retries); + phy_exit(dwc->usb3_generic_phy); + phy_exit(dwc->usb2_generic_phy); + return -ETIMEDOUT; } -- cgit v1.2.3 From c4a5153e87fdf6805f63ff57556260e2554155a5 Mon Sep 17 00:00:00 2001 From: Manu Gautam Date: Thu, 18 Jan 2018 16:54:30 +0530 Subject: usb: dwc3: core: Power-off core/PHYs on system_suspend in host mode Commit 689bf72c6e0d ("usb: dwc3: Don't reinitialize core during host bus-suspend/resume") updated suspend/resume routines to not power_off and reinit PHYs/core for host mode. It broke platforms that rely on DWC3 core to power_off PHYs to enter low power state on system suspend. Perform dwc3_core_exit/init only during host mode system_suspend/ resume to addresses power regression from above mentioned patch and also allow USB session to stay connected across runtime_suspend/resume in host mode. While at it also replace existing checks for HOST only dr_mode with current_dr_role to have similar core driver behavior for both Host-only and DRD+Host configurations. Fixes: 689bf72c6e0d ("usb: dwc3: Don't reinitialize core during host bus-suspend/resume") Reviewed-by: Roger Quadros Signed-off-by: Manu Gautam Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index bc2467f0e6a7..59511f2cd3ac 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -100,6 +100,8 @@ static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); reg |= DWC3_GCTL_PRTCAPDIR(mode); dwc3_writel(dwc->regs, DWC3_GCTL, reg); + + dwc->current_dr_role = mode; } static void __dwc3_set_mode(struct work_struct *work) @@ -133,8 +135,6 @@ static void __dwc3_set_mode(struct work_struct *work) dwc3_set_prtcap(dwc, dwc->desired_dr_role); - dwc->current_dr_role = dwc->desired_dr_role; - spin_unlock_irqrestore(&dwc->lock, flags); switch (dwc->desired_dr_role) { @@ -219,7 +219,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) * XHCI driver will reset the host block. If dwc3 was configured for * host-only mode, then we can return early. */ - if (dwc->dr_mode == USB_DR_MODE_HOST) + if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) return 0; reg = dwc3_readl(dwc->regs, DWC3_DCTL); @@ -919,7 +919,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: - dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE; dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); if (dwc->usb2_phy) @@ -935,7 +934,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) } break; case USB_DR_MODE_HOST: - dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST; dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); if (dwc->usb2_phy) @@ -1287,7 +1285,7 @@ static int dwc3_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int dwc3_suspend_common(struct dwc3 *dwc) +static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) { unsigned long flags; @@ -1299,6 +1297,10 @@ static int dwc3_suspend_common(struct dwc3 *dwc) dwc3_core_exit(dwc); break; case DWC3_GCTL_PRTCAP_HOST: + /* do nothing during host runtime_suspend */ + if (!PMSG_IS_AUTO(msg)) + dwc3_core_exit(dwc); + break; default: /* do nothing */ break; @@ -1307,7 +1309,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc) return 0; } -static int dwc3_resume_common(struct dwc3 *dwc) +static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) { unsigned long flags; int ret; @@ -1323,6 +1325,13 @@ static int dwc3_resume_common(struct dwc3 *dwc) spin_unlock_irqrestore(&dwc->lock, flags); break; case DWC3_GCTL_PRTCAP_HOST: + /* nothing to do on host runtime_resume */ + if (!PMSG_IS_AUTO(msg)) { + ret = dwc3_core_init(dwc); + if (ret) + return ret; + } + break; default: /* do nothing */ break; @@ -1334,12 +1343,11 @@ static int dwc3_resume_common(struct dwc3 *dwc) static int dwc3_runtime_checks(struct dwc3 *dwc) { switch (dwc->current_dr_role) { - case USB_DR_MODE_PERIPHERAL: - case USB_DR_MODE_OTG: + case DWC3_GCTL_PRTCAP_DEVICE: if (dwc->connected) return -EBUSY; break; - case USB_DR_MODE_HOST: + case DWC3_GCTL_PRTCAP_HOST: default: /* do nothing */ break; @@ -1356,7 +1364,7 @@ static int dwc3_runtime_suspend(struct device *dev) if (dwc3_runtime_checks(dwc)) return -EBUSY; - ret = dwc3_suspend_common(dwc); + ret = dwc3_suspend_common(dwc, PMSG_AUTO_SUSPEND); if (ret) return ret; @@ -1372,7 +1380,7 @@ static int dwc3_runtime_resume(struct device *dev) device_init_wakeup(dev, false); - ret = dwc3_resume_common(dwc); + ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME); if (ret) return ret; @@ -1419,7 +1427,7 @@ static int dwc3_suspend(struct device *dev) struct dwc3 *dwc = dev_get_drvdata(dev); int ret; - ret = dwc3_suspend_common(dwc); + ret = dwc3_suspend_common(dwc, PMSG_SUSPEND); if (ret) return ret; @@ -1435,7 +1443,7 @@ static int dwc3_resume(struct device *dev) pinctrl_pm_select_default_state(dev); - ret = dwc3_resume_common(dwc); + ret = dwc3_resume_common(dwc, PMSG_RESUME); if (ret) return ret; -- cgit v1.2.3 From 499350865387f8b8c40a9e9453a9a7eb3cec5dc4 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 18 Jan 2018 00:22:45 -0200 Subject: usb: phy: mxs: Fix NULL pointer dereference on i.MX23/28 Commit e93650994a95 ("usb: phy: mxs: add usb charger type detection") causes the following kernel hang on i.MX28: [ 2.207973] usbcore: registered new interface driver usb-storage [ 2.235659] Unable to handle kernel NULL pointer dereference at virtual address 00000188 [ 2.244195] pgd = (ptrval) [ 2.246994] [00000188] *pgd=00000000 [ 2.250676] Internal error: Oops: 5 [#1] ARM [ 2.254979] Modules linked in: [ 2.258089] CPU: 0 PID: 1 Comm: swapper Not tainted 4.15.0-rc8-next-20180117-00002-g75d5f21 #7 [ 2.266724] Hardware name: Freescale MXS (Device Tree) [ 2.271921] PC is at regmap_read+0x0/0x5c [ 2.275977] LR is at mxs_phy_charger_detect+0x34/0x1dc mxs_phy_charger_detect() makes accesses to the anatop registers via regmap, however i.MX23/28 do not have such registers, which causes a NULL pointer dereference. Fix the issue by doing a NULL check on the 'regmap' pointer. Fixes: e93650994a95 ("usb: phy: mxs: add usb charger type detection") Cc: # v4.15 Reviewed-by: Li Jun Acked-by: Peter Chen Signed-off-by: Fabio Estevam Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-mxs-usb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index da031c45395a..fbec863350f6 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -602,6 +602,9 @@ static enum usb_charger_type mxs_phy_charger_detect(struct usb_phy *phy) void __iomem *base = phy->io_priv; enum usb_charger_type chgr_type = UNKNOWN_TYPE; + if (!regmap) + return UNKNOWN_TYPE; + if (mxs_charger_data_contact_detect(mxs_phy)) return chgr_type; -- cgit v1.2.3 From 6cf439e0d37463e42784271179c8a308fd7493c6 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 24 Jan 2018 00:11:53 -0800 Subject: usb: gadget: f_fs: Process all descriptors during bind During _ffs_func_bind(), the received descriptors are evaluated to prepare for binding with the gadget in order to allocate endpoints and optionally set up OS descriptors. However, the high- and super-speed descriptors are only parsed based on whether the gadget_is_dualspeed() and gadget_is_superspeed() calls are true, respectively. This is a problem in case a userspace program always provides all of the {full,high,super,OS} descriptors when configuring a function. Then, for example if a gadget device is not capable of SuperSpeed, the call to ffs_do_descs() for the SS descriptors is skipped, resulting in an incorrect offset calculation for the vla_ptr when moving on to the OS descriptors that follow. This causes ffs_do_os_descs() to fail as it is now looking at the SS descriptors' offset within the raw_descs buffer instead. _ffs_func_bind() should evaluate the descriptors unconditionally, so remove the checks for gadget speed. Fixes: f0175ab51993 ("usb: gadget: f_fs: OS descriptors support") Cc: stable@vger.kernel.org Co-Developed-by: Mayank Rana Signed-off-by: Mayank Rana Signed-off-by: Jack Pham Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 8f2cf3baa19c..49fc589fbf58 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2979,10 +2979,8 @@ static int _ffs_func_bind(struct usb_configuration *c, struct ffs_data *ffs = func->ffs; const int full = !!func->ffs->fs_descs_count; - const int high = gadget_is_dualspeed(func->gadget) && - func->ffs->hs_descs_count; - const int super = gadget_is_superspeed(func->gadget) && - func->ffs->ss_descs_count; + const int high = !!func->ffs->hs_descs_count; + const int super = !!func->ffs->ss_descs_count; int fs_len, hs_len, ss_len, ret, i; struct ffs_ep *eps_ptr; -- cgit v1.2.3 From 675272d092e4a5570bace92593776f7348daf4c5 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 24 Jan 2018 23:58:20 -0800 Subject: usb: gadget: f_fs: Use config_ep_by_speed() In commit 2bfa0719ac2a ("usb: gadget: function: f_fs: pass companion descriptor along") there is a pointer arithmetic bug where the comp_desc is obtained as follows: comp_desc = (struct usb_ss_ep_comp_descriptor *)(ds + USB_DT_ENDPOINT_SIZE); Since ds is a pointer to usb_endpoint_descriptor, adding 7 to it ends up going out of bounds (7 * sizeof(struct usb_endpoint_descriptor), which is actually 7*9 bytes) past the SS descriptor. As a result the maxburst value will be read incorrectly, and the UDC driver will also get a garbage comp_desc (assuming it uses it). Since Felipe wrote, "Eventually, f_fs.c should be converted to use config_ep_by_speed() like all other functions, though", let's finally do it. This allows the other usb_ep fields to be properly populated, such as maxpacket and mult. It also eliminates the awkward speed-based descriptor lookup since config_ep_by_speed() does that already using the ones found in struct usb_function. Fixes: 2bfa0719ac2a ("usb: gadget: function: f_fs: pass companion descriptor along") Cc: stable@vger.kernel.org Signed-off-by: Jack Pham Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 38 +++++++------------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 49fc589fbf58..c2592d883f67 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1855,44 +1855,20 @@ static int ffs_func_eps_enable(struct ffs_function *func) spin_lock_irqsave(&func->ffs->eps_lock, flags); while(count--) { - struct usb_endpoint_descriptor *ds; - struct usb_ss_ep_comp_descriptor *comp_desc = NULL; - int needs_comp_desc = false; - int desc_idx; - - if (ffs->gadget->speed == USB_SPEED_SUPER) { - desc_idx = 2; - needs_comp_desc = true; - } else if (ffs->gadget->speed == USB_SPEED_HIGH) - desc_idx = 1; - else - desc_idx = 0; - - /* fall-back to lower speed if desc missing for current speed */ - do { - ds = ep->descs[desc_idx]; - } while (!ds && --desc_idx >= 0); - - if (!ds) { - ret = -EINVAL; - break; - } - ep->ep->driver_data = ep; - ep->ep->desc = ds; - if (needs_comp_desc) { - comp_desc = (struct usb_ss_ep_comp_descriptor *)(ds + - USB_DT_ENDPOINT_SIZE); - ep->ep->maxburst = comp_desc->bMaxBurst + 1; - ep->ep->comp_desc = comp_desc; + ret = config_ep_by_speed(func->gadget, &func->function, ep->ep); + if (ret) { + pr_err("%s: config_ep_by_speed(%s) returned %d\n", + __func__, ep->ep->name, ret); + break; } ret = usb_ep_enable(ep->ep); if (likely(!ret)) { epfile->ep = ep; - epfile->in = usb_endpoint_dir_in(ds); - epfile->isoc = usb_endpoint_xfer_isoc(ds); + epfile->in = usb_endpoint_dir_in(ep->ep->desc); + epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc); } else { break; } -- cgit v1.2.3 From c49f63055e252810e5d6c83a4943b18db16b3cd8 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 22 Jan 2018 15:01:42 +0200 Subject: usb: dwc3: omap: don't miss events during suspend/resume The USB cable state can change during suspend/resume so be sure to check and update the extcon state. Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-omap.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index a4719e853b85..ed8b86517675 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -582,9 +582,25 @@ static int dwc3_omap_resume(struct device *dev) return 0; } +static void dwc3_omap_complete(struct device *dev) +{ + struct dwc3_omap *omap = dev_get_drvdata(dev); + + if (extcon_get_state(omap->edev, EXTCON_USB)) + dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); + else + dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF); + + if (extcon_get_state(omap->edev, EXTCON_USB_HOST)) + dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); + else + dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT); +} + static const struct dev_pm_ops dwc3_omap_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume) + .complete = dwc3_omap_complete, }; #define DEV_PM_OPS (&dwc3_omap_dev_pm_ops) -- cgit v1.2.3 From e74bd4d358e5455233f1dcc3975425905b270b91 Mon Sep 17 00:00:00 2001 From: Manu Gautam Date: Thu, 21 Dec 2017 09:54:25 +0530 Subject: usb: gadget: core: Fix use-after-free of usb_request Driver is tracing usb_request after freeing it. Fix it by changing the order. Signed-off-by: Manu Gautam Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 859d5b11ba4c..1f8b19d9cf97 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -180,8 +180,8 @@ EXPORT_SYMBOL_GPL(usb_ep_alloc_request); void usb_ep_free_request(struct usb_ep *ep, struct usb_request *req) { - ep->ops->free_request(ep, req); trace_usb_ep_free_request(ep, req, 0); + ep->ops->free_request(ep, req); } EXPORT_SYMBOL_GPL(usb_ep_free_request); -- cgit v1.2.3 From b16ea8b9492e99e03b1269fe93ebdbf8e4eabf8a Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Fri, 2 Feb 2018 13:21:35 -0800 Subject: usb: dwc3: Fix GDBGFIFOSPACE_TYPE values The FIFO/Queue type values are incorrect. Correct them according to DWC_usb3 programming guide section 1.2.27 (or DWC_usb31 section 1.2.25). Additionally, this patch includes ProtocolStatusQ and AuxEventQ types. Fixes: cf6d867d3b57 ("usb: dwc3: core: add fifo space helper") Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 03c7aaaac926..185b9603fd98 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -158,13 +158,15 @@ #define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0) #define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff) -#define DWC3_TXFIFOQ 1 -#define DWC3_RXFIFOQ 3 -#define DWC3_TXREQQ 5 -#define DWC3_RXREQQ 7 -#define DWC3_RXINFOQ 9 -#define DWC3_DESCFETCHQ 13 -#define DWC3_EVENTQ 15 +#define DWC3_TXFIFOQ 0 +#define DWC3_RXFIFOQ 1 +#define DWC3_TXREQQ 2 +#define DWC3_RXREQQ 3 +#define DWC3_RXINFOQ 4 +#define DWC3_PSTATQ 5 +#define DWC3_DESCFETCHQ 6 +#define DWC3_EVENTQ 7 +#define DWC3_AUXEVENTQ 8 /* Global RX Threshold Configuration Register */ #define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19) -- cgit v1.2.3 From 20bf410ecf9e9c045f4b0548d516dd3de8691074 Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Mon, 5 Feb 2018 02:21:23 +0100 Subject: usb: gadget: udc: Remove USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED was removed by commit 85b8614d7223 ("usb: gadget: get rid of USB_GADGET_{DUAL,SUPER}SPEED"), but the USB_SNP_UDC_PLAT symbol still selects it. Remove the USB_GADGET_DUALSPEED select from USB_SNP_UDC_PLAT. Discovered with the https://github.com/ulfalizer/Kconfiglib/blob/master/examples/list_undefined.py script. Signed-off-by: Ulf Magnusson Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 1e9567091d86..0875d38476ee 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -274,7 +274,6 @@ config USB_SNP_UDC_PLAT tristate "Synopsys USB 2.0 Device controller" depends on USB_GADGET && OF && HAS_DMA depends on EXTCON || EXTCON=n - select USB_GADGET_DUALSPEED select USB_SNP_CORE default ARCH_BCM_IPROC help -- cgit v1.2.3 From 17aa31f13cad25daa19d3f923323f552e87bc874 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 5 Feb 2018 17:12:35 +0900 Subject: usb: renesas_usbhs: missed the "running" flag in usb_dmac with rx path This fixes an issue that a gadget driver (usb_f_fs) is possible to stop rx transactions after the usb-dmac is used because the following functions missed to set/check the "running" flag. - usbhsf_dma_prepare_pop_with_usb_dmac() - usbhsf_dma_pop_done_with_usb_dmac() So, if next transaction uses pio, the usbhsf_prepare_pop() can not start the transaction because the "running" flag is 0. Fixes: 8355b2b3082d ("usb: renesas_usbhs: fix the behavior of some usbhs_pkt_handle") Cc: # v3.19+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/fifo.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 5925d111bd47..39fa2fc1b8b7 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -982,6 +982,10 @@ static int usbhsf_dma_prepare_pop_with_usb_dmac(struct usbhs_pkt *pkt, if ((uintptr_t)pkt->buf & (USBHS_USB_DMAC_XFER_SIZE - 1)) goto usbhsf_pio_prepare_pop; + /* return at this time if the pipe is running */ + if (usbhs_pipe_is_running(pipe)) + return 0; + usbhs_pipe_config_change_bfre(pipe, 1); ret = usbhsf_fifo_select(pipe, fifo, 0); @@ -1172,6 +1176,7 @@ static int usbhsf_dma_pop_done_with_usb_dmac(struct usbhs_pkt *pkt, usbhsf_fifo_clear(pipe, fifo); pkt->actual = usbhs_dma_calc_received_size(pkt, chan, rcv_len); + usbhs_pipe_running(pipe, 0); usbhsf_dma_stop(pipe, fifo); usbhsf_dma_unmap(pkt); usbhsf_fifo_unselect(pipe, pipe->fifo); -- cgit v1.2.3 From 20c63f4089cceab803438c383631963e34c4d8e5 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 12 Feb 2018 00:14:42 +0100 Subject: usb: gadget: fsl_udc_core: fix ep valid checks Clang reports the following warning: drivers/usb/gadget/udc/fsl_udc_core.c:1312:10: warning: address of array 'ep->name' will always evaluate to 'true' [-Wpointer-bool-conversion] if (ep->name) ~~ ~~~~^~~~ It seems that the authors intention was to check if the ep has been configured through struct_ep_setup. Check whether struct usb_ep name pointer has been set instead. Signed-off-by: Stefan Agner Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fsl_udc_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index e5b4ee96c4bf..56b517a38865 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -1305,7 +1305,7 @@ static void udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe) { struct fsl_ep *ep = get_ep_by_pipe(udc, pipe); - if (ep->name) + if (ep->ep.name) nuke(ep, -ESHUTDOWN); } @@ -1693,7 +1693,7 @@ static void dtd_complete_irq(struct fsl_udc *udc) curr_ep = get_ep_by_pipe(udc, i); /* If the ep is configured */ - if (curr_ep->name == NULL) { + if (!curr_ep->ep.name) { WARNING("Invalid EP?"); continue; } -- cgit v1.2.3 From 201ec568c57a43dbc73c7ac00e73c3c2d39559fc Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Tue, 16 Jan 2018 16:03:32 +0400 Subject: usb: dwc2: Add safety check in setting of descriptor chain pointers In some cases device sending ZLP IN on non EP0 which reassigning EP0 OUT descriptor pointer to that EP. Dedicated for EP0 OUT descriptor multiple time re-used by other EP while that descriptor already in use by EP0 OUT for SETUP transaction. As result when SETUP packet received BNA interrupt asserting. In dwc2_hsotg_program_zlp() function dwc2_gadget_set_ep0_desc_chain() must be called only for EP0. Acked-by: John Youn Signed-off-by: Minas Harutyunyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index e4c3ce0de5de..57c7400057fa 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -1917,7 +1917,9 @@ static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, /* Not specific buffer needed for ep0 ZLP */ dma_addr_t dma = hs_ep->desc_list_dma; - dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep); + if (!index) + dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep); + dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0); } else { dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | -- cgit v1.2.3 From 9e95a66cce7250c358d496e1c3b62e29ce79ef40 Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Tue, 16 Jan 2018 16:03:58 +0400 Subject: usb: dwc2: Add safety check for STSPHSERCVD intr STSPHSERCVD (status phase received) interrupt should be handled when EP0 is in DWC2_EP0_DATA_OUT state. Sometimes STSPHSERCVD interrupt asserted , when EP0 is not in DATA_OUT state. Spurios interrupt. Acked-by: John Youn Signed-off-by: Minas Harutyunyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 57c7400057fa..d6222e946463 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2976,9 +2976,13 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, if (ints & DXEPINT_STSPHSERCVD) { dev_dbg(hsotg->dev, "%s: StsPhseRcvd\n", __func__); - /* Move to STATUS IN for DDMA */ - if (using_desc_dma(hsotg)) - dwc2_hsotg_ep0_zlp(hsotg, true); + /* Safety check EP0 state when STSPHSERCVD asserted */ + if (hsotg->ep0_state == DWC2_EP0_DATA_OUT) { + /* Move to STATUS IN for DDMA */ + if (using_desc_dma(hsotg)) + dwc2_hsotg_ep0_zlp(hsotg, true); + } + } if (ints & DXEPINT_BACK2BACKSETUP) -- cgit v1.2.3 From 755d739534f998d92e348fba8ffb0478416576e7 Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Tue, 16 Jan 2018 16:04:24 +0400 Subject: usb: dwc2: Fix dwc2_hsotg_core_init_disconnected() We should call dwc2_hsotg_enqueue_setup() after properly setting lx_state. Because it may cause error-out from dwc2_hsotg_enqueue_setup() due to wrong value in lx_state. Issue can be reproduced by loading driver while connected A-Connector (start in A-HOST mode) then disconnect A-Connector to switch to B-DEVICE. Acked-by: John Youn Signed-off-by: Vardan Mikayelyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index d6222e946463..5bcad1d869b5 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3381,12 +3381,6 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0); - dwc2_hsotg_enqueue_setup(hsotg); - - dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", - dwc2_readl(hsotg->regs + DIEPCTL0), - dwc2_readl(hsotg->regs + DOEPCTL0)); - /* clear global NAKs */ val = DCTL_CGOUTNAK | DCTL_CGNPINNAK; if (!is_usb_reset) @@ -3397,6 +3391,12 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, mdelay(3); hsotg->lx_state = DWC2_L0; + + dwc2_hsotg_enqueue_setup(hsotg); + + dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + dwc2_readl(hsotg->regs + DIEPCTL0), + dwc2_readl(hsotg->regs + DOEPCTL0)); } static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) -- cgit v1.2.3 From 3cd091a773936c54344a519f7ee1379ccb620bee Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 9 Feb 2018 22:55:28 +0100 Subject: ACPI / EC: Restore polling during noirq suspend/resume phases Commit 662591461c4b (ACPI / EC: Drop EC noirq hooks to fix a regression) modified the ACPI EC driver so that it doesn't switch over to busy polling mode during noirq stages of system suspend and resume in an attempt to fix an issue resulting from that behavior. However, that modification introduced a system resume regression on Thinkpad X240, so make the EC driver switch over to the polling mode during noirq stages of system suspend and resume again, which effectively reverts the problematic commit. Fixes: 662591461c4b (ACPI / EC: Drop EC noirq hooks to fix a regression) Link: https://bugzilla.kernel.org/show_bug.cgi?id=197863 Reported-by: Markus Demleitner Tested-by: Markus Demleitner Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index d9f38c645e4a..30a572956557 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1927,6 +1927,9 @@ static int acpi_ec_suspend_noirq(struct device *dev) ec->reference_count >= 1) acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE); + if (acpi_sleep_no_ec_events()) + acpi_ec_enter_noirq(ec); + return 0; } @@ -1934,6 +1937,9 @@ static int acpi_ec_resume_noirq(struct device *dev) { struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev)); + if (acpi_sleep_no_ec_events()) + acpi_ec_leave_noirq(ec); + if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) && ec->reference_count >= 1) acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE); -- cgit v1.2.3 From 5a9e59e8d9dd9586d78c244b9d96fb18156daad3 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 9 Feb 2018 12:08:21 -0600 Subject: ACPI: SPCR: Mark expected switch fall-through in acpi_parse_spcr In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Addresses-Coverity-ID: 1465078 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Rafael J. Wysocki --- drivers/acpi/spcr.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 89e97d21a89c..9d52743080a4 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -115,6 +115,7 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console) table->serial_port.access_width))) { default: pr_err("Unexpected SPCR Access Width. Defaulting to byte size\n"); + /* fall through */ case 8: iotype = "mmio"; break; -- cgit v1.2.3 From 4a823c0be80fa996234ebb41c80d40458b1bec1e Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Fri, 26 Jan 2018 16:48:49 +0800 Subject: opp: cpu: Replace GFP_ATOMIC with GFP_KERNEL in dev_pm_opp_init_cpufreq_table After checking all possible call chains to dev_pm_opp_init_cpufreq_table() here, my tool finds that this function is never called in atomic context, namely never in an interrupt handler or holding a spinlock. And dev_pm_opp_init_cpufreq_table() calls dev_pm_opp_get_opp_count(), which calls mutex_lock that can sleep. It indicates that atmtcp_v_send() can call functions which may sleep. Thus GFP_ATOMIC is not necessary, and it can be replaced with GFP_KERNEL. This is found by a static analysis tool named DCNS written by myself. Signed-off-by: Jia-Ju Bai Signed-off-by: Viresh Kumar --- drivers/opp/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/opp/cpu.c b/drivers/opp/cpu.c index 2d87bc1adf38..0c0910709435 100644 --- a/drivers/opp/cpu.c +++ b/drivers/opp/cpu.c @@ -55,7 +55,7 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev, if (max_opps <= 0) return max_opps ? max_opps : -ENODATA; - freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC); + freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_KERNEL); if (!freq_table) return -ENOMEM; -- cgit v1.2.3 From 4222f38ca3b7ae30ace582077677cec8b88fac36 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 9 Feb 2018 17:38:33 +0200 Subject: ACPI / bus: Do not traverse through non-existed device table When __acpi_match_device() is called it would be possible to have ACPI ID table a NULL pointer. To avoid potential dereference, check for this before traverse. While here, remove redundant 'else'. Note, this patch implies a bit of refactoring acpi_of_match_device() to return pointer to OF ID when matched followed by refactoring __acpi_match_device() to return either ACPI or OF ID when matches. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 63 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 676c9788e1c8..f1384e107eed 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -660,13 +660,15 @@ struct acpi_device *acpi_companion_match(const struct device *dev) * acpi_of_match_device - Match device object using the "compatible" property. * @adev: ACPI device object to match. * @of_match_table: List of device IDs to match against. + * @of_id: OF ID if matched * * If @dev has an ACPI companion which has ACPI_DT_NAMESPACE_HID in its list of * identifiers and a _DSD object with the "compatible" property, use that * property to match against the given list of identifiers. */ static bool acpi_of_match_device(struct acpi_device *adev, - const struct of_device_id *of_match_table) + const struct of_device_id *of_match_table, + const struct of_device_id **of_id) { const union acpi_object *of_compatible, *obj; int i, nval; @@ -690,8 +692,11 @@ static bool acpi_of_match_device(struct acpi_device *adev, const struct of_device_id *id; for (id = of_match_table; id->compatible[0]; id++) - if (!strcasecmp(obj->string.pointer, id->compatible)) + if (!strcasecmp(obj->string.pointer, id->compatible)) { + if (of_id) + *of_id = id; return true; + } } return false; @@ -762,10 +767,11 @@ static bool __acpi_match_device_cls(const struct acpi_device_id *id, return true; } -static const struct acpi_device_id *__acpi_match_device( - struct acpi_device *device, - const struct acpi_device_id *ids, - const struct of_device_id *of_ids) +static bool __acpi_match_device(struct acpi_device *device, + const struct acpi_device_id *acpi_ids, + const struct of_device_id *of_ids, + const struct acpi_device_id **acpi_id, + const struct of_device_id **of_id) { const struct acpi_device_id *id; struct acpi_hardware_id *hwid; @@ -775,30 +781,32 @@ static const struct acpi_device_id *__acpi_match_device( * driver for it. */ if (!device || !device->status.present) - return NULL; + return false; list_for_each_entry(hwid, &device->pnp.ids, list) { /* First, check the ACPI/PNP IDs provided by the caller. */ - for (id = ids; id->id[0] || id->cls; id++) { - if (id->id[0] && !strcmp((char *) id->id, hwid->id)) - return id; - else if (id->cls && __acpi_match_device_cls(id, hwid)) - return id; + if (acpi_ids) { + for (id = acpi_ids; id->id[0] || id->cls; id++) { + if (id->id[0] && !strcmp((char *)id->id, hwid->id)) + goto out_acpi_match; + if (id->cls && __acpi_match_device_cls(id, hwid)) + goto out_acpi_match; + } } /* * Next, check ACPI_DT_NAMESPACE_HID and try to match the * "compatible" property if found. - * - * The id returned by the below is not valid, but the only - * caller passing non-NULL of_ids here is only interested in - * whether or not the return value is NULL. */ - if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id) - && acpi_of_match_device(device, of_ids)) - return id; + if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id)) + return acpi_of_match_device(device, of_ids, of_id); } - return NULL; + return false; + +out_acpi_match: + if (acpi_id) + *acpi_id = id; + return true; } /** @@ -815,7 +823,10 @@ static const struct acpi_device_id *__acpi_match_device( const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, const struct device *dev) { - return __acpi_match_device(acpi_companion_match(dev), ids, NULL); + const struct acpi_device_id *id = NULL; + + __acpi_match_device(acpi_companion_match(dev), ids, NULL, &id, NULL); + return id; } EXPORT_SYMBOL_GPL(acpi_match_device); @@ -840,7 +851,7 @@ EXPORT_SYMBOL_GPL(acpi_get_match_data); int acpi_match_device_ids(struct acpi_device *device, const struct acpi_device_id *ids) { - return __acpi_match_device(device, ids, NULL) ? 0 : -ENOENT; + return __acpi_match_device(device, ids, NULL, NULL, NULL) ? 0 : -ENOENT; } EXPORT_SYMBOL(acpi_match_device_ids); @@ -849,10 +860,12 @@ bool acpi_driver_match_device(struct device *dev, { if (!drv->acpi_match_table) return acpi_of_match_device(ACPI_COMPANION(dev), - drv->of_match_table); + drv->of_match_table, + NULL); - return !!__acpi_match_device(acpi_companion_match(dev), - drv->acpi_match_table, drv->of_match_table); + return __acpi_match_device(acpi_companion_match(dev), + drv->acpi_match_table, drv->of_match_table, + NULL, NULL); } EXPORT_SYMBOL_GPL(acpi_driver_match_device); -- cgit v1.2.3 From 8ff277c5bf87d750a44a656d4f113462493acbfc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 9 Feb 2018 17:38:34 +0200 Subject: ACPI / bus: Remove checks in acpi_get_match_data() As well as its sibling of_device_get_match_data() has no such checks, no need to do it in acpi_get_match_data(). First of all, we are not supposed to call fwnode API like this without driver attached. Second, since __acpi_match_device() does check input parameter there is no need to duplicate it outside. And last but not least one, the API should still serve the cases when ACPI device is enumerated via PRP0001. In such case driver has neither ACPI table nor driver data there. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index f1384e107eed..ca4af098b1bf 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -834,12 +834,6 @@ void *acpi_get_match_data(const struct device *dev) { const struct acpi_device_id *match; - if (!dev->driver) - return NULL; - - if (!dev->driver->acpi_match_table) - return NULL; - match = acpi_match_device(dev->driver->acpi_match_table, dev); if (!match) return NULL; -- cgit v1.2.3 From 29d5325a14ab49375476e3a6442ff40a008a8c9a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 9 Feb 2018 17:38:35 +0200 Subject: ACPI / bus: Rename acpi_get_match_data() to acpi_device_get_match_data() Do the renaming to be consistent with its sibling, i.e. of_device_get_match_data(). No functional change. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 4 ++-- drivers/acpi/property.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index ca4af098b1bf..e6285b5ce0d5 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -830,7 +830,7 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, } EXPORT_SYMBOL_GPL(acpi_match_device); -void *acpi_get_match_data(const struct device *dev) +void *acpi_device_get_match_data(const struct device *dev) { const struct acpi_device_id *match; @@ -840,7 +840,7 @@ void *acpi_get_match_data(const struct device *dev) return (void *)match->driver_data; } -EXPORT_SYMBOL_GPL(acpi_get_match_data); +EXPORT_SYMBOL_GPL(acpi_device_get_match_data); int acpi_match_device_ids(struct acpi_device *device, const struct acpi_device_id *ids) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 466d1503aba0..f9b5fa230a86 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1275,7 +1275,7 @@ static void * acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, const struct device *dev) { - return acpi_get_match_data(dev); + return acpi_device_get_match_data(dev); } #define DECLARE_ACPI_FWNODE_OPS(ops) \ -- cgit v1.2.3 From 67dcc26d208ca5578f08c3c78cb254418c24e9ec Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 9 Feb 2018 17:38:36 +0200 Subject: device property: Constify device_get_match_data() Constify device_get_match_data() as OF and ACPI variants return constant value. Acked-by: Sakari Ailus Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 4 ++-- drivers/acpi/property.c | 2 +- drivers/base/property.c | 5 ++--- drivers/of/property.c | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index e6285b5ce0d5..0dad0bd9327b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -830,7 +830,7 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, } EXPORT_SYMBOL_GPL(acpi_match_device); -void *acpi_device_get_match_data(const struct device *dev) +const void *acpi_device_get_match_data(const struct device *dev) { const struct acpi_device_id *match; @@ -838,7 +838,7 @@ void *acpi_device_get_match_data(const struct device *dev) if (!match) return NULL; - return (void *)match->driver_data; + return (const void *)match->driver_data; } EXPORT_SYMBOL_GPL(acpi_device_get_match_data); diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index f9b5fa230a86..5815356ea6ad 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1271,7 +1271,7 @@ static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, return 0; } -static void * +static const void * acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, const struct device *dev) { diff --git a/drivers/base/property.c b/drivers/base/property.c index 302236281d83..8f205f6461ed 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -1410,9 +1410,8 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, } EXPORT_SYMBOL(fwnode_graph_parse_endpoint); -void *device_get_match_data(struct device *dev) +const void *device_get_match_data(struct device *dev) { - return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, - dev); + return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev); } EXPORT_SYMBOL_GPL(device_get_match_data); diff --git a/drivers/of/property.c b/drivers/of/property.c index 36ed84e26d9c..f46828e3b082 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -977,11 +977,11 @@ static int of_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, return 0; } -static void * +static const void * of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, const struct device *dev) { - return (void *)of_device_get_match_data(dev); + return of_device_get_match_data(dev); } const struct fwnode_operations of_fwnode_ops = { -- cgit v1.2.3 From 49527bc0e8d207e87bf3ebe8eb8cce7353372d79 Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Thu, 18 Jan 2018 22:17:57 +0800 Subject: pinctrl: meson-axg: adjust uart_ao_b pin group naming Simply adjust the pin group to _x _y _z style, as to keep the consistency in DT with previous naming scheme. Fixes: 83c566806a68 ("pinctrl: meson-axg: Add new pinctrl driver for Meson AXG SoC") Signed-off-by: Yixun Lan Signed-off-by: Linus Walleij --- drivers/pinctrl/meson/pinctrl-meson-axg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg.c b/drivers/pinctrl/meson/pinctrl-meson-axg.c index 1fda9d6c7ea3..4b91ff74779b 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-axg.c +++ b/drivers/pinctrl/meson/pinctrl-meson-axg.c @@ -716,7 +716,7 @@ static const char * const uart_b_groups[] = { "uart_tx_b_x", "uart_rx_b_x", "uart_cts_b_x", "uart_rts_b_x", }; -static const char * const uart_ao_b_gpioz_groups[] = { +static const char * const uart_ao_b_z_groups[] = { "uart_ao_tx_b_z", "uart_ao_rx_b_z", "uart_ao_cts_b_z", "uart_ao_rts_b_z", }; @@ -855,7 +855,7 @@ static struct meson_pmx_func meson_axg_periphs_functions[] = { FUNCTION(nand), FUNCTION(uart_a), FUNCTION(uart_b), - FUNCTION(uart_ao_b_gpioz), + FUNCTION(uart_ao_b_z), FUNCTION(i2c0), FUNCTION(i2c1), FUNCTION(i2c2), -- cgit v1.2.3 From ea56fb282368ea08c2a313af6b55cb597aec4db1 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 9 Feb 2018 13:21:42 +0100 Subject: mtd: nand: vf610: set correct ooblayout With commit 3cf32d180227 ("mtd: nand: vf610: switch to mtd_ooblayout_ops") the driver started to use the NAND cores default large page ooblayout. However, shortly after commit 6a623e076944 ("mtd: nand: add ooblayout for old hamming layout") changed the default layout to the old hamming layout, which is not what vf610_nfc is using. Specify the default large page layout explicitly. Fixes: 6a623e076944 ("mtd: nand: add ooblayout for old hamming layout") Cc: # v4.12+ Signed-off-by: Stefan Agner Signed-off-by: Boris Brezillon --- drivers/mtd/nand/vf610_nfc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 80d31a58e558..f367144f3c6f 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -752,10 +752,8 @@ static int vf610_nfc_probe(struct platform_device *pdev) if (mtd->oobsize > 64) mtd->oobsize = 64; - /* - * mtd->ecclayout is not specified here because we're using the - * default large page ECC layout defined in NAND core. - */ + /* Use default large page ECC layout defined in NAND core */ + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); if (chip->ecc.strength == 32) { nfc->ecc_mode = ECC_60_BYTE; chip->ecc.bytes = 60; -- cgit v1.2.3 From f23def8038611fa362de345c540107c78edaa085 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 30 Jan 2018 14:23:21 +0100 Subject: mtd: nand: MTD_NAND_MARVELL should depend on HAS_DMA If NO_DMA=y: ERROR: "bad_dma_ops" [drivers/mtd/nand/marvell_nand.ko] undefined! Add a dependency on HAS_DMA to fix this. Fixes: 02f26ecf8c772751 ("mtd: nand: add reworked Marvell NAND controller driver") Signed-off-by: Geert Uytterhoeven Acked-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index e6b8c59f2c0d..736ac887303c 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -328,7 +328,7 @@ config MTD_NAND_MARVELL tristate "NAND controller support on Marvell boards" depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \ COMPILE_TEST - depends on HAS_IOMEM + depends on HAS_IOMEM && HAS_DMA help This enables the NAND flash controller driver for Marvell boards, including: -- cgit v1.2.3 From 69728051f5bf15efaf6edfbcfe1b5a49a2437918 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 9 Feb 2018 08:11:26 -0800 Subject: PM / wakeirq: Fix unbalanced IRQ enable for wakeirq If a device is runtime PM suspended when we enter suspend and has a dedicated wake IRQ, we can get the following warning: WARNING: CPU: 0 PID: 108 at kernel/irq/manage.c:526 enable_irq+0x40/0x94 [ 102.087860] Unbalanced enable for IRQ 147 ... (enable_irq) from [] (dev_pm_arm_wake_irq+0x4c/0x60) (dev_pm_arm_wake_irq) from [] (device_wakeup_arm_wake_irqs+0x58/0x9c) (device_wakeup_arm_wake_irqs) from [] (dpm_suspend_noirq+0x10/0x48) (dpm_suspend_noirq) from [] (suspend_devices_and_enter+0x30c/0xf14) (suspend_devices_and_enter) from [] (enter_state+0xad4/0xbd8) (enter_state) from [] (pm_suspend+0x38/0x98) (pm_suspend) from [] (state_store+0x68/0xc8) This is because the dedicated wake IRQ for the device may have been already enabled earlier by dev_pm_enable_wake_irq_check(). Fix the issue by checking for runtime PM suspended status. This issue can be easily reproduced by setting serial console log level to zero, letting the serial console idle, and suspend the system from an ssh terminal. On resume, dmesg will have the warning above. The reason why I have not run into this issue earlier has been that I typically run my PM test cases from on a serial console instead over ssh. Fixes: c84345597558 (PM / wakeirq: Enable dedicated wakeirq for suspend) Signed-off-by: Tony Lindgren Signed-off-by: Rafael J. Wysocki --- drivers/base/power/wakeirq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c index a8ac86e4d79e..6637fc319269 100644 --- a/drivers/base/power/wakeirq.c +++ b/drivers/base/power/wakeirq.c @@ -321,7 +321,8 @@ void dev_pm_arm_wake_irq(struct wake_irq *wirq) return; if (device_may_wakeup(wirq->dev)) { - if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED) + if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED && + !pm_runtime_status_suspended(wirq->dev)) enable_irq(wirq->irq); enable_irq_wake(wirq->irq); @@ -343,7 +344,8 @@ void dev_pm_disarm_wake_irq(struct wake_irq *wirq) if (device_may_wakeup(wirq->dev)) { disable_irq_wake(wirq->irq); - if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED) + if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED && + !pm_runtime_status_suspended(wirq->dev)) disable_irq_nosync(wirq->irq); } } -- cgit v1.2.3 From 433986c2c265d106d6a8e88006e0131fefc92b7b Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 10 Feb 2018 19:13:58 +0100 Subject: PM / runtime: Update links_count also if !CONFIG_SRCU Commit baa8809f6097 (PM / runtime: Optimize the use of device links) added an invocation of pm_runtime_drop_link() to __device_link_del(). However there are two variants of that function, one for CONFIG_SRCU and another for !CONFIG_SRCU, and the commit only modified the former. Fixes: baa8809f6097 (PM / runtime: Optimize the use of device links) Cc: v4.10+ # v4.10+ Signed-off-by: Lukas Wunner Signed-off-by: Rafael J. Wysocki --- drivers/base/core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/base/core.c b/drivers/base/core.c index b2261f92f2f1..5847364f25d9 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -310,6 +310,9 @@ static void __device_link_del(struct device_link *link) dev_info(link->consumer, "Dropping the link to %s\n", dev_name(link->supplier)); + if (link->flags & DL_FLAG_PM_RUNTIME) + pm_runtime_drop_link(link->consumer); + list_del(&link->s_node); list_del(&link->c_node); device_link_free(link); -- cgit v1.2.3 From f121e7d87e00d71ecf47630be2a6d95a82c1ea7a Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 11 Jan 2018 11:34:59 +0000 Subject: drm/etnaviv: make local symbols static Fixes the following sparse warnings: drivers/gpu/drm/etnaviv/etnaviv_iommu.c:161:39: warning: symbol 'etnaviv_iommuv1_ops' was not declared. Should it be static? drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c:239:39: warning: symbol 'etnaviv_iommuv2_ops' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_iommu.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c index 7a8c94731748..4b9b11ca6f03 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c @@ -158,7 +158,7 @@ void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu) gpu_write(gpu, VIVS_MC_MMU_RA_PAGE_TABLE, pgtable); } -const struct etnaviv_iommu_domain_ops etnaviv_iommuv1_ops = { +static const struct etnaviv_iommu_domain_ops etnaviv_iommuv1_ops = { .free = etnaviv_iommuv1_domain_free, .map = etnaviv_iommuv1_map, .unmap = etnaviv_iommuv1_unmap, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c index 1e956e266aa3..6e7c89247dc6 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c @@ -236,7 +236,7 @@ void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu) gpu_write(gpu, VIVS_MMUv2_CONTROL, VIVS_MMUv2_CONTROL_ENABLE); } -const struct etnaviv_iommu_domain_ops etnaviv_iommuv2_ops = { +static const struct etnaviv_iommu_domain_ops etnaviv_iommuv2_ops = { .free = etnaviv_iommuv2_domain_free, .map = etnaviv_iommuv2_map, .unmap = etnaviv_iommuv2_unmap, -- cgit v1.2.3 From c09d7f7911aa35570b29674f72077e1342260970 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 4 Jan 2018 13:40:03 +0100 Subject: drm/etnaviv: don't fail to build on arches without PHYS_OFFSET Some architecture ports like ARC don't provide the PHYS_OFFSET symbol. Define it to 0 in that case, which is the most conservative default in the usage context of the etnaviv driver. Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 21d0d22f1168..dfac65585e1d 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -31,6 +31,10 @@ #include "state_hi.xml.h" #include "cmdstream.xml.h" +#ifndef PHYS_OFFSET +#define PHYS_OFFSET 0 +#endif + static const struct platform_device_id gpu_ids[] = { { .name = "etnaviv-gpu,2d" }, { }, -- cgit v1.2.3 From 3d9fc6428434e534893b5f3a2c1f86c7660eac11 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 4 Jan 2018 13:50:14 +0100 Subject: drm/etnaviv: add missing major features field to debugfs This can be useful when dealing with a new GPU core. Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index dfac65585e1d..72c350c70c77 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -811,6 +811,8 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m) verify_dma(gpu, &debug); seq_puts(m, "\tfeatures\n"); + seq_printf(m, "\t major_features: 0x%08x\n", + gpu->identity.features); seq_printf(m, "\t minor_features0: 0x%08x\n", gpu->identity.minor_features0); seq_printf(m, "\t minor_features1: 0x%08x\n", -- cgit v1.2.3 From 8bc4d885bd42e9a1d47a53aa4efbb818597ef9a0 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 29 Nov 2017 14:49:04 +0100 Subject: drm/etnaviv: track fences by IDR instead of seqno This moves away from using the internal seqno as the userspace fence reference. By moving to a generic ID, we can later replace the internal fence by something different than the etnaviv seqno fence. Signed-off-by: Lucas Stach Reviewed-by: Philipp Zabel --- drivers/gpu/drm/etnaviv/etnaviv_gem.h | 1 + drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 56 +++++++++++++++++++--------- drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 1 + 4 files changed, 42 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h index be72a9833f2b..c30964152381 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h @@ -104,6 +104,7 @@ struct etnaviv_gem_submit { struct kref refcount; struct etnaviv_gpu *gpu; struct dma_fence *out_fence, *in_fence; + int out_fence_id; struct list_head node; /* GPU active submit list */ struct etnaviv_cmdbuf cmdbuf; bool runtime_resumed; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 1f8202bca061..919c8dc39f32 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -563,7 +563,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, } args->fence_fd = out_fence_fd; - args->fence = submit->out_fence->seqno; + args->fence = submit->out_fence_id; err_submit_objects: etnaviv_submit_put(submit); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 72c350c70c77..bab6a8286520 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1016,6 +1016,7 @@ static void hangcheck_disable(struct etnaviv_gpu *gpu) /* fence object management */ struct etnaviv_fence { struct etnaviv_gpu *gpu; + int id; struct dma_fence base; }; @@ -1052,6 +1053,11 @@ static void etnaviv_fence_release(struct dma_fence *fence) { struct etnaviv_fence *f = to_etnaviv_fence(fence); + /* first remove from IDR, so fence can not be looked up anymore */ + mutex_lock(&f->gpu->lock); + idr_remove(&f->gpu->fence_idr, f->id); + mutex_unlock(&f->gpu->lock); + kfree_rcu(f, base.rcu); } @@ -1078,6 +1084,11 @@ static struct dma_fence *etnaviv_gpu_fence_alloc(struct etnaviv_gpu *gpu) if (!f) return NULL; + f->id = idr_alloc_cyclic(&gpu->fence_idr, &f->base, 0, INT_MAX, GFP_KERNEL); + if (f->id < 0) { + kfree(f); + return NULL; + } f->gpu = gpu; dma_fence_init(&f->base, &etnaviv_fence_ops, &gpu->fence_spinlock, @@ -1226,35 +1237,43 @@ static void retire_worker(struct work_struct *work) } int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, - u32 fence, struct timespec *timeout) + u32 id, struct timespec *timeout) { + struct dma_fence *fence; int ret; - if (fence_after(fence, gpu->next_fence)) { - DRM_ERROR("waiting on invalid fence: %u (of %u)\n", - fence, gpu->next_fence); - return -EINVAL; - } + /* + * Look up the fence and take a reference. The mutex only synchronizes + * the IDR lookup with the fence release. We might still find a fence + * whose refcount has already dropped to zero. dma_fence_get_rcu + * pretends we didn't find a fence in that case. + */ + ret = mutex_lock_interruptible(&gpu->lock); + if (ret) + return ret; + fence = idr_find(&gpu->fence_idr, id); + if (fence) + fence = dma_fence_get_rcu(fence); + mutex_unlock(&gpu->lock); + + if (!fence) + return 0; if (!timeout) { /* No timeout was requested: just test for completion */ - ret = fence_completed(gpu, fence) ? 0 : -EBUSY; + ret = dma_fence_is_signaled(fence) ? 0 : -EBUSY; } else { unsigned long remaining = etnaviv_timeout_to_jiffies(timeout); - ret = wait_event_interruptible_timeout(gpu->fence_event, - fence_completed(gpu, fence), - remaining); - if (ret == 0) { - DBG("timeout waiting for fence: %u (retired: %u completed: %u)", - fence, gpu->retired_fence, - gpu->completed_fence); + ret = dma_fence_wait_timeout(fence, true, remaining); + if (ret == 0) ret = -ETIMEDOUT; - } else if (ret != -ERESTARTSYS) { + else if (ret != -ERESTARTSYS) ret = 0; - } + } + dma_fence_put(fence); return ret; } @@ -1386,6 +1405,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, ret = -ENOMEM; goto out_unlock; } + submit->out_fence_id = to_etnaviv_fence(submit->out_fence)->id; gpu->active_fence = submit->out_fence->seqno; @@ -1490,7 +1510,6 @@ static irqreturn_t irq_handler(int irq, void *data) continue; gpu->event[event].fence = NULL; - dma_fence_signal(fence); /* * Events can be processed out of order. Eg, @@ -1503,6 +1522,7 @@ static irqreturn_t irq_handler(int irq, void *data) */ if (fence_after(fence->seqno, gpu->completed_fence)) gpu->completed_fence = fence->seqno; + dma_fence_signal(fence); event_free(gpu, event); } @@ -1700,6 +1720,7 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master, gpu->drm = drm; gpu->fence_context = dma_fence_context_alloc(1); + idr_init(&gpu->fence_idr); spin_lock_init(&gpu->fence_spinlock); INIT_LIST_HEAD(&gpu->active_submit_list); @@ -1751,6 +1772,7 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master, } gpu->drm = NULL; + idr_destroy(&gpu->fence_idr); if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) thermal_cooling_device_unregister(gpu->cooling); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 7623905210dc..0170eb0a0923 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -128,6 +128,7 @@ struct etnaviv_gpu { u32 idle_mask; /* Fencing support */ + struct idr fence_idr; u32 next_fence; u32 active_fence; u32 completed_fence; -- cgit v1.2.3 From e93b6deeb45a781489f4ceaa97f9545a3cbebb81 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 4 Dec 2017 18:41:58 +0100 Subject: drm/etnaviv: hook up DRM GPU scheduler This hooks in the DRM GPU scheduler. No improvement yet, as all the dependency handling is still done in etnaviv_gem_submit. This just replaces the actual GPU submit by passing through the scheduler. Allows to get rid of the retire worker, as this is now driven by the scheduler. Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/Kconfig | 1 + drivers/gpu/drm/etnaviv/Makefile | 3 +- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 16 ++++ drivers/gpu/drm/etnaviv/etnaviv_drv.h | 7 +- drivers/gpu/drm/etnaviv/etnaviv_gem.h | 1 + drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 11 ++- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 113 +++++++++--------------- drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 14 +-- drivers/gpu/drm/etnaviv/etnaviv_sched.c | 125 +++++++++++++++++++++++++++ drivers/gpu/drm/etnaviv/etnaviv_sched.h | 35 ++++++++ 10 files changed, 235 insertions(+), 91 deletions(-) create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_sched.c create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_sched.h (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/Kconfig b/drivers/gpu/drm/etnaviv/Kconfig index 3f58b4077767..e5bfeca361bd 100644 --- a/drivers/gpu/drm/etnaviv/Kconfig +++ b/drivers/gpu/drm/etnaviv/Kconfig @@ -11,6 +11,7 @@ config DRM_ETNAVIV select WANT_DEV_COREDUMP select CMA if HAVE_DMA_CONTIGUOUS select DMA_CMA if HAVE_DMA_CONTIGUOUS + select DRM_SCHED help DRM driver for Vivante GPUs. diff --git a/drivers/gpu/drm/etnaviv/Makefile b/drivers/gpu/drm/etnaviv/Makefile index 1281c8d4fae5..9bb780c22501 100644 --- a/drivers/gpu/drm/etnaviv/Makefile +++ b/drivers/gpu/drm/etnaviv/Makefile @@ -12,6 +12,7 @@ etnaviv-y := \ etnaviv_iommu_v2.o \ etnaviv_iommu.o \ etnaviv_mmu.o \ - etnaviv_perfmon.o + etnaviv_perfmon.o \ + etnaviv_sched.o obj-$(CONFIG_DRM_ETNAVIV) += etnaviv.o diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index 6faf4042db23..8a73414682b2 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -101,12 +101,25 @@ static void load_gpu(struct drm_device *dev) static int etnaviv_open(struct drm_device *dev, struct drm_file *file) { + struct etnaviv_drm_private *priv = dev->dev_private; struct etnaviv_file_private *ctx; + int i; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; + for (i = 0; i < ETNA_MAX_PIPES; i++) { + struct etnaviv_gpu *gpu = priv->gpu[i]; + + if (gpu) { + drm_sched_entity_init(&gpu->sched, + &ctx->sched_entity[i], + &gpu->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL], + 32, NULL); + } + } + file->driver_priv = ctx; return 0; @@ -126,6 +139,9 @@ static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file) if (gpu->lastctx == ctx) gpu->lastctx = NULL; mutex_unlock(&gpu->lock); + + drm_sched_entity_fini(&gpu->sched, + &ctx->sched_entity[i]); } } diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h index a54f0b758a5c..1f055d931c6c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h @@ -34,6 +34,7 @@ #include #include #include +#include struct etnaviv_cmdbuf; struct etnaviv_gpu; @@ -42,11 +43,11 @@ struct etnaviv_gem_object; struct etnaviv_gem_submit; struct etnaviv_file_private { - /* currently we don't do anything useful with this.. but when - * per-context address spaces are supported we'd keep track of + /* + * When per-context address spaces are supported we'd keep track of * the context's page-tables here. */ - int dummy; + struct drm_sched_entity sched_entity[ETNA_MAX_PIPES]; }; struct etnaviv_drm_private { diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h index c30964152381..ae352f2a77f9 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h @@ -101,6 +101,7 @@ struct etnaviv_gem_submit_bo { * make it easier to unwind when things go wrong, etc). */ struct etnaviv_gem_submit { + struct drm_sched_job sched_job; struct kref refcount; struct etnaviv_gpu *gpu; struct dma_fence *out_fence, *in_fence; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 919c8dc39f32..0bc89e4daade 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -22,6 +22,7 @@ #include "etnaviv_gpu.h" #include "etnaviv_gem.h" #include "etnaviv_perfmon.h" +#include "etnaviv_sched.h" /* * Cmdstream submission: @@ -381,8 +382,13 @@ static void submit_cleanup(struct kref *kref) if (submit->in_fence) dma_fence_put(submit->in_fence); - if (submit->out_fence) + if (submit->out_fence) { + /* first remove from IDR, so fence can not be found anymore */ + mutex_lock(&submit->gpu->fence_idr_lock); + idr_remove(&submit->gpu->fence_idr, submit->out_fence_id); + mutex_unlock(&submit->gpu->fence_idr_lock); dma_fence_put(submit->out_fence); + } kfree(submit->pmrs); kfree(submit); } @@ -395,6 +401,7 @@ void etnaviv_submit_put(struct etnaviv_gem_submit *submit) int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file) { + struct etnaviv_file_private *ctx = file->driver_priv; struct etnaviv_drm_private *priv = dev->dev_private; struct drm_etnaviv_gem_submit *args = data; struct drm_etnaviv_gem_submit_reloc *relocs; @@ -541,7 +548,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, memcpy(submit->cmdbuf.vaddr, stream, args->stream_size); submit->cmdbuf.user_size = ALIGN(args->stream_size, 8); - ret = etnaviv_gpu_submit(gpu, submit); + ret = etnaviv_sched_push_job(&ctx->sched_entity[args->pipe], submit); if (ret) goto err_submit_objects; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index bab6a8286520..fa5063010435 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -26,6 +26,7 @@ #include "etnaviv_gem.h" #include "etnaviv_mmu.h" #include "etnaviv_perfmon.h" +#include "etnaviv_sched.h" #include "common.xml.h" #include "state.xml.h" #include "state_hi.xml.h" @@ -961,9 +962,6 @@ static void recover_worker(struct work_struct *work) mutex_unlock(&gpu->lock); pm_runtime_mark_last_busy(gpu->dev); pm_runtime_put_autosuspend(gpu->dev); - - /* Retire the buffer objects in a work */ - queue_work(gpu->wq, &gpu->retire_work); } static void hangcheck_timer_reset(struct etnaviv_gpu *gpu) @@ -1016,7 +1014,6 @@ static void hangcheck_disable(struct etnaviv_gpu *gpu) /* fence object management */ struct etnaviv_fence { struct etnaviv_gpu *gpu; - int id; struct dma_fence base; }; @@ -1053,11 +1050,6 @@ static void etnaviv_fence_release(struct dma_fence *fence) { struct etnaviv_fence *f = to_etnaviv_fence(fence); - /* first remove from IDR, so fence can not be looked up anymore */ - mutex_lock(&f->gpu->lock); - idr_remove(&f->gpu->fence_idr, f->id); - mutex_unlock(&f->gpu->lock); - kfree_rcu(f, base.rcu); } @@ -1084,11 +1076,6 @@ static struct dma_fence *etnaviv_gpu_fence_alloc(struct etnaviv_gpu *gpu) if (!f) return NULL; - f->id = idr_alloc_cyclic(&gpu->fence_idr, &f->base, 0, INT_MAX, GFP_KERNEL); - if (f->id < 0) { - kfree(f); - return NULL; - } f->gpu = gpu; dma_fence_init(&f->base, &etnaviv_fence_ops, &gpu->fence_spinlock, @@ -1211,31 +1198,6 @@ static void event_free(struct etnaviv_gpu *gpu, unsigned int event) /* * Cmdstream submission/retirement: */ - -static void retire_worker(struct work_struct *work) -{ - struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu, - retire_work); - u32 fence = gpu->completed_fence; - struct etnaviv_gem_submit *submit, *tmp; - LIST_HEAD(retire_list); - - mutex_lock(&gpu->lock); - list_for_each_entry_safe(submit, tmp, &gpu->active_submit_list, node) { - if (!dma_fence_is_signaled(submit->out_fence)) - break; - - list_move(&submit->node, &retire_list); - } - - gpu->retired_fence = fence; - - mutex_unlock(&gpu->lock); - - list_for_each_entry_safe(submit, tmp, &retire_list, node) - etnaviv_submit_put(submit); -} - int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, u32 id, struct timespec *timeout) { @@ -1243,18 +1205,15 @@ int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, int ret; /* - * Look up the fence and take a reference. The mutex only synchronizes - * the IDR lookup with the fence release. We might still find a fence + * Look up the fence and take a reference. We might still find a fence * whose refcount has already dropped to zero. dma_fence_get_rcu * pretends we didn't find a fence in that case. */ - ret = mutex_lock_interruptible(&gpu->lock); - if (ret) - return ret; + rcu_read_lock(); fence = idr_find(&gpu->fence_idr, id); if (fence) fence = dma_fence_get_rcu(fence); - mutex_unlock(&gpu->lock); + rcu_read_unlock(); if (!fence) return 0; @@ -1279,7 +1238,7 @@ int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, /* * Wait for an object to become inactive. This, on it's own, is not race - * free: the object is moved by the retire worker off the active list, and + * free: the object is moved by the scheduler off the active list, and * then the iova is put. Moreover, the object could be re-submitted just * after we notice that it's become inactive. * @@ -1368,15 +1327,16 @@ static void sync_point_perfmon_sample_post(struct etnaviv_gpu *gpu, /* add bo's to gpu's ring, and kick gpu: */ -int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, - struct etnaviv_gem_submit *submit) +struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit) { + struct etnaviv_gpu *gpu = submit->gpu; + struct dma_fence *gpu_fence; unsigned int i, nr_events = 1, event[3]; int ret; ret = pm_runtime_get_sync(gpu->dev); if (ret < 0) - return ret; + return NULL; submit->runtime_resumed = true; /* @@ -1392,22 +1352,20 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, ret = event_alloc(gpu, nr_events, event); if (ret) { DRM_ERROR("no free events\n"); - return ret; + return NULL; } mutex_lock(&gpu->lock); - submit->out_fence = etnaviv_gpu_fence_alloc(gpu); - if (!submit->out_fence) { + gpu_fence = etnaviv_gpu_fence_alloc(gpu); + if (!gpu_fence) { for (i = 0; i < nr_events; i++) event_free(gpu, event[i]); - ret = -ENOMEM; goto out_unlock; } - submit->out_fence_id = to_etnaviv_fence(submit->out_fence)->id; - gpu->active_fence = submit->out_fence->seqno; + gpu->active_fence = gpu_fence->seqno; if (submit->nr_pmrs) { gpu->event[event[1]].sync_point = &sync_point_perfmon_sample_pre; @@ -1416,8 +1374,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, etnaviv_sync_point_queue(gpu, event[1]); } - kref_get(&submit->refcount); - gpu->event[event[0]].fence = submit->out_fence; + gpu->event[event[0]].fence = gpu_fence; etnaviv_buffer_queue(gpu, submit->exec_state, event[0], &submit->cmdbuf); @@ -1428,15 +1385,12 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, etnaviv_sync_point_queue(gpu, event[2]); } - list_add_tail(&submit->node, &gpu->active_submit_list); - hangcheck_timer_reset(gpu); - ret = 0; out_unlock: mutex_unlock(&gpu->lock); - return ret; + return gpu_fence; } static void sync_point_worker(struct work_struct *work) @@ -1527,9 +1481,6 @@ static irqreturn_t irq_handler(int irq, void *data) event_free(gpu, event); } - /* Retire the buffer objects in a work */ - queue_work(gpu->wq, &gpu->retire_work); - ret = IRQ_HANDLED; } @@ -1701,22 +1652,22 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master, gpu->wq = alloc_ordered_workqueue(dev_name(dev), 0); if (!gpu->wq) { - if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) - thermal_cooling_device_unregister(gpu->cooling); - return -ENOMEM; + ret = -ENOMEM; + goto out_thermal; } + ret = etnaviv_sched_init(gpu); + if (ret) + goto out_workqueue; + #ifdef CONFIG_PM ret = pm_runtime_get_sync(gpu->dev); #else ret = etnaviv_gpu_clk_enable(gpu); #endif - if (ret < 0) { - destroy_workqueue(gpu->wq); - if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) - thermal_cooling_device_unregister(gpu->cooling); - return ret; - } + if (ret < 0) + goto out_sched; + gpu->drm = drm; gpu->fence_context = dma_fence_context_alloc(1); @@ -1724,7 +1675,6 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master, spin_lock_init(&gpu->fence_spinlock); INIT_LIST_HEAD(&gpu->active_submit_list); - INIT_WORK(&gpu->retire_work, retire_worker); INIT_WORK(&gpu->sync_point_work, sync_point_worker); INIT_WORK(&gpu->recover_work, recover_worker); init_waitqueue_head(&gpu->fence_event); @@ -1737,6 +1687,18 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master, pm_runtime_put_autosuspend(gpu->dev); return 0; + +out_sched: + etnaviv_sched_fini(gpu); + +out_workqueue: + destroy_workqueue(gpu->wq); + +out_thermal: + if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) + thermal_cooling_device_unregister(gpu->cooling); + + return ret; } static void etnaviv_gpu_unbind(struct device *dev, struct device *master, @@ -1751,6 +1713,8 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master, flush_workqueue(gpu->wq); destroy_workqueue(gpu->wq); + etnaviv_sched_fini(gpu); + #ifdef CONFIG_PM pm_runtime_get_sync(gpu->dev); pm_runtime_put_sync_suspend(gpu->dev); @@ -1803,6 +1767,7 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev) gpu->dev = &pdev->dev; mutex_init(&gpu->lock); + mutex_init(&gpu->fence_idr_lock); /* Map registers: */ gpu->mmio = etnaviv_ioremap(pdev, NULL, dev_name(gpu->dev)); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 0170eb0a0923..02f7ffa34f3b 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -108,6 +108,7 @@ struct etnaviv_gpu { struct etnaviv_chip_identity identity; struct etnaviv_file_private *lastctx; struct workqueue_struct *wq; + struct drm_gpu_scheduler sched; /* 'ring'-buffer: */ struct etnaviv_cmdbuf buffer; @@ -128,18 +129,15 @@ struct etnaviv_gpu { u32 idle_mask; /* Fencing support */ + struct mutex fence_idr_lock; struct idr fence_idr; u32 next_fence; u32 active_fence; u32 completed_fence; - u32 retired_fence; wait_queue_head_t fence_event; u64 fence_context; spinlock_t fence_spinlock; - /* worker for handling active-list retiring: */ - struct work_struct retire_work; - /* worker for handling 'sync' points: */ struct work_struct sync_point_work; int sync_point_event; @@ -182,11 +180,6 @@ static inline bool fence_completed(struct etnaviv_gpu *gpu, u32 fence) return fence_after_eq(gpu->completed_fence, fence); } -static inline bool fence_retired(struct etnaviv_gpu *gpu, u32 fence) -{ - return fence_after_eq(gpu->retired_fence, fence); -} - int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value); int etnaviv_gpu_init(struct etnaviv_gpu *gpu); @@ -203,8 +196,7 @@ int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, u32 fence, struct timespec *timeout); int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu, struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout); -int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, - struct etnaviv_gem_submit *submit); +struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit); int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu); void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu); int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c new file mode 100644 index 000000000000..143c3eca80b0 --- /dev/null +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2017 Etnaviv Project + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include + +#include "etnaviv_drv.h" +#include "etnaviv_gem.h" +#include "etnaviv_gpu.h" + +static int etnaviv_job_hang_limit = 0; +module_param_named(job_hang_limit, etnaviv_job_hang_limit, int , 0444); +static int etnaviv_hw_jobs_limit = 2; +module_param_named(hw_job_limit, etnaviv_hw_jobs_limit, int , 0444); + +static inline +struct etnaviv_gem_submit *to_etnaviv_submit(struct drm_sched_job *sched_job) +{ + return container_of(sched_job, struct etnaviv_gem_submit, sched_job); +} + +struct dma_fence *etnaviv_sched_dependency(struct drm_sched_job *sched_job, + struct drm_sched_entity *entity) +{ + return NULL; +} + +struct dma_fence *etnaviv_sched_run_job(struct drm_sched_job *sched_job) +{ + struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); + struct dma_fence *fence; + + mutex_lock(&submit->gpu->lock); + list_add_tail(&submit->node, &submit->gpu->active_submit_list); + mutex_unlock(&submit->gpu->lock); + + fence = etnaviv_gpu_submit(submit); + if (!fence) { + etnaviv_submit_put(submit); + return NULL; + } + + return fence; +} + +static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job) +{ + /* this replaces the hangcheck */ +} + +static void etnaviv_sched_free_job(struct drm_sched_job *sched_job) +{ + struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); + + mutex_lock(&submit->gpu->lock); + list_del(&submit->node); + mutex_unlock(&submit->gpu->lock); + + etnaviv_submit_put(submit); +} + +static const struct drm_sched_backend_ops etnaviv_sched_ops = { + .dependency = etnaviv_sched_dependency, + .run_job = etnaviv_sched_run_job, + .timedout_job = etnaviv_sched_timedout_job, + .free_job = etnaviv_sched_free_job, +}; + +int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity, + struct etnaviv_gem_submit *submit) +{ + int ret; + + ret = drm_sched_job_init(&submit->sched_job, &submit->gpu->sched, + sched_entity, submit->cmdbuf.ctx); + if (ret) + return ret; + + submit->out_fence = dma_fence_get(&submit->sched_job.s_fence->finished); + mutex_lock(&submit->gpu->fence_idr_lock); + submit->out_fence_id = idr_alloc_cyclic(&submit->gpu->fence_idr, + submit->out_fence, 0, + INT_MAX, GFP_KERNEL); + mutex_unlock(&submit->gpu->fence_idr_lock); + if (submit->out_fence_id < 0) + return -ENOMEM; + + /* the scheduler holds on to the job now */ + kref_get(&submit->refcount); + + drm_sched_entity_push_job(&submit->sched_job, sched_entity); + + return 0; +} + +int etnaviv_sched_init(struct etnaviv_gpu *gpu) +{ + int ret; + + ret = drm_sched_init(&gpu->sched, &etnaviv_sched_ops, + etnaviv_hw_jobs_limit, etnaviv_job_hang_limit, + msecs_to_jiffies(500), dev_name(gpu->dev)); + if (ret) + return ret; + + return 0; +} + +void etnaviv_sched_fini(struct etnaviv_gpu *gpu) +{ + drm_sched_fini(&gpu->sched); +} diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.h b/drivers/gpu/drm/etnaviv/etnaviv_sched.h new file mode 100644 index 000000000000..097635fa78ae --- /dev/null +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017 Etnaviv Project + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __ETNAVIV_SCHED_H__ +#define __ETNAVIV_SCHED_H__ + +#include + +struct etnaviv_gpu; + +static inline +struct etnaviv_gem_submit *to_etnaviv_submit(struct drm_sched_job *sched_job) +{ + return container_of(sched_job, struct etnaviv_gem_submit, sched_job); +} + +int etnaviv_sched_init(struct etnaviv_gpu *gpu); +void etnaviv_sched_fini(struct etnaviv_gpu *gpu); +int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity, + struct etnaviv_gem_submit *submit); + +#endif /* __ETNAVIV_SCHED_H__ */ -- cgit v1.2.3 From 683da226f88dde7bf68940c21418995b63baae2f Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 4 Dec 2017 19:24:06 +0100 Subject: drm/etnaviv: move dependency handling to scheduler Move the fence dependency handling to the scheduler where it belongs. Jobs with unsignaled dependencies just get to sit in the scheduler queue without holding any locks. Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gem.h | 3 ++ drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 38 ++++++++++++---------- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 48 ---------------------------- drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 3 -- drivers/gpu/drm/etnaviv/etnaviv_sched.c | 45 ++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h index ae352f2a77f9..93e696fcc14f 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h @@ -94,6 +94,9 @@ struct etnaviv_gem_submit_bo { u32 flags; struct etnaviv_gem_object *obj; struct etnaviv_vram_mapping *mapping; + struct dma_fence *excl; + unsigned int nr_shared; + struct dma_fence **shared; }; /* Created per submit-ioctl, to track bo's and cmdstream bufs, etc, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 0bc89e4daade..2e278a69f3f0 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -170,29 +170,33 @@ fail: return ret; } -static int submit_fence_sync(const struct etnaviv_gem_submit *submit) +static int submit_fence_sync(struct etnaviv_gem_submit *submit) { - unsigned int context = submit->gpu->fence_context; int i, ret = 0; for (i = 0; i < submit->nr_bos; i++) { - struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; - bool write = submit->bos[i].flags & ETNA_SUBMIT_BO_WRITE; - bool explicit = !!(submit->flags & ETNA_SUBMIT_NO_IMPLICIT); + struct etnaviv_gem_submit_bo *bo = &submit->bos[i]; + struct reservation_object *robj = bo->obj->resv; - ret = etnaviv_gpu_fence_sync_obj(etnaviv_obj, context, write, - explicit); - if (ret) - break; - } + if (!(bo->flags & ETNA_SUBMIT_BO_WRITE)) { + ret = reservation_object_reserve_shared(robj); + if (ret) + return ret; + } + + if (submit->flags & ETNA_SUBMIT_NO_IMPLICIT) + continue; + + if (bo->flags & ETNA_SUBMIT_BO_WRITE) { + ret = reservation_object_get_fences_rcu(robj, &bo->excl, + &bo->nr_shared, + &bo->shared); + if (ret) + return ret; + } else { + bo->excl = reservation_object_get_excl_rcu(robj); + } - if (submit->flags & ETNA_SUBMIT_FENCE_FD_IN) { - /* - * Wait if the fence is from a foreign context, or if the fence - * array contains any fence from a foreign context. - */ - if (!dma_fence_match_context(submit->in_fence, context)) - ret = dma_fence_wait(submit->in_fence, true); } return ret; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index fa5063010435..22a09c0680d6 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1084,54 +1084,6 @@ static struct dma_fence *etnaviv_gpu_fence_alloc(struct etnaviv_gpu *gpu) return &f->base; } -int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj, - unsigned int context, bool exclusive, bool explicit) -{ - struct reservation_object *robj = etnaviv_obj->resv; - struct reservation_object_list *fobj; - struct dma_fence *fence; - int i, ret; - - if (!exclusive) { - ret = reservation_object_reserve_shared(robj); - if (ret) - return ret; - } - - if (explicit) - return 0; - - /* - * If we have any shared fences, then the exclusive fence - * should be ignored as it will already have been signalled. - */ - fobj = reservation_object_get_list(robj); - if (!fobj || fobj->shared_count == 0) { - /* Wait on any existing exclusive fence which isn't our own */ - fence = reservation_object_get_excl(robj); - if (fence && fence->context != context) { - ret = dma_fence_wait(fence, true); - if (ret) - return ret; - } - } - - if (!exclusive || !fobj) - return 0; - - for (i = 0; i < fobj->shared_count; i++) { - fence = rcu_dereference_protected(fobj->shared[i], - reservation_object_held(robj)); - if (fence->context != context) { - ret = dma_fence_wait(fence, true); - if (ret) - return ret; - } - } - - return 0; -} - /* * event management: */ diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 02f7ffa34f3b..f5c6dbe026d6 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -188,9 +188,6 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu); int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m); #endif -int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj, - unsigned int context, bool exclusive, bool implicit); - void etnaviv_gpu_retire(struct etnaviv_gpu *gpu); int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, u32 fence, struct timespec *timeout); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index 143c3eca80b0..26e139786c7a 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -35,6 +35,51 @@ struct etnaviv_gem_submit *to_etnaviv_submit(struct drm_sched_job *sched_job) struct dma_fence *etnaviv_sched_dependency(struct drm_sched_job *sched_job, struct drm_sched_entity *entity) { + struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); + struct dma_fence *fence; + int i; + + if (unlikely(submit->in_fence)) { + fence = submit->in_fence; + submit->in_fence = NULL; + + if (!dma_fence_is_signaled(fence)) + return fence; + + dma_fence_put(fence); + } + + for (i = 0; i < submit->nr_bos; i++) { + struct etnaviv_gem_submit_bo *bo = &submit->bos[i]; + int j; + + if (bo->excl) { + fence = bo->excl; + bo->excl = NULL; + + if (!dma_fence_is_signaled(fence)) + return fence; + + dma_fence_put(fence); + } + + for (j = 0; j < bo->nr_shared; j++) { + if (!bo->shared[j]) + continue; + + fence = bo->shared[j]; + bo->shared[j] = NULL; + + if (!dma_fence_is_signaled(fence)) + return fence; + + dma_fence_put(fence); + } + kfree(bo->shared); + bo->nr_shared = 0; + bo->shared = NULL; + } + return NULL; } -- cgit v1.2.3 From e0580254ae5c70f9fad3e24c20b92287ad817d8e Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 5 Dec 2017 10:55:02 +0100 Subject: drm/etnaviv: lock BOs after all other submit work is done Populating objects, adding them to the GPU VM and patching/validating the command stream might take a lot of CPU time. There is no reason to hold all object reservations during that time. Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 2e278a69f3f0..83339e0335ff 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -514,10 +514,6 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, if (ret) goto err_submit_objects; - ret = submit_lock_objects(submit, &ticket); - if (ret) - goto err_submit_objects; - if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4, relocs, args->nr_relocs)) { ret = -EINVAL; @@ -532,10 +528,6 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, } } - ret = submit_fence_sync(submit); - if (ret) - goto err_submit_objects; - ret = submit_pin_objects(submit); if (ret) goto err_submit_objects; @@ -552,6 +544,14 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, memcpy(submit->cmdbuf.vaddr, stream, args->stream_size); submit->cmdbuf.user_size = ALIGN(args->stream_size, 8); + ret = submit_lock_objects(submit, &ticket); + if (ret) + goto err_submit_objects; + + ret = submit_fence_sync(submit); + if (ret) + goto err_submit_objects; + ret = etnaviv_sched_push_job(&ctx->sched_entity[args->pipe], submit); if (ret) goto err_submit_objects; -- cgit v1.2.3 From 6d7a20c0776036115c6e22bc673d645d524c4b8a Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 6 Dec 2017 10:53:27 +0100 Subject: drm/etnaviv: replace hangcheck with scheduler timeout This replaces the etnaviv internal hangcheck logic with the job timeout handling provided by the DRM scheduler. This simplifies the driver further and allows to replay jobs after a GPU reset, so only minimal state is lost. This introduces a user-visible change in that we don't allow jobs to run indefinitely as long as they make progress anymore, as this introduces quality of service issues when multiple processes are using the GPU. Userspace is now responsible to flush jobs in a way that the finish in a reasonable time, where reasonable is currently defined as less than 500ms. Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_dump.c | 21 ++++++- drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 1 - drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 89 ++++------------------------ drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 11 +--- drivers/gpu/drm/etnaviv/etnaviv_sched.c | 43 +++++++------- 5 files changed, 51 insertions(+), 114 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c index 6d0909c589d1..48aef6cf6a42 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c @@ -20,9 +20,13 @@ #include "etnaviv_gem.h" #include "etnaviv_gpu.h" #include "etnaviv_mmu.h" +#include "etnaviv_sched.h" #include "state.xml.h" #include "state_hi.xml.h" +static bool etnaviv_dump_core = true; +module_param_named(dump_core, etnaviv_dump_core, bool, 0600); + struct core_dump_iterator { void *start; struct etnaviv_dump_object_header *hdr; @@ -121,10 +125,16 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) struct etnaviv_vram_mapping *vram; struct etnaviv_gem_object *obj; struct etnaviv_gem_submit *submit; + struct drm_sched_job *s_job; unsigned int n_obj, n_bomap_pages; size_t file_size, mmu_size; __le64 *bomap, *bomap_start; + /* Only catch the first event, or when manually re-armed */ + if (!etnaviv_dump_core) + return; + etnaviv_dump_core = false; + mmu_size = etnaviv_iommu_dump_size(gpu->mmu); /* We always dump registers, mmu, ring and end marker */ @@ -135,10 +145,13 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) mmu_size + gpu->buffer.size; /* Add in the active command buffers */ - list_for_each_entry(submit, &gpu->active_submit_list, node) { + spin_lock(&gpu->sched.job_list_lock); + list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) { + submit = to_etnaviv_submit(s_job); file_size += submit->cmdbuf.size; n_obj++; } + spin_unlock(&gpu->sched.job_list_lock); /* Add in the active buffer objects */ list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) { @@ -180,10 +193,14 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) gpu->buffer.size, etnaviv_cmdbuf_get_va(&gpu->buffer)); - list_for_each_entry(submit, &gpu->active_submit_list, node) + spin_lock(&gpu->sched.job_list_lock); + list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) { + submit = to_etnaviv_submit(s_job); etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, submit->cmdbuf.vaddr, submit->cmdbuf.size, etnaviv_cmdbuf_get_va(&submit->cmdbuf)); + } + spin_unlock(&gpu->sched.job_list_lock); /* Reserve space for the bomap */ if (n_bomap_pages) { diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 83339e0335ff..46ecd3e66ac9 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -542,7 +542,6 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, goto err_submit_objects; memcpy(submit->cmdbuf.vaddr, stream, args->stream_size); - submit->cmdbuf.user_size = ALIGN(args->stream_size, 8); ret = submit_lock_objects(submit, &ticket); if (ret) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 22a09c0680d6..1309de3c7190 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -41,9 +41,6 @@ static const struct platform_device_id gpu_ids[] = { { }, }; -static bool etnaviv_dump_core = true; -module_param_named(dump_core, etnaviv_dump_core, bool, 0600); - /* * Driver functions: */ @@ -919,38 +916,24 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m) } #endif -/* - * Hangcheck detection for locked gpu: - */ -static void recover_worker(struct work_struct *work) +void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu) { - struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu, - recover_work); unsigned long flags; unsigned int i = 0; - dev_err(gpu->dev, "hangcheck recover!\n"); + dev_err(gpu->dev, "recover hung GPU!\n"); if (pm_runtime_get_sync(gpu->dev) < 0) return; mutex_lock(&gpu->lock); - /* Only catch the first event, or when manually re-armed */ - if (etnaviv_dump_core) { - etnaviv_core_dump(gpu); - etnaviv_dump_core = false; - } - etnaviv_hw_reset(gpu); /* complete all events, the GPU won't do it after the reset */ spin_lock_irqsave(&gpu->event_spinlock, flags); - for_each_set_bit_from(i, gpu->event_bitmap, ETNA_NR_EVENTS) { - dma_fence_signal(gpu->event[i].fence); - gpu->event[i].fence = NULL; + for_each_set_bit_from(i, gpu->event_bitmap, ETNA_NR_EVENTS) complete(&gpu->event_free); - } bitmap_zero(gpu->event_bitmap, ETNA_NR_EVENTS); spin_unlock_irqrestore(&gpu->event_spinlock, flags); gpu->completed_fence = gpu->active_fence; @@ -964,53 +947,6 @@ static void recover_worker(struct work_struct *work) pm_runtime_put_autosuspend(gpu->dev); } -static void hangcheck_timer_reset(struct etnaviv_gpu *gpu) -{ - DBG("%s", dev_name(gpu->dev)); - mod_timer(&gpu->hangcheck_timer, - round_jiffies_up(jiffies + DRM_ETNAVIV_HANGCHECK_JIFFIES)); -} - -static void hangcheck_handler(struct timer_list *t) -{ - struct etnaviv_gpu *gpu = from_timer(gpu, t, hangcheck_timer); - u32 fence = gpu->completed_fence; - bool progress = false; - - if (fence != gpu->hangcheck_fence) { - gpu->hangcheck_fence = fence; - progress = true; - } - - if (!progress) { - u32 dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); - int change = dma_addr - gpu->hangcheck_dma_addr; - - if (change < 0 || change > 16) { - gpu->hangcheck_dma_addr = dma_addr; - progress = true; - } - } - - if (!progress && fence_after(gpu->active_fence, fence)) { - dev_err(gpu->dev, "hangcheck detected gpu lockup!\n"); - dev_err(gpu->dev, " completed fence: %u\n", fence); - dev_err(gpu->dev, " active fence: %u\n", - gpu->active_fence); - queue_work(gpu->wq, &gpu->recover_work); - } - - /* if still more pending work, reset the hangcheck timer: */ - if (fence_after(gpu->active_fence, gpu->hangcheck_fence)) - hangcheck_timer_reset(gpu); -} - -static void hangcheck_disable(struct etnaviv_gpu *gpu) -{ - del_timer_sync(&gpu->hangcheck_timer); - cancel_work_sync(&gpu->recover_work); -} - /* fence object management */ struct etnaviv_fence { struct etnaviv_gpu *gpu; @@ -1286,10 +1222,12 @@ struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit) unsigned int i, nr_events = 1, event[3]; int ret; - ret = pm_runtime_get_sync(gpu->dev); - if (ret < 0) - return NULL; - submit->runtime_resumed = true; + if (!submit->runtime_resumed) { + ret = pm_runtime_get_sync(gpu->dev); + if (ret < 0) + return NULL; + submit->runtime_resumed = true; + } /* * if there are performance monitor requests we need to have @@ -1327,6 +1265,7 @@ struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit) } gpu->event[event[0]].fence = gpu_fence; + submit->cmdbuf.user_size = submit->cmdbuf.size - 8; etnaviv_buffer_queue(gpu, submit->exec_state, event[0], &submit->cmdbuf); @@ -1337,8 +1276,6 @@ struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit) etnaviv_sync_point_queue(gpu, event[2]); } - hangcheck_timer_reset(gpu); - out_unlock: mutex_unlock(&gpu->lock); @@ -1626,13 +1563,9 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master, idr_init(&gpu->fence_idr); spin_lock_init(&gpu->fence_spinlock); - INIT_LIST_HEAD(&gpu->active_submit_list); INIT_WORK(&gpu->sync_point_work, sync_point_worker); - INIT_WORK(&gpu->recover_work, recover_worker); init_waitqueue_head(&gpu->fence_event); - timer_setup(&gpu->hangcheck_timer, hangcheck_handler, TIMER_DEFERRABLE); - priv->gpu[priv->num_gpus++] = gpu; pm_runtime_mark_last_busy(gpu->dev); @@ -1660,8 +1593,6 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master, DBG("%s", dev_name(gpu->dev)); - hangcheck_disable(gpu); - flush_workqueue(gpu->wq); destroy_workqueue(gpu->wq); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index f5c6dbe026d6..186f7c7408b5 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -123,9 +123,6 @@ struct etnaviv_gpu { struct completion event_free; spinlock_t event_spinlock; - /* list of currently in-flight command buffers */ - struct list_head active_submit_list; - u32 idle_mask; /* Fencing support */ @@ -153,13 +150,6 @@ struct etnaviv_gpu { struct clk *clk_core; struct clk *clk_shader; - /* Hang Detction: */ -#define DRM_ETNAVIV_HANGCHECK_PERIOD 500 /* in ms */ -#define DRM_ETNAVIV_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_ETNAVIV_HANGCHECK_PERIOD) - struct timer_list hangcheck_timer; - u32 hangcheck_fence; - u32 hangcheck_dma_addr; - struct work_struct recover_work; unsigned int freq_scale; unsigned long base_rate_core; unsigned long base_rate_shader; @@ -188,6 +178,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu); int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m); #endif +void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu); void etnaviv_gpu_retire(struct etnaviv_gpu *gpu); int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, u32 fence, struct timespec *timeout); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index 26e139786c7a..3e334735ac17 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -14,24 +14,19 @@ * this program. If not, see . */ -#include #include #include "etnaviv_drv.h" +#include "etnaviv_dump.h" #include "etnaviv_gem.h" #include "etnaviv_gpu.h" +#include "etnaviv_sched.h" static int etnaviv_job_hang_limit = 0; module_param_named(job_hang_limit, etnaviv_job_hang_limit, int , 0444); static int etnaviv_hw_jobs_limit = 2; module_param_named(hw_job_limit, etnaviv_hw_jobs_limit, int , 0444); -static inline -struct etnaviv_gem_submit *to_etnaviv_submit(struct drm_sched_job *sched_job) -{ - return container_of(sched_job, struct etnaviv_gem_submit, sched_job); -} - struct dma_fence *etnaviv_sched_dependency(struct drm_sched_job *sched_job, struct drm_sched_entity *entity) { @@ -86,34 +81,38 @@ struct dma_fence *etnaviv_sched_dependency(struct drm_sched_job *sched_job, struct dma_fence *etnaviv_sched_run_job(struct drm_sched_job *sched_job) { struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); - struct dma_fence *fence; - - mutex_lock(&submit->gpu->lock); - list_add_tail(&submit->node, &submit->gpu->active_submit_list); - mutex_unlock(&submit->gpu->lock); + struct dma_fence *fence = NULL; - fence = etnaviv_gpu_submit(submit); - if (!fence) { - etnaviv_submit_put(submit); - return NULL; - } + if (likely(!sched_job->s_fence->finished.error)) + fence = etnaviv_gpu_submit(submit); + else + dev_dbg(submit->gpu->dev, "skipping bad job\n"); return fence; } static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job) { - /* this replaces the hangcheck */ + struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); + struct etnaviv_gpu *gpu = submit->gpu; + + /* block scheduler */ + kthread_park(gpu->sched.thread); + drm_sched_hw_job_reset(&gpu->sched, sched_job); + + /* get the GPU back into the init state */ + etnaviv_core_dump(gpu); + etnaviv_gpu_recover_hang(gpu); + + /* restart scheduler after GPU is usable again */ + drm_sched_job_recovery(&gpu->sched); + kthread_unpark(gpu->sched.thread); } static void etnaviv_sched_free_job(struct drm_sched_job *sched_job) { struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); - mutex_lock(&submit->gpu->lock); - list_del(&submit->node); - mutex_unlock(&submit->gpu->lock); - etnaviv_submit_put(submit); } -- cgit v1.2.3 From ba5a42196b3e73a734f934e479e573a4dfd40dc5 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 18 Jan 2018 12:14:14 +0100 Subject: drm/etnaviv: use correct format specifier for size_t Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c index d113fe06e6b5..49e049713a52 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c @@ -29,7 +29,7 @@ static void etnaviv_domain_unmap(struct etnaviv_iommu_domain *domain, size_t pgsize = SZ_4K; if (!IS_ALIGNED(iova | size, pgsize)) { - pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n", + pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%zx\n", iova, size, pgsize); return; } @@ -54,7 +54,7 @@ static int etnaviv_domain_map(struct etnaviv_iommu_domain *domain, int ret = 0; if (!IS_ALIGNED(iova | paddr | size, pgsize)) { - pr_err("unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%x\n", + pr_err("unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%zx\n", iova, &paddr, size, pgsize); return -EINVAL; } -- cgit v1.2.3 From 246774d17fc05a9b33c769c937003cc73d258674 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 24 Jan 2018 15:30:29 +0100 Subject: drm/etnaviv: remove the need for a gpu-subsystem DT node The module autoloading can be triggered through the GPU core nodes and the necessary platform device for the DRM toplevel device will be instantiated on module init. Suggested-by: Rob Herring Signed-off-by: Lucas Stach Reviewed-by: Rob Herring --- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 36 ++++++++++++++++++----------------- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 1 + 2 files changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index 8a73414682b2..ab50090d066c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -653,25 +653,21 @@ static int compare_str(struct device *dev, void *data) static int etnaviv_pdev_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; struct component_match *match = NULL; dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (node) { + if (!dev->platform_data) { struct device_node *core_node; - int i; - for (i = 0; ; i++) { - core_node = of_parse_phandle(node, "cores", i); - if (!core_node) - break; + for_each_compatible_node(core_node, NULL, "vivante,gc") { + if (!of_device_is_available(core_node)) + continue; drm_of_component_match_add(&pdev->dev, &match, compare_of, core_node); - of_node_put(core_node); } - } else if (dev->platform_data) { + } else { char **names = dev->platform_data; unsigned i; @@ -689,25 +685,18 @@ static int etnaviv_pdev_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id dt_match[] = { - { .compatible = "fsl,imx-gpu-subsystem" }, - { .compatible = "marvell,dove-gpu-subsystem" }, - {} -}; -MODULE_DEVICE_TABLE(of, dt_match); - static struct platform_driver etnaviv_platform_driver = { .probe = etnaviv_pdev_probe, .remove = etnaviv_pdev_remove, .driver = { .name = "etnaviv", - .of_match_table = dt_match, }, }; static int __init etnaviv_init(void) { int ret; + struct device_node *np; etnaviv_validate_init(); @@ -719,6 +708,19 @@ static int __init etnaviv_init(void) if (ret != 0) platform_driver_unregister(&etnaviv_gpu_driver); + /* + * If the DT contains at least one available GPU device, instantiate + * the DRM platform device. + */ + for_each_compatible_node(np, NULL, "vivante,gc") { + if (!of_device_is_available(np)) + continue; + + platform_device_register_simple("etnaviv", -1, NULL, 0); + of_node_put(np); + break; + } + return ret; } module_init(etnaviv_init); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 1309de3c7190..94fa3d3244fb 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1637,6 +1637,7 @@ static const struct of_device_id etnaviv_gpu_match[] = { }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, etnaviv_gpu_match); static int etnaviv_gpu_platform_probe(struct platform_device *pdev) { -- cgit v1.2.3 From 18a5b052bb1ae77453c5e50fffe3470ced9ed82f Mon Sep 17 00:00:00 2001 From: Ingo van Lil Date: Mon, 12 Feb 2018 12:02:52 +0100 Subject: net: phy: fix wrong mask to phy_modify() When forcing a specific link mode, the PHY driver must clear the existing speed and duplex bits in BMCR while preserving some other control bits. This logic was accidentally inverted with the introduction of phy_modify(). Fixes: fea23fb591cc ("net: phy: convert read-modify-write to phy_modify()") Signed-off-by: Ingo van Lil Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index b13eed21c87d..d39ae77707ef 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1382,7 +1382,7 @@ int genphy_setup_forced(struct phy_device *phydev) ctl |= BMCR_FULLDPLX; return phy_modify(phydev, MII_BMCR, - BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN, ctl); + ~(BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN), ctl); } EXPORT_SYMBOL(genphy_setup_forced); -- cgit v1.2.3 From dd62c236c0fe1166d037485494ec5ff6545480eb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 12 Feb 2018 14:40:00 +0100 Subject: ravb: Remove obsolete explicit clock handling for WoL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, if Wake-on-LAN is enabled, the EtherAVB device's module clock is manually kept running during system suspend, to make sure the device stays active. Since commit 91c719f5ec6671f7 ("soc: renesas: rcar-sysc: Keep wakeup sources active during system suspend") , this workaround is no longer needed. Hence remove all explicit clock handling to keep the device active. Signed-off-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Reviewed-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb_main.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index c87f57ca4437..a95fbd5510d9 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2255,9 +2255,6 @@ static int ravb_wol_setup(struct net_device *ndev) /* Enable MagicPacket */ ravb_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE); - /* Increased clock usage so device won't be suspended */ - clk_enable(priv->clk); - return enable_irq_wake(priv->emac_irq); } @@ -2276,9 +2273,6 @@ static int ravb_wol_restore(struct net_device *ndev) if (ret < 0) return ret; - /* Restore clock usage count */ - clk_disable(priv->clk); - return disable_irq_wake(priv->emac_irq); } -- cgit v1.2.3 From b4580c952e89a332f077038ef19a7582950c082d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 12 Feb 2018 14:42:36 +0100 Subject: sh_eth: Remove obsolete explicit clock handling for WoL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, if Wake-on-LAN is enabled, the SH-ETH device's module clock is manually kept running during system suspend, to make sure the device stays active. Since commits 91c719f5ec6671f7 ("soc: renesas: rcar-sysc: Keep wakeup sources active during system suspend") and 744dddcae84441b1 ("clk: renesas: mstp: Keep wakeup sources active during system suspend"), this workaround is no longer needed. Hence remove all explicit clock handling to keep the device active. Signed-off-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Reviewed-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index a197e11f3a56..92dcf8717fc6 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include @@ -2304,7 +2303,7 @@ static void sh_eth_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) wol->supported = 0; wol->wolopts = 0; - if (mdp->cd->magic && mdp->clk) { + if (mdp->cd->magic) { wol->supported = WAKE_MAGIC; wol->wolopts = mdp->wol_enabled ? WAKE_MAGIC : 0; } @@ -2314,7 +2313,7 @@ static int sh_eth_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) { struct sh_eth_private *mdp = netdev_priv(ndev); - if (!mdp->cd->magic || !mdp->clk || wol->wolopts & ~WAKE_MAGIC) + if (!mdp->cd->magic || wol->wolopts & ~WAKE_MAGIC) return -EOPNOTSUPP; mdp->wol_enabled = !!(wol->wolopts & WAKE_MAGIC); @@ -3153,11 +3152,6 @@ static int sh_eth_drv_probe(struct platform_device *pdev) goto out_release; } - /* Get clock, if not found that's OK but Wake-On-Lan is unavailable */ - mdp->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(mdp->clk)) - mdp->clk = NULL; - ndev->base_addr = res->start; spin_lock_init(&mdp->lock); @@ -3278,7 +3272,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) if (ret) goto out_napi_del; - if (mdp->cd->magic && mdp->clk) + if (mdp->cd->magic) device_set_wakeup_capable(&pdev->dev, 1); /* print device information */ @@ -3331,9 +3325,6 @@ static int sh_eth_wol_setup(struct net_device *ndev) /* Enable MagicPacket */ sh_eth_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE); - /* Increased clock usage so device won't be suspended */ - clk_enable(mdp->clk); - return enable_irq_wake(ndev->irq); } @@ -3359,9 +3350,6 @@ static int sh_eth_wol_restore(struct net_device *ndev) if (ret < 0) return ret; - /* Restore clock usage count */ - clk_disable(mdp->clk); - return disable_irq_wake(ndev->irq); } -- cgit v1.2.3 From 0d3e45bc6507bd1f8728bf586ebd16c2d9e40613 Mon Sep 17 00:00:00 2001 From: Dong Bo Date: Fri, 26 Jan 2018 11:21:49 +0800 Subject: libata: Fix compile warning with ATA_DEBUG enabled This fixs the following comile warnings with ATA_DEBUG enabled, which detected by Linaro GCC 5.2-2015.11: drivers/ata/libata-scsi.c: In function 'ata_scsi_dump_cdb': ./include/linux/kern_levels.h:5:18: warning: format '%d' expects argument of type 'int', but argument 6 has type 'u64 {aka long long unsigned int}' [-Wformat=] tj: Patch hand-applied and description trimmed. Signed-off-by: Dong Bo Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 66be961c93a4..d959b154de4f 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -4282,7 +4282,7 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap, #ifdef ATA_DEBUG struct scsi_device *scsidev = cmd->device; - DPRINTK("CDB (%u:%d,%d,%d) %9ph\n", + DPRINTK("CDB (%u:%d,%d,%lld) %9ph\n", ap->print_id, scsidev->channel, scsidev->id, scsidev->lun, cmd->cmnd); -- cgit v1.2.3 From 8e021a14d908475fea89ef85b5421865f7ad650d Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 12 Feb 2018 17:10:19 +0300 Subject: net: thunderbolt: Tear down connection properly on suspend When suspending to mem or disk the Thunderbolt controller typically goes down as well tearing down the connection automatically. However, when suspend to idle is used this does not happen so we need to make sure the connection is properly disconnected before it can be re-established during resume. Fixes: e69b6c02b4c3 ("net: Add support for networking over Thunderbolt cable") Signed-off-by: Mika Westerberg Cc: stable@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/thunderbolt.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c index ca5e375de27c..71cf9ab72fbc 100644 --- a/drivers/net/thunderbolt.c +++ b/drivers/net/thunderbolt.c @@ -1270,10 +1270,7 @@ static int __maybe_unused tbnet_suspend(struct device *dev) stop_login(net); if (netif_running(net->dev)) { netif_device_detach(net->dev); - tb_ring_stop(net->rx_ring.ring); - tb_ring_stop(net->tx_ring.ring); - tbnet_free_buffers(&net->rx_ring); - tbnet_free_buffers(&net->tx_ring); + tbnet_tear_down(net, true); } return 0; -- cgit v1.2.3 From 027d351c541744c0c780dd5801c63e4b90750b90 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 12 Feb 2018 17:10:20 +0300 Subject: net: thunderbolt: Run disconnect flow asynchronously when logout is received The control channel calls registered callbacks when control messages such as XDomain protocol messages are received. The control channel handling is done in a worker running on system workqueue which means the networking driver can't run tear down flow which includes sending disconnect request and waiting for a reply in the same worker. Otherwise reply is never received (as the work is already running) and the operation times out. To fix this run disconnect ThunderboltIP flow asynchronously once ThunderboltIP logout message is received. Fixes: e69b6c02b4c3 ("net: Add support for networking over Thunderbolt cable") Signed-off-by: Mika Westerberg Cc: stable@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/thunderbolt.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c index 71cf9ab72fbc..e0d6760f3219 100644 --- a/drivers/net/thunderbolt.c +++ b/drivers/net/thunderbolt.c @@ -166,6 +166,8 @@ struct tbnet_ring { * @connected_work: Worker that finalizes the ThunderboltIP connection * setup and enables DMA paths for high speed data * transfers + * @disconnect_work: Worker that handles tearing down the ThunderboltIP + * connection * @rx_hdr: Copy of the currently processed Rx frame. Used when a * network packet consists of multiple Thunderbolt frames. * In host byte order. @@ -190,6 +192,7 @@ struct tbnet { int login_retries; struct delayed_work login_work; struct work_struct connected_work; + struct work_struct disconnect_work; struct thunderbolt_ip_frame_header rx_hdr; struct tbnet_ring rx_ring; atomic_t frame_id; @@ -445,7 +448,7 @@ static int tbnet_handle_packet(const void *buf, size_t size, void *data) case TBIP_LOGOUT: ret = tbnet_logout_response(net, route, sequence, command_id); if (!ret) - tbnet_tear_down(net, false); + queue_work(system_long_wq, &net->disconnect_work); break; default: @@ -659,6 +662,13 @@ static void tbnet_login_work(struct work_struct *work) } } +static void tbnet_disconnect_work(struct work_struct *work) +{ + struct tbnet *net = container_of(work, typeof(*net), disconnect_work); + + tbnet_tear_down(net, false); +} + static bool tbnet_check_frame(struct tbnet *net, const struct tbnet_frame *tf, const struct thunderbolt_ip_frame_header *hdr) { @@ -881,6 +891,7 @@ static int tbnet_stop(struct net_device *dev) napi_disable(&net->napi); + cancel_work_sync(&net->disconnect_work); tbnet_tear_down(net, true); tb_ring_free(net->rx_ring.ring); @@ -1195,6 +1206,7 @@ static int tbnet_probe(struct tb_service *svc, const struct tb_service_id *id) net = netdev_priv(dev); INIT_DELAYED_WORK(&net->login_work, tbnet_login_work); INIT_WORK(&net->connected_work, tbnet_connected_work); + INIT_WORK(&net->disconnect_work, tbnet_disconnect_work); mutex_init(&net->connection_lock); atomic_set(&net->command_id, 0); atomic_set(&net->frame_id, 0); -- cgit v1.2.3 From 3b61e5121d5c4d0ea79fe90ced8df2fe5cb67dc2 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 30 Jan 2018 11:02:55 +0100 Subject: ahci: Add check for device presence (PCIe hot unplug) in ahci_stop_engine() Exit directly with ENODEV, if the AHCI controller is not available anymore. Otherwise a delay of 500ms for each port is added to the remove function while trying to issue a command on the non-existent controller. Signed-off-by: Stefan Roese Cc: Tejun Heo Signed-off-by: Tejun Heo --- drivers/ata/libahci.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index a0de7a38430c..7adcf3caabd0 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -665,6 +665,16 @@ int ahci_stop_engine(struct ata_port *ap) if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) return 0; + /* + * Don't try to issue commands but return with ENODEV if the + * AHCI controller not available anymore (e.g. due to PCIe hot + * unplugging). Otherwise a 500ms delay for each port is added. + */ + if (tmp == 0xffffffff) { + dev_err(ap->host->dev, "AHCI controller unavailable!\n"); + return -ENODEV; + } + /* setting HBA to idle */ tmp &= ~PORT_CMD_START; writel(tmp, port_mmio + PORT_CMD); -- cgit v1.2.3 From 9f2b51db5b551085e26c8af5fbe484d62b891ec9 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 5 Feb 2018 13:50:36 +0200 Subject: ata: libahci: fix comment indentation Indent the numbered item with one space like all other items in the same list. Signed-off-by: Baruch Siach Signed-off-by: Tejun Heo --- drivers/ata/libahci_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 341d0ef82cbd..30cc8f1a31e1 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -340,7 +340,7 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port, * 2) regulator for controlling the targets power (optional) * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, * or for non devicetree enabled platforms a single clock - * 4) phys (optional) + * 4) phys (optional) * * RETURNS: * The allocated ahci_host_priv on success, otherwise an ERR_PTR value -- cgit v1.2.3 From 058f58e235cbe03e923b30ea7c49995a46a8725f Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 3 Feb 2018 20:30:56 -0800 Subject: libata: fix length validation of ATAPI-relayed SCSI commands syzkaller reported a crash in ata_bmdma_fill_sg() when writing to /dev/sg1. The immediate cause was that the ATA command's scatterlist was not DMA-mapped, which causes 'pi - 1' to underflow, resulting in a write to 'qc->ap->bmdma_prd[0xffffffff]'. Strangely though, the flag ATA_QCFLAG_DMAMAP was set in qc->flags. The root cause is that when __ata_scsi_queuecmd() is preparing to relay a SCSI command to an ATAPI device, it doesn't correctly validate the CDB length before copying it into the 16-byte buffer 'cdb' in 'struct ata_queued_cmd'. Namely, it validates the fixed CDB length expected based on the SCSI opcode but not the actual CDB length, which can be larger due to the use of the SG_NEXT_CMD_LEN ioctl. Since 'flags' is the next member in ata_queued_cmd, a buffer overflow corrupts it. Fix it by requiring that the actual CDB length be <= 16 (ATAPI_CDB_LEN). [Really it seems the length should be required to be <= dev->cdb_len, but the current behavior seems to have been intentionally introduced by commit 607126c2a21c ("libata-scsi: be tolerant of 12-byte ATAPI commands in 16-byte CDBs") to work around a userspace bug in mplayer. Probably the workaround is no longer needed (mplayer was fixed in 2007), but continuing to allow lengths to up 16 appears harmless for now.] Here's a reproducer that works in QEMU when /dev/sg1 refers to the CD-ROM drive that qemu-system-x86_64 creates by default: #include #include #include #define SG_NEXT_CMD_LEN 0x2283 int main() { char buf[53] = { [36] = 0x7e, [52] = 0x02 }; int fd = open("/dev/sg1", O_RDWR); ioctl(fd, SG_NEXT_CMD_LEN, &(int){ 17 }); write(fd, buf, sizeof(buf)); } The crash was: BUG: unable to handle kernel paging request at ffff8cb97db37ffc IP: ata_bmdma_fill_sg drivers/ata/libata-sff.c:2623 [inline] IP: ata_bmdma_qc_prep+0xa4/0xc0 drivers/ata/libata-sff.c:2727 PGD fb6c067 P4D fb6c067 PUD 0 Oops: 0002 [#1] SMP CPU: 1 PID: 150 Comm: syz_ata_bmdma_q Not tainted 4.15.0-next-20180202 #99 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.0-20171110_100015-anatol 04/01/2014 [...] Call Trace: ata_qc_issue+0x100/0x1d0 drivers/ata/libata-core.c:5421 ata_scsi_translate+0xc9/0x1a0 drivers/ata/libata-scsi.c:2024 __ata_scsi_queuecmd drivers/ata/libata-scsi.c:4326 [inline] ata_scsi_queuecmd+0x8c/0x210 drivers/ata/libata-scsi.c:4375 scsi_dispatch_cmd+0xa2/0xe0 drivers/scsi/scsi_lib.c:1727 scsi_request_fn+0x24c/0x530 drivers/scsi/scsi_lib.c:1865 __blk_run_queue_uncond block/blk-core.c:412 [inline] __blk_run_queue+0x3a/0x60 block/blk-core.c:432 blk_execute_rq_nowait+0x93/0xc0 block/blk-exec.c:78 sg_common_write.isra.7+0x272/0x5a0 drivers/scsi/sg.c:806 sg_write+0x1ef/0x340 drivers/scsi/sg.c:677 __vfs_write+0x31/0x160 fs/read_write.c:480 vfs_write+0xa7/0x160 fs/read_write.c:544 SYSC_write fs/read_write.c:589 [inline] SyS_write+0x4d/0xc0 fs/read_write.c:581 do_syscall_64+0x5e/0x110 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x21/0x86 Fixes: 607126c2a21c ("libata-scsi: be tolerant of 12-byte ATAPI commands in 16-byte CDBs") Reported-by: syzbot+1ff6f9fcc3c35f1c72a95e26528c8e7e3276e4da@syzkaller.appspotmail.com Cc: # v2.6.24+ Signed-off-by: Eric Biggers Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d959b154de4f..9ae8986bae48 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -4309,7 +4309,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, if (likely((scsi_op != ATA_16) || !atapi_passthru16)) { /* relay SCSI command to ATAPI device */ int len = COMMAND_SIZE(scsi_op); - if (unlikely(len > scmd->cmd_len || len > dev->cdb_len)) + if (unlikely(len > scmd->cmd_len || + len > dev->cdb_len || + scmd->cmd_len > ATAPI_CDB_LEN)) goto bad_cdb_len; xlat_func = atapi_xlat; -- cgit v1.2.3 From 9173e5e80729c8434b8d27531527c5245f4a5594 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 3 Feb 2018 20:33:27 -0800 Subject: libata: remove WARN() for DMA or PIO command without data syzkaller hit a WARN() in ata_qc_issue() when writing to /dev/sg0. This happened because it issued a READ_6 command with no data buffer. Just remove the WARN(), as it doesn't appear indicate a kernel bug. The expected behavior is to fail the command, which the code does. Here's a reproducer that works in QEMU when /dev/sg0 refers to a disk of the default type ("82371SB PIIX3 IDE"): #include #include int main() { char buf[42] = { [36] = 0x8 /* READ_6 */ }; write(open("/dev/sg0", O_RDWR), buf, sizeof(buf)); } Fixes: f92a26365a72 ("libata: change ATA_QCFLAG_DMAMAP semantics") Reported-by: syzbot+f7b556d1766502a69d85071d2ff08bd87be53d0f@syzkaller.appspotmail.com Cc: # v2.6.25+ Signed-off-by: Eric Biggers Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3c09122bf038..61b09968d032 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5401,8 +5401,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc) * We guarantee to LLDs that they will have at least one * non-zero sg if the command is a data command. */ - if (WARN_ON_ONCE(ata_is_data(prot) && - (!qc->sg || !qc->n_elem || !qc->nbytes))) + if (ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes)) goto sys_err; if (ata_is_dma(prot) || (ata_is_pio(prot) && -- cgit v1.2.3 From 2c1ec6fda2d07044cda922ee25337cf5d4b429b3 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 3 Feb 2018 20:33:51 -0800 Subject: libata: don't try to pass through NCQ commands to non-NCQ devices syzkaller hit a WARN() in ata_bmdma_qc_issue() when writing to /dev/sg0. This happened because it issued an ATA pass-through command (ATA_16) where the protocol field indicated that NCQ should be used -- but the device did not support NCQ. We could just remove the WARN() from libata-sff.c, but the real problem seems to be that the SCSI -> ATA translation code passes through NCQ commands without verifying that the device actually supports NCQ. Fix this by adding the appropriate check to ata_scsi_pass_thru(). Here's reproducer that works in QEMU when /dev/sg0 refers to a disk of the default type ("82371SB PIIX3 IDE"): #include #include int main() { char buf[53] = { 0 }; buf[36] = 0x85; /* ATA_16 */ buf[37] = (12 << 1); /* FPDMA */ buf[38] = 0x1; /* Has data */ buf[51] = 0xC8; /* ATA_CMD_READ */ write(open("/dev/sg0", O_RDWR), buf, sizeof(buf)); } Fixes: ee7fb331c3ac ("libata: add support for NCQ commands for SG interface") Reported-by: syzbot+2f69ca28df61bdfc77cd36af2e789850355a221e@syzkaller.appspotmail.com Cc: # v4.4+ Signed-off-by: Eric Biggers Signed-off-by: Tejun Heo --- drivers/ata/libata-scsi.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 9ae8986bae48..89a9d4a2efc8 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3316,6 +3316,12 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) goto invalid_fld; } + /* We may not issue NCQ commands to devices not supporting NCQ */ + if (ata_is_ncq(tf->protocol) && !ata_ncq_enabled(dev)) { + fp = 1; + goto invalid_fld; + } + /* sanity check for pio multi commands */ if ((cdb[1] & 0xe0) && !is_multi_taskfile(tf)) { fp = 1; -- cgit v1.2.3 From da77d76b95a0e8940793f4f7fe12a4a2d2048e39 Mon Sep 17 00:00:00 2001 From: Khiem Nguyen Date: Mon, 5 Feb 2018 04:18:51 +0900 Subject: sata_rcar: Reset SATA PHY when Salvator-X board resumes Because power of Salvator-X board is cut off in suspend, it needs to reset SATA PHY state in resume. Otherwise, SATA partition could not be accessed anymore. Signed-off-by: Khiem Nguyen Signed-off-by: Hien Dang [reinit phy in sata_rcar_resume() function on R-Car Gen3 only] [factor out SATA module init sequence] [fixed the prefix for the subject] Signed-off-by: Yoshihiro Kaneko Signed-off-by: Tejun Heo --- drivers/ata/sata_rcar.c | 63 +++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 80ee2f2a50d0..6f47ca34767d 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -146,6 +146,7 @@ enum sata_rcar_type { RCAR_GEN1_SATA, RCAR_GEN2_SATA, + RCAR_GEN3_SATA, RCAR_R8A7790_ES1_SATA, }; @@ -784,26 +785,11 @@ static void sata_rcar_setup_port(struct ata_host *host) ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << 2); } -static void sata_rcar_init_controller(struct ata_host *host) +static void sata_rcar_init_module(struct sata_rcar_priv *priv) { - struct sata_rcar_priv *priv = host->private_data; void __iomem *base = priv->base; u32 val; - /* reset and setup phy */ - switch (priv->type) { - case RCAR_GEN1_SATA: - sata_rcar_gen1_phy_init(priv); - break; - case RCAR_GEN2_SATA: - case RCAR_R8A7790_ES1_SATA: - sata_rcar_gen2_phy_init(priv); - break; - default: - dev_warn(host->dev, "SATA phy is not initialized\n"); - break; - } - /* SATA-IP reset state */ val = ioread32(base + ATAPI_CONTROL1_REG); val |= ATAPI_CONTROL1_RESET; @@ -824,10 +810,34 @@ static void sata_rcar_init_controller(struct ata_host *host) /* ack and mask */ iowrite32(0, base + SATAINTSTAT_REG); iowrite32(0x7ff, base + SATAINTMASK_REG); + /* enable interrupts */ iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG); } +static void sata_rcar_init_controller(struct ata_host *host) +{ + struct sata_rcar_priv *priv = host->private_data; + void __iomem *base = priv->base; + + /* reset and setup phy */ + switch (priv->type) { + case RCAR_GEN1_SATA: + sata_rcar_gen1_phy_init(priv); + break; + case RCAR_GEN2_SATA: + case RCAR_GEN3_SATA: + case RCAR_R8A7790_ES1_SATA: + sata_rcar_gen2_phy_init(priv); + break; + default: + dev_warn(host->dev, "SATA phy is not initialized\n"); + break; + } + + sata_rcar_init_module(priv); +} + static const struct of_device_id sata_rcar_match[] = { { /* Deprecated by "renesas,sata-r8a7779" */ @@ -856,7 +866,7 @@ static const struct of_device_id sata_rcar_match[] = { }, { .compatible = "renesas,sata-r8a7795", - .data = (void *)RCAR_GEN2_SATA + .data = (void *)RCAR_GEN3_SATA }, { .compatible = "renesas,rcar-gen2-sata", @@ -864,7 +874,7 @@ static const struct of_device_id sata_rcar_match[] = { }, { .compatible = "renesas,rcar-gen3-sata", - .data = (void *)RCAR_GEN2_SATA + .data = (void *)RCAR_GEN3_SATA }, { }, }; @@ -982,11 +992,18 @@ static int sata_rcar_resume(struct device *dev) if (ret) return ret; - /* ack and mask */ - iowrite32(0, base + SATAINTSTAT_REG); - iowrite32(0x7ff, base + SATAINTMASK_REG); - /* enable interrupts */ - iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG); + if (priv->type == RCAR_GEN3_SATA) { + sata_rcar_gen2_phy_init(priv); + sata_rcar_init_module(priv); + } else { + /* ack and mask */ + iowrite32(0, base + SATAINTSTAT_REG); + iowrite32(0x7ff, base + SATAINTMASK_REG); + + /* enable interrupts */ + iowrite32(ATAPI_INT_ENABLE_SATAINT, + base + ATAPI_INT_ENABLE_REG); + } ata_host_resume(host); -- cgit v1.2.3 From 07a2e1cf398187814b405665b19d36425ec7a962 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Mon, 12 Feb 2018 18:20:11 +0100 Subject: net: cavium: fix NULL pointer dereference in cavium_ptp_put Prevent a kernel panic on reboot if ptp_clock is NULL by checking the ptp pointer before using it. Signed-off-by: Jan Glauber Fixes: 8c56df372bc1 ("net: add support for Cavium PTP coprocessor") Cc: Radoslaw Biernacki Cc: Aleksey Makarov Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/common/cavium_ptp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/common/cavium_ptp.c b/drivers/net/ethernet/cavium/common/cavium_ptp.c index c87c9c684a33..d59497a7bdce 100644 --- a/drivers/net/ethernet/cavium/common/cavium_ptp.c +++ b/drivers/net/ethernet/cavium/common/cavium_ptp.c @@ -75,6 +75,8 @@ EXPORT_SYMBOL(cavium_ptp_get); void cavium_ptp_put(struct cavium_ptp *ptp) { + if (!ptp) + return; pci_dev_put(ptp->pdev); } EXPORT_SYMBOL(cavium_ptp_put); -- cgit v1.2.3 From 0a34e4668c508cbbc2d5ef2d9710b145e4c0b27d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 11 Jan 2018 13:38:15 -0800 Subject: nvme: Don't use a stack buffer for keep-alive command In nvme_keep_alive() we pass a request with a pointer to an NVMe command on the stack into blk_execute_rq_nowait(). However, the block layer doesn't guarantee that the request is fully queued before blk_execute_rq_nowait() returns. If not, and the request is queued after nvme_keep_alive() returns, then we'll end up using stack memory that might have been overwritten to form the NVMe command we pass to hardware. Fix this by keeping a special command struct in the nvme_ctrl struct right next to the delayed work struct used for keep-alives. Signed-off-by: Roland Dreier Signed-off-by: Sagi Grimberg --- drivers/nvme/host/core.c | 8 +++----- drivers/nvme/host/nvme.h | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 2fd8688cfa47..6d0490b477c9 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -796,13 +796,9 @@ static void nvme_keep_alive_end_io(struct request *rq, blk_status_t status) static int nvme_keep_alive(struct nvme_ctrl *ctrl) { - struct nvme_command c; struct request *rq; - memset(&c, 0, sizeof(c)); - c.common.opcode = nvme_admin_keep_alive; - - rq = nvme_alloc_request(ctrl->admin_q, &c, BLK_MQ_REQ_RESERVED, + rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd, BLK_MQ_REQ_RESERVED, NVME_QID_ANY); if (IS_ERR(rq)) return PTR_ERR(rq); @@ -834,6 +830,8 @@ void nvme_start_keep_alive(struct nvme_ctrl *ctrl) return; INIT_DELAYED_WORK(&ctrl->ka_work, nvme_keep_alive_work); + memset(&ctrl->ka_cmd, 0, sizeof(ctrl->ka_cmd)); + ctrl->ka_cmd.common.opcode = nvme_admin_keep_alive; schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ); } EXPORT_SYMBOL_GPL(nvme_start_keep_alive); diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 27e31c00b306..0521e4707d1c 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -183,6 +183,7 @@ struct nvme_ctrl { struct work_struct scan_work; struct work_struct async_event_work; struct delayed_work ka_work; + struct nvme_command ka_cmd; struct work_struct fw_act_work; /* Power saving configuration */ -- cgit v1.2.3 From 5b4e64beb6ab40f5d8b44500fe0fc201c25a0f16 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 12 Feb 2018 20:46:28 +0100 Subject: extcon: axp288: Constify the axp288_pwr_up_down_info array Make the axp288_pwr_up_down_info array const char * const, this leads to the following section size changes: .text 0x674 -> 0x664 .data 0x148 -> 0x0f0 .rodata 0x0b4 -> 0x114 Signed-off-by: Hans de Goede Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-axp288.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c index 0a44d43802fe..c8f7b6435679 100644 --- a/drivers/extcon/extcon-axp288.c +++ b/drivers/extcon/extcon-axp288.c @@ -106,7 +106,7 @@ struct axp288_extcon_info { }; /* Power up/down reason string array */ -static char *axp288_pwr_up_down_info[] = { +static const char * const axp288_pwr_up_down_info[] = { "Last wake caused by user pressing the power button", "Last wake caused by a charger insertion", "Last wake caused by a battery insertion", @@ -124,7 +124,7 @@ static char *axp288_pwr_up_down_info[] = { */ static void axp288_extcon_log_rsi(struct axp288_extcon_info *info) { - char **rsi; + const char * const *rsi; unsigned int val, i, clear_mask = 0; int ret; -- cgit v1.2.3 From d82e233cee26ceacb9feb937a21bfb61b1826860 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 12 Feb 2018 20:46:29 +0100 Subject: Revert "extcon: axp288: Redo charger type detection a couple of seconds after probe()" Redoing the charger type detection to give the usb-role-switch code time to properly set the role-switch is no good for mainline, since the usb-role-switch code is not yet in mainline (my bad, sorry). Also once we've that code there are better ways to fix this which are not prone to racing as doing a retry after 2 seconds is. This reverts commit 50082c17bb1455acacd376ae30dff92f2e1addbd. Signed-off-by: Hans de Goede Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-axp288.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c index c8f7b6435679..3ec4c715e240 100644 --- a/drivers/extcon/extcon-axp288.c +++ b/drivers/extcon/extcon-axp288.c @@ -1,7 +1,6 @@ /* * extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver * - * Copyright (C) 2016-2017 Hans de Goede * Copyright (C) 2015 Intel Corporation * Author: Ramakrishna Pallala * @@ -98,11 +97,9 @@ struct axp288_extcon_info { struct device *dev; struct regmap *regmap; struct regmap_irq_chip_data *regmap_irqc; - struct delayed_work det_work; int irq[EXTCON_IRQ_END]; struct extcon_dev *edev; unsigned int previous_cable; - bool first_detect_done; }; /* Power up/down reason string array */ @@ -140,25 +137,6 @@ static void axp288_extcon_log_rsi(struct axp288_extcon_info *info) regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask); } -static void axp288_chrg_detect_complete(struct axp288_extcon_info *info) -{ - /* - * We depend on other drivers to do things like mux the data lines, - * enable/disable vbus based on the id-pin, etc. Sometimes the BIOS has - * not set these things up correctly resulting in the initial charger - * cable type detection giving a wrong result and we end up not charging - * or charging at only 0.5A. - * - * So we schedule a second cable type detection after 2 seconds to - * give the other drivers time to load and do their thing. - */ - if (!info->first_detect_done) { - queue_delayed_work(system_wq, &info->det_work, - msecs_to_jiffies(2000)); - info->first_detect_done = true; - } -} - static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) { int ret, stat, cfg, pwr_stat; @@ -223,8 +201,6 @@ no_vbus: info->previous_cable = cable; } - axp288_chrg_detect_complete(info); - return 0; dev_det_ret: @@ -246,11 +222,8 @@ static irqreturn_t axp288_extcon_isr(int irq, void *data) return IRQ_HANDLED; } -static void axp288_extcon_det_work(struct work_struct *work) +static void axp288_extcon_enable(struct axp288_extcon_info *info) { - struct axp288_extcon_info *info = - container_of(work, struct axp288_extcon_info, det_work.work); - regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, BC_GLOBAL_RUN, 0); /* Enable the charger detection logic */ @@ -272,7 +245,6 @@ static int axp288_extcon_probe(struct platform_device *pdev) info->regmap = axp20x->regmap; info->regmap_irqc = axp20x->regmap_irqc; info->previous_cable = EXTCON_NONE; - INIT_DELAYED_WORK(&info->det_work, axp288_extcon_det_work); platform_set_drvdata(pdev, info); @@ -318,7 +290,7 @@ static int axp288_extcon_probe(struct platform_device *pdev) } /* Start charger cable type detection */ - queue_delayed_work(system_wq, &info->det_work, 0); + axp288_extcon_enable(info); return 0; } -- cgit v1.2.3 From aef17ca1271948ee57cc39b2493d31110cc42625 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 7 Feb 2018 17:49:39 -0800 Subject: hwmon: (k10temp) Only apply temperature offset if result is positive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A user reports a really bad temperature on Ryzen 1950X. k10temp-pci-00cb Adapter: PCI adapter temp1: +4294948.3°C (high = +70.0°C) This will happen if the temperature reported by the chip is lower than the offset temperature. This has been seen in the field if "Sense MI Skew" and/or "Sense MI Offset" BIOS parameters were set to unexpected values. Let's report a temperature of 0 degrees C in that case. Fixes: 1b50b776355f ("hwmon: (k10temp) Add support for temperature offsets") Signed-off-by: Guenter Roeck --- drivers/hwmon/k10temp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 06b4e1c78bd8..4c6594a4661d 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -129,7 +129,10 @@ static ssize_t temp1_input_show(struct device *dev, data->read_tempreg(data->pdev, ®val); temp = (regval >> 21) * 125; - temp -= data->temp_offset; + if (temp > data->temp_offset) + temp -= data->temp_offset; + else + temp = 0; return sprintf(buf, "%u\n", temp); } -- cgit v1.2.3 From 75b0e73023ef7994348d619e9adadab0e96bb195 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Feb 2018 10:24:02 +0000 Subject: drm/i915/perf: Fix compiler warning for string truncation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/gpu/drm/i915/i915_oa_cflgt3.c: In function ‘i915_perf_load_test_config_cflgt3’: drivers/gpu/drm/i915/i915_oa_cflgt3.c:87:2: error: ‘strncpy’ output truncated before terminating nul copying 36 bytes from a string of the same length [-Werror=stringop-truncation] v2: strlcpy Fixes: 4407eaa9b0cc ("drm/i915/perf: add support for Coffeelake GT3") Signed-off-by: Chris Wilson Cc: Lionel Landwerlin Cc: Matthew Auld Reviewed-by: Lionel Landwerlin Link: https://patchwork.freedesktop.org/patch/msgid/20180208102403.5587-1-chris@chris-wilson.co.uk (cherry picked from commit 43df81d324cdd7056ad0ce3df709aff8dce856b7) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_oa_cflgt3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_oa_cflgt3.c b/drivers/gpu/drm/i915/i915_oa_cflgt3.c index 42ff06fe54a3..792facdb6702 100644 --- a/drivers/gpu/drm/i915/i915_oa_cflgt3.c +++ b/drivers/gpu/drm/i915/i915_oa_cflgt3.c @@ -84,9 +84,9 @@ show_test_oa_id(struct device *kdev, struct device_attribute *attr, char *buf) void i915_perf_load_test_config_cflgt3(struct drm_i915_private *dev_priv) { - strncpy(dev_priv->perf.oa.test_config.uuid, + strlcpy(dev_priv->perf.oa.test_config.uuid, "577e8e2c-3fa0-4875-8743-3538d585e3b0", - UUID_STRING_LEN); + sizeof(dev_priv->perf.oa.test_config.uuid)); dev_priv->perf.oa.test_config.id = 1; dev_priv->perf.oa.test_config.mux_regs = mux_config_test_oa; -- cgit v1.2.3 From 73b0fcd24ef1b8e20b7f6e6babcde540d96d0cb2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Feb 2018 10:24:03 +0000 Subject: drm/i915/perf: Fix compiler warning for string truncation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/gpu/drm/i915/i915_oa_cnl.c: In function ‘i915_perf_load_test_config_cnl’: drivers/gpu/drm/i915/i915_oa_cnl.c:99:2: error: ‘strncpy’ output truncated before terminating nul copying 36 bytes from a string of the same length [-Werror=stringop-truncation] v2: strlcpy Fixes: 95690a02fb5d ("drm/i915/perf: enable perf support on CNL") Signed-off-by: Chris Wilson Cc: Lionel Landwerlin Cc: Matthew Auld Reviewed-by: Lionel Landwerlin Link: https://patchwork.freedesktop.org/patch/msgid/20180208102403.5587-2-chris@chris-wilson.co.uk (cherry picked from commit 020580ff8edd50e64ae1bf47e560c61e5e2f29fc) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_oa_cnl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_oa_cnl.c b/drivers/gpu/drm/i915/i915_oa_cnl.c index ff0ac3627cc4..ba9140c87cc0 100644 --- a/drivers/gpu/drm/i915/i915_oa_cnl.c +++ b/drivers/gpu/drm/i915/i915_oa_cnl.c @@ -96,9 +96,9 @@ show_test_oa_id(struct device *kdev, struct device_attribute *attr, char *buf) void i915_perf_load_test_config_cnl(struct drm_i915_private *dev_priv) { - strncpy(dev_priv->perf.oa.test_config.uuid, + strlcpy(dev_priv->perf.oa.test_config.uuid, "db41edd4-d8e7-4730-ad11-b9a2d6833503", - UUID_STRING_LEN); + sizeof(dev_priv->perf.oa.test_config.uuid)); dev_priv->perf.oa.test_config.id = 1; dev_priv->perf.oa.test_config.mux_regs = mux_config_test_oa; -- cgit v1.2.3 From 33afe065b66f226ee5f90ab24ff55799c896e381 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Feb 2018 08:51:51 +0000 Subject: drm/i915: Avoid truncation before clamping userspace's priority value Userspace provides a 64b value for the priority, we need to be careful to preserve the full range before validation to prevent truncation (and letting an illegal value pass). Reported-by: Antonio Argenziano Fixes: ac14fbd460d0 ("drm/i915/scheduler: Support user-defined priorities") Signed-off-by: Chris Wilson Cc: Antonio Argenziano Cc: Michal Winiarski Cc: Mika Kuoppala Cc: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20180208085151.11480-1-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen (cherry picked from commit 11a18f631959fd1ca10856c836a827683536770c) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 648e7536ff51..0c963fcf31ff 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -803,7 +803,7 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data, case I915_CONTEXT_PARAM_PRIORITY: { - int priority = args->value; + s64 priority = args->value; if (args->size) ret = -EINVAL; -- cgit v1.2.3 From 7292b9e6586534fb43e4316ad8b508bf3d1212f7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 12 Feb 2018 09:39:28 +0000 Subject: drm/i915: Don't wake the device up to check if the engine is asleep If the entire device is powered off, we can safely assume that the engine is also asleep (and idle). Reported-by: Tvrtko Ursulin Fixes: a091d4ee931b ("drm/i915: Hold a wakeref for probing the ring registers") Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180212093928.6005-1-chris@chris-wilson.co.uk (cherry picked from commit 74d00d28a15c8452f65de0a9477b52d95639cc63) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/intel_engine_cs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index d790bdc227ff..acc661aa9c0c 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1458,7 +1458,9 @@ static bool ring_is_idle(struct intel_engine_cs *engine) struct drm_i915_private *dev_priv = engine->i915; bool idle = true; - intel_runtime_pm_get(dev_priv); + /* If the whole device is asleep, the engine must be idle */ + if (!intel_runtime_pm_get_if_in_use(dev_priv)) + return true; /* First check that no commands are left in the ring */ if ((I915_READ_HEAD(engine) & HEAD_ADDR) != -- cgit v1.2.3 From 8f8ca51dbb4da0457f57f83d94aea81931b0707a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 13 Feb 2018 13:43:23 +0100 Subject: ata: sata_rcar: Remove unused variable in sata_rcar_init_controller() drivers/ata/sata_rcar.c: In function 'sata_rcar_init_controller': drivers/ata/sata_rcar.c:821:8: warning: unused variable 'base' [-Wunused-variable] Fixes: da77d76b95a0e894 ("sata_rcar: Reset SATA PHY when Salvator-X board resumes") Signed-off-by: Geert Uytterhoeven Signed-off-by: Tejun Heo --- drivers/ata/sata_rcar.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 6f47ca34767d..6456e07db72a 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -818,7 +818,6 @@ static void sata_rcar_init_module(struct sata_rcar_priv *priv) static void sata_rcar_init_controller(struct ata_host *host) { struct sata_rcar_priv *priv = host->private_data; - void __iomem *base = priv->base; /* reset and setup phy */ switch (priv->type) { -- cgit v1.2.3 From 7bcfab202ca71bece02b283cdd104301c07eece4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 13 Feb 2018 07:44:34 -0800 Subject: powerpc/macio: set a proper dma_coherent_mask We have expected busses to set up a coherent mask to properly use the common dma mapping code for a long time, and now that I've added a warning macio turned out to not set one up yet. This sets it to the same value as the dma_mask, which seems to be what the drivers expect. Reported-by: Mathieu Malaterre Tested-by: Mathieu Malaterre Reported-by: Meelis Roos Tested-by: Meelis Roos Signed-off-by: Christoph Hellwig --- drivers/macintosh/macio_asic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 62f541f968f6..07074820a167 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -375,6 +375,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, dev->ofdev.dev.of_node = np; dev->ofdev.archdata.dma_mask = 0xffffffffUL; dev->ofdev.dev.dma_mask = &dev->ofdev.archdata.dma_mask; + dev->ofdev.dev.coherent_dma_mask = dev->ofdev.archdata.dma_mask; dev->ofdev.dev.parent = parent; dev->ofdev.dev.bus = &macio_bus_type; dev->ofdev.dev.release = macio_release_dev; -- cgit v1.2.3 From 0f2d2b2736b08dafa3bde31d048750fbc8df3a31 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 13 Feb 2018 11:22:42 +0100 Subject: mlxsw: spectrum_router: Fix error path in mlxsw_sp_vr_create Since mlxsw_sp_fib_create() and mlxsw_sp_mr_table_create() use ERR_PTR macro to propagate int err through return of a pointer, the return value is not NULL in case of failure. So if one of the calls fails, one of vr->fib4, vr->fib6 or vr->mr4_table is not NULL and mlxsw_sp_vr_is_used wrongly assumes that vr is in use which leads to crash like following one: [ 1293.949291] BUG: unable to handle kernel NULL pointer dereference at 00000000000006c9 [ 1293.952729] IP: mlxsw_sp_mr_table_flush+0x15/0x70 [mlxsw_spectrum] Fix this by using local variables to hold the pointers and set vr->* only in case everything went fine. Fixes: 76610ebbde18 ("mlxsw: spectrum_router: Refactor virtual router handling") Fixes: a3d9bc506d64 ("mlxsw: spectrum_router: Extend virtual routers with IPv6 support") Fixes: d42b0965b1d4 ("mlxsw: spectrum_router: Add multicast routes notification handling functionality") Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 32 ++++++++++++---------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index f0b25baba09a..dcc6305f7c22 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -788,6 +788,9 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp, u32 tb_id, struct netlink_ext_ack *extack) { + struct mlxsw_sp_mr_table *mr4_table; + struct mlxsw_sp_fib *fib4; + struct mlxsw_sp_fib *fib6; struct mlxsw_sp_vr *vr; int err; @@ -796,29 +799,30 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp, NL_SET_ERR_MSG(extack, "spectrum: Exceeded number of supported virtual routers"); return ERR_PTR(-EBUSY); } - vr->fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4); - if (IS_ERR(vr->fib4)) - return ERR_CAST(vr->fib4); - vr->fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6); - if (IS_ERR(vr->fib6)) { - err = PTR_ERR(vr->fib6); + fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4); + if (IS_ERR(fib4)) + return ERR_CAST(fib4); + fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6); + if (IS_ERR(fib6)) { + err = PTR_ERR(fib6); goto err_fib6_create; } - vr->mr4_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id, - MLXSW_SP_L3_PROTO_IPV4); - if (IS_ERR(vr->mr4_table)) { - err = PTR_ERR(vr->mr4_table); + mr4_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id, + MLXSW_SP_L3_PROTO_IPV4); + if (IS_ERR(mr4_table)) { + err = PTR_ERR(mr4_table); goto err_mr_table_create; } + vr->fib4 = fib4; + vr->fib6 = fib6; + vr->mr4_table = mr4_table; vr->tb_id = tb_id; return vr; err_mr_table_create: - mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib6); - vr->fib6 = NULL; + mlxsw_sp_fib_destroy(mlxsw_sp, fib6); err_fib6_create: - mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib4); - vr->fib4 = NULL; + mlxsw_sp_fib_destroy(mlxsw_sp, fib4); return ERR_PTR(err); } -- cgit v1.2.3 From 0434352d3d2e950cf5e743f6062abd87de22f960 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 13 Feb 2018 20:25:50 +0100 Subject: extcon: int3496: process id-pin first so that we start with the right status Some other drivers may be waiting for our extcon to show-up, exiting their probe methods with -EPROBE_DEFER until we show up. These drivers will typically get the cable state directly after getting the extcon, this commit changes the int3496 code to wait for the initial processing of the id-pin to complete before exiting probe() with 0, which will cause devices waiting on the defered probe to get reprobed. This fixes a race where the initial work might still be running while other drivers were already calling extcon_get_state(). Fixes: 2f556bdb9f2e ("extcon: int3496: Add Intel INT3496 ACPI ... driver") Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-intel-int3496.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c index c8691b5a9cb0..191e99f06a9a 100644 --- a/drivers/extcon/extcon-intel-int3496.c +++ b/drivers/extcon/extcon-intel-int3496.c @@ -153,8 +153,9 @@ static int int3496_probe(struct platform_device *pdev) return ret; } - /* queue initial processing of id-pin */ + /* process id-pin so that we start with the right status */ queue_delayed_work(system_wq, &data->work, 0); + flush_delayed_work(&data->work); platform_set_drvdata(pdev, data); -- cgit v1.2.3 From 3fd176b754e992e1cdf1693ea8184626d1ed7671 Mon Sep 17 00:00:00 2001 From: Jianchao Wang Date: Mon, 12 Feb 2018 20:54:45 +0800 Subject: nvme: fix the deadlock in nvme_update_formats nvme_update_formats will invoke nvme_ns_remove under namespaces_mutext. The will cause deadlock because nvme_ns_remove will also require the namespaces_mutext. Fix it by getting the ns entries which should be removed under namespaces_mutext and invoke nvme_ns_remove out of namespaces_mutext. Signed-off-by: Jianchao Wang Reviewed-by: Christoph Hellwig Reviewed-by: Keith Busch Signed-off-by: Sagi Grimberg --- drivers/nvme/host/core.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 6d0490b477c9..52b3626fb64e 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1117,14 +1117,19 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, static void nvme_update_formats(struct nvme_ctrl *ctrl) { - struct nvme_ns *ns; + struct nvme_ns *ns, *next; + LIST_HEAD(rm_list); mutex_lock(&ctrl->namespaces_mutex); list_for_each_entry(ns, &ctrl->namespaces, list) { - if (ns->disk && nvme_revalidate_disk(ns->disk)) - nvme_ns_remove(ns); + if (ns->disk && nvme_revalidate_disk(ns->disk)) { + list_move_tail(&ns->list, &rm_list); + } } mutex_unlock(&ctrl->namespaces_mutex); + + list_for_each_entry_safe(ns, next, &rm_list, list) + nvme_ns_remove(ns); } static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects) -- cgit v1.2.3 From 815c6704bf9f1c59f3a6be380a4032b9c57b12f1 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 13 Feb 2018 05:44:44 -0700 Subject: nvme-pci: Remap CMB SQ entries on every controller reset The controller memory buffer is remapped into a kernel address on each reset, but the driver was setting the submission queue base address only on the very first queue creation. The remapped address is likely to change after a reset, so accessing the old address will hit a kernel bug. This patch fixes that by setting the queue's CMB base address each time the queue is created. Fixes: f63572dff1421 ("nvme: unmap CMB and remove sysfs file in reset path") Reported-by: Christian Black Cc: Jon Derrick Cc: # 4.9+ Signed-off-by: Keith Busch Reviewed-by: Christoph Hellwig --- drivers/nvme/host/pci.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index ab9c19525fa8..b427157af74e 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1364,18 +1364,14 @@ static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues, static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq, int qid, int depth) { - if (qid && dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) { - unsigned offset = (qid - 1) * roundup(SQ_SIZE(depth), - dev->ctrl.page_size); - nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset; - nvmeq->sq_cmds_io = dev->cmb + offset; - } else { - nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth), - &nvmeq->sq_dma_addr, GFP_KERNEL); - if (!nvmeq->sq_cmds) - return -ENOMEM; - } + /* CMB SQEs will be mapped before creation */ + if (qid && dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) + return 0; + nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth), + &nvmeq->sq_dma_addr, GFP_KERNEL); + if (!nvmeq->sq_cmds) + return -ENOMEM; return 0; } @@ -1449,6 +1445,13 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) struct nvme_dev *dev = nvmeq->dev; int result; + if (dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) { + unsigned offset = (qid - 1) * roundup(SQ_SIZE(nvmeq->q_depth), + dev->ctrl.page_size); + nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset; + nvmeq->sq_cmds_io = dev->cmb + offset; + } + nvmeq->cq_vector = qid - 1; result = adapter_alloc_cq(dev, qid, nvmeq); if (result < 0) -- cgit v1.2.3 From 4244140d7b8f406b7edfd01c050dea783aa1efc5 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 8 Feb 2018 08:55:34 -0700 Subject: nvme-pci: Fix timeouts in connecting state We need to halt the controller immediately if we haven't completed initialization as indicated by the new "connecting" state. Fixes: ad70062cdb ("nvme-pci: introduce RECONNECTING state to mark initializing procedure") Signed-off-by: Keith Busch Reviewed-by: Christoph Hellwig --- drivers/nvme/host/pci.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index b427157af74e..73036d2fbbd5 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1215,13 +1215,17 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved) * cancellation error. All outstanding requests are completed on * shutdown, so we return BLK_EH_HANDLED. */ - if (dev->ctrl.state == NVME_CTRL_RESETTING) { + switch (dev->ctrl.state) { + case NVME_CTRL_CONNECTING: + case NVME_CTRL_RESETTING: dev_warn(dev->ctrl.device, "I/O %d QID %d timeout, disable controller\n", req->tag, nvmeq->qid); nvme_dev_disable(dev, false); nvme_req(req)->flags |= NVME_REQ_CANCELLED; return BLK_EH_HANDLED; + default: + break; } /* -- cgit v1.2.3 From 117172c8f9d40ba1de8cb35c6e614422faa03330 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 13 Feb 2018 09:01:54 +0000 Subject: drm/i915/breadcrumbs: Ignore unsubmitted signalers When a request is preempted, it is unsubmitted from the HW queue and removed from the active list of breadcrumbs. In the process, this however triggers the signaler and it may see the clear rbtree with the old, and still valid, seqno, or it may match the cleared seqno with the now zero rq->global_seqno. This confuses the signaler into action and signaling the fence. Fixes: d6a2289d9d6b ("drm/i915: Remove the preempted request from the execution queue") Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Cc: # v4.12+ Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180206094633.30181-1-chris@chris-wilson.co.uk (cherry picked from commit fd10e2ce9905030d922e179a8047a4d50daffd8e) Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180213090154.17373-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_breadcrumbs.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c index bd40fea16b4f..f54ddda9fdad 100644 --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c @@ -594,29 +594,16 @@ void intel_engine_remove_wait(struct intel_engine_cs *engine, spin_unlock_irq(&b->rb_lock); } -static bool signal_valid(const struct drm_i915_gem_request *request) -{ - return intel_wait_check_request(&request->signaling.wait, request); -} - static bool signal_complete(const struct drm_i915_gem_request *request) { if (!request) return false; - /* If another process served as the bottom-half it may have already - * signalled that this wait is already completed. - */ - if (intel_wait_complete(&request->signaling.wait)) - return signal_valid(request); - - /* Carefully check if the request is complete, giving time for the + /* + * Carefully check if the request is complete, giving time for the * seqno to be visible or if the GPU hung. */ - if (__i915_request_irq_complete(request)) - return true; - - return false; + return __i915_request_irq_complete(request); } static struct drm_i915_gem_request *to_signaler(struct rb_node *rb) @@ -659,9 +646,13 @@ static int intel_breadcrumbs_signaler(void *arg) request = i915_gem_request_get_rcu(request); rcu_read_unlock(); if (signal_complete(request)) { - local_bh_disable(); - dma_fence_signal(&request->fence); - local_bh_enable(); /* kick start the tasklets */ + if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, + &request->fence.flags)) { + local_bh_disable(); + dma_fence_signal(&request->fence); + GEM_BUG_ON(!i915_gem_request_completed(request)); + local_bh_enable(); /* kick start the tasklets */ + } spin_lock_irq(&b->rb_lock); -- cgit v1.2.3 From edb76b01ac1629bfe17158bea56fcc16bfb57854 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 13 Feb 2018 09:57:44 +0000 Subject: drm/i915: Lock out execlist tasklet while peeking inside for busy-stats In order to prevent a race condition where we may end up overaccounting the active state and leaving the busy-stats believing the GPU is 100% busy, lock out the tasklet while we reconstruct the busy state. There is no direct spinlock guard for the execlists->port[], so we need to utilise tasklet_disable() as a synchronous barrier to prevent it, the only writer to execlists->port[], from running at the same time as the enable. Fixes: 4900727d35bb ("drm/i915/pmu: Reconstruct active state on starting busy-stats") Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180115092041.13509-1-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin (cherry picked from commit 99e48bf98dd036090b480a12c39e8b971731247e) Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180213095747.2424-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/intel_engine_cs.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index acc661aa9c0c..fa960cfd2764 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1945,16 +1945,22 @@ intel_engine_lookup_user(struct drm_i915_private *i915, u8 class, u8 instance) */ int intel_enable_engine_stats(struct intel_engine_cs *engine) { + struct intel_engine_execlists *execlists = &engine->execlists; unsigned long flags; + int err = 0; if (!intel_engine_supports_stats(engine)) return -ENODEV; + tasklet_disable(&execlists->tasklet); spin_lock_irqsave(&engine->stats.lock, flags); - if (engine->stats.enabled == ~0) - goto busy; + + if (unlikely(engine->stats.enabled == ~0)) { + err = -EBUSY; + goto unlock; + } + if (engine->stats.enabled++ == 0) { - struct intel_engine_execlists *execlists = &engine->execlists; const struct execlist_port *port = execlists->port; unsigned int num_ports = execlists_num_ports(execlists); @@ -1969,14 +1975,12 @@ int intel_enable_engine_stats(struct intel_engine_cs *engine) if (engine->stats.active) engine->stats.start = engine->stats.enabled_at; } - spin_unlock_irqrestore(&engine->stats.lock, flags); - return 0; - -busy: +unlock: spin_unlock_irqrestore(&engine->stats.lock, flags); + tasklet_enable(&execlists->tasklet); - return -EBUSY; + return err; } static ktime_t __intel_engine_get_busy_time(struct intel_engine_cs *engine) -- cgit v1.2.3 From d3f84c8b097001e3f31f584b793493cb0033a7ae Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 13 Feb 2018 09:57:45 +0000 Subject: drm/i915/pmu: Fix PMU enable vs execlists tasklet race Commit 99e48bf98dd0 ("drm/i915: Lock out execlist tasklet while peeking inside for busy-stats") added a tasklet_disable call in busy stats enabling, but we failed to understand that the PMU enable callback runs as an hard IRQ (IPI). Consequence of this is that the PMU enable callback can interrupt the execlists tasklet, and will then deadlock when it calls intel_engine_stats_enable->tasklet_disable. To fix this, I realized it is possible to move the engine stats enablement and disablement to PMU event init and destroy hooks. This allows for much simpler implementation since those hooks run in normal context (can sleep). v2: Extract engine_event_destroy. (Chris Wilson) Signed-off-by: Tvrtko Ursulin Fixes: 99e48bf98dd0 ("drm/i915: Lock out execlist tasklet while peeking inside for busy-stats") Testcase: igt/perf_pmu/enable-race-* Cc: Chris Wilson Cc: Tvrtko Ursulin Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: intel-gfx@lists.freedesktop.org Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180205093448.13877-1-tvrtko.ursulin@linux.intel.com (cherry picked from commit b2f78cda260bc6a1a2d382b1d85a29e69b5b3724) Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180213095747.2424-2-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 125 +++++++++++++------------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 14 ---- 2 files changed, 52 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 55a8a1e29424..337eaa6ede52 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -285,26 +285,41 @@ static u64 count_interrupts(struct drm_i915_private *i915) return sum; } -static void i915_pmu_event_destroy(struct perf_event *event) +static void engine_event_destroy(struct perf_event *event) { - WARN_ON(event->parent); + struct drm_i915_private *i915 = + container_of(event->pmu, typeof(*i915), pmu.base); + struct intel_engine_cs *engine; + + engine = intel_engine_lookup_user(i915, + engine_event_class(event), + engine_event_instance(event)); + if (WARN_ON_ONCE(!engine)) + return; + + if (engine_event_sample(event) == I915_SAMPLE_BUSY && + intel_engine_supports_stats(engine)) + intel_disable_engine_stats(engine); } -static int engine_event_init(struct perf_event *event) +static void i915_pmu_event_destroy(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); + WARN_ON(event->parent); - if (!intel_engine_lookup_user(i915, engine_event_class(event), - engine_event_instance(event))) - return -ENODEV; + if (is_engine_event(event)) + engine_event_destroy(event); +} - switch (engine_event_sample(event)) { +static int +engine_event_status(struct intel_engine_cs *engine, + enum drm_i915_pmu_engine_sample sample) +{ + switch (sample) { case I915_SAMPLE_BUSY: case I915_SAMPLE_WAIT: break; case I915_SAMPLE_SEMA: - if (INTEL_GEN(i915) < 6) + if (INTEL_GEN(engine->i915) < 6) return -ENODEV; break; default: @@ -314,6 +329,30 @@ static int engine_event_init(struct perf_event *event) return 0; } +static int engine_event_init(struct perf_event *event) +{ + struct drm_i915_private *i915 = + container_of(event->pmu, typeof(*i915), pmu.base); + struct intel_engine_cs *engine; + u8 sample; + int ret; + + engine = intel_engine_lookup_user(i915, engine_event_class(event), + engine_event_instance(event)); + if (!engine) + return -ENODEV; + + sample = engine_event_sample(event); + ret = engine_event_status(engine, sample); + if (ret) + return ret; + + if (sample == I915_SAMPLE_BUSY && intel_engine_supports_stats(engine)) + ret = intel_enable_engine_stats(engine); + + return ret; +} + static int i915_pmu_event_init(struct perf_event *event) { struct drm_i915_private *i915 = @@ -387,7 +426,7 @@ static u64 __i915_pmu_event_read(struct perf_event *event) if (WARN_ON_ONCE(!engine)) { /* Do nothing */ } else if (sample == I915_SAMPLE_BUSY && - engine->pmu.busy_stats) { + intel_engine_supports_stats(engine)) { val = ktime_to_ns(intel_engine_get_busy_time(engine)); } else { val = engine->pmu.sample[sample].cur; @@ -442,12 +481,6 @@ again: local64_add(new - prev, &event->count); } -static bool engine_needs_busy_stats(struct intel_engine_cs *engine) -{ - return intel_engine_supports_stats(engine) && - (engine->pmu.enable & BIT(I915_SAMPLE_BUSY)); -} - static void i915_pmu_enable(struct perf_event *event) { struct drm_i915_private *i915 = @@ -487,21 +520,7 @@ static void i915_pmu_enable(struct perf_event *event) GEM_BUG_ON(sample >= I915_PMU_SAMPLE_BITS); GEM_BUG_ON(engine->pmu.enable_count[sample] == ~0); - if (engine->pmu.enable_count[sample]++ == 0) { - /* - * Enable engine busy stats tracking if needed or - * alternatively cancel the scheduled disable. - * - * If the delayed disable was pending, cancel it and - * in this case do not enable since it already is. - */ - if (engine_needs_busy_stats(engine) && - !engine->pmu.busy_stats) { - engine->pmu.busy_stats = true; - if (!cancel_delayed_work(&engine->pmu.disable_busy_stats)) - intel_enable_engine_stats(engine); - } - } + engine->pmu.enable_count[sample]++; } /* @@ -514,14 +533,6 @@ static void i915_pmu_enable(struct perf_event *event) spin_unlock_irqrestore(&i915->pmu.lock, flags); } -static void __disable_busy_stats(struct work_struct *work) -{ - struct intel_engine_cs *engine = - container_of(work, typeof(*engine), pmu.disable_busy_stats.work); - - intel_disable_engine_stats(engine); -} - static void i915_pmu_disable(struct perf_event *event) { struct drm_i915_private *i915 = @@ -545,26 +556,8 @@ static void i915_pmu_disable(struct perf_event *event) * Decrement the reference count and clear the enabled * bitmask when the last listener on an event goes away. */ - if (--engine->pmu.enable_count[sample] == 0) { + if (--engine->pmu.enable_count[sample] == 0) engine->pmu.enable &= ~BIT(sample); - if (!engine_needs_busy_stats(engine) && - engine->pmu.busy_stats) { - engine->pmu.busy_stats = false; - /* - * We request a delayed disable to handle the - * rapid on/off cycles on events, which can - * happen when tools like perf stat start, in a - * nicer way. - * - * In addition, this also helps with busy stats - * accuracy with background CPU offline/online - * migration events. - */ - queue_delayed_work(system_wq, - &engine->pmu.disable_busy_stats, - round_jiffies_up_relative(HZ)); - } - } } GEM_BUG_ON(bit >= I915_PMU_MASK_BITS); @@ -797,8 +790,6 @@ static void i915_pmu_unregister_cpuhp_state(struct drm_i915_private *i915) void i915_pmu_register(struct drm_i915_private *i915) { - struct intel_engine_cs *engine; - enum intel_engine_id id; int ret; if (INTEL_GEN(i915) <= 2) { @@ -820,10 +811,6 @@ void i915_pmu_register(struct drm_i915_private *i915) hrtimer_init(&i915->pmu.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); i915->pmu.timer.function = i915_sample; - for_each_engine(engine, i915, id) - INIT_DELAYED_WORK(&engine->pmu.disable_busy_stats, - __disable_busy_stats); - ret = perf_pmu_register(&i915->pmu.base, "i915", -1); if (ret) goto err; @@ -843,9 +830,6 @@ err: void i915_pmu_unregister(struct drm_i915_private *i915) { - struct intel_engine_cs *engine; - enum intel_engine_id id; - if (!i915->pmu.base.event_init) return; @@ -853,11 +837,6 @@ void i915_pmu_unregister(struct drm_i915_private *i915) hrtimer_cancel(&i915->pmu.timer); - for_each_engine(engine, i915, id) { - GEM_BUG_ON(engine->pmu.busy_stats); - flush_delayed_work(&engine->pmu.disable_busy_stats); - } - i915_pmu_unregister_cpuhp_state(i915); perf_pmu_unregister(&i915->pmu.base); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index c5ff203e42d6..a0e7a6c2a57c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -366,20 +366,6 @@ struct intel_engine_cs { */ #define I915_ENGINE_SAMPLE_MAX (I915_SAMPLE_SEMA + 1) struct i915_pmu_sample sample[I915_ENGINE_SAMPLE_MAX]; - /** - * @busy_stats: Has enablement of engine stats tracking been - * requested. - */ - bool busy_stats; - /** - * @disable_busy_stats: Work item for busy stats disabling. - * - * Same as with @enable_busy_stats action, with the difference - * that we delay it in case there are rapid enable-disable - * actions, which can happen during tool startup (like perf - * stat). - */ - struct delayed_work disable_busy_stats; } pmu; /* -- cgit v1.2.3 From 4c83f0a788ccf58864f781585d8ae7c7e6a7e07d Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 13 Feb 2018 09:57:46 +0000 Subject: drm/i915/pmu: Fix sleep under atomic in RC6 readout We are not allowed to call intel_runtime_pm_get from the PMU counter read callback since the former can sleep, and the latter is running under IRQ context. To workaround this, we record the last known RC6 and while runtime suspended estimate its increase by querying the runtime PM core timestamps. Downside of this approach is that we can temporarily lose a chunk of RC6 time, from the last PMU read-out to runtime suspend entry, but that will eventually catch up, once device comes back online and in the presence of PMU queries. Also, we have to be careful not to overshoot the RC6 estimate, so once resumed after a period of approximation, we only update the counter once it catches up. With the observation that RC6 is increasing while the device is suspended, this should not pose a problem and can only cause slight inaccuracies due clock base differences. v2: Simplify by estimating on top of PM core counters. (Imre) Signed-off-by: Tvrtko Ursulin Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104943 Fixes: 6060b6aec03c ("drm/i915/pmu: Add RC6 residency metrics") Testcase: igt/perf_pmu/rc6-runtime-pm Cc: Tvrtko Ursulin Cc: Chris Wilson Cc: Imre Deak Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: David Airlie Cc: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180206183311.17924-1-tvrtko.ursulin@linux.intel.com (cherry picked from commit 1fe699e30113ed6f6e853ff44710d256072ea627) Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180213095747.2424-3-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 93 ++++++++++++++++++++++++++++++++++------- drivers/gpu/drm/i915/i915_pmu.h | 6 +++ 2 files changed, 84 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 337eaa6ede52..e13859aaa2a3 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -409,7 +409,81 @@ static int i915_pmu_event_init(struct perf_event *event) return 0; } -static u64 __i915_pmu_event_read(struct perf_event *event) +static u64 get_rc6(struct drm_i915_private *i915, bool locked) +{ + unsigned long flags; + u64 val; + + if (intel_runtime_pm_get_if_in_use(i915)) { + val = intel_rc6_residency_ns(i915, IS_VALLEYVIEW(i915) ? + VLV_GT_RENDER_RC6 : + GEN6_GT_GFX_RC6); + + if (HAS_RC6p(i915)) + val += intel_rc6_residency_ns(i915, GEN6_GT_GFX_RC6p); + + if (HAS_RC6pp(i915)) + val += intel_rc6_residency_ns(i915, GEN6_GT_GFX_RC6pp); + + intel_runtime_pm_put(i915); + + /* + * If we are coming back from being runtime suspended we must + * be careful not to report a larger value than returned + * previously. + */ + + if (!locked) + spin_lock_irqsave(&i915->pmu.lock, flags); + + if (val >= i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) { + i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = 0; + i915->pmu.sample[__I915_SAMPLE_RC6].cur = val; + } else { + val = i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur; + } + + if (!locked) + spin_unlock_irqrestore(&i915->pmu.lock, flags); + } else { + struct pci_dev *pdev = i915->drm.pdev; + struct device *kdev = &pdev->dev; + unsigned long flags2; + + /* + * We are runtime suspended. + * + * Report the delta from when the device was suspended to now, + * on top of the last known real value, as the approximated RC6 + * counter value. + */ + if (!locked) + spin_lock_irqsave(&i915->pmu.lock, flags); + + spin_lock_irqsave(&kdev->power.lock, flags2); + + if (!i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) + i915->pmu.suspended_jiffies_last = + kdev->power.suspended_jiffies; + + val = kdev->power.suspended_jiffies - + i915->pmu.suspended_jiffies_last; + val += jiffies - kdev->power.accounting_timestamp; + + spin_unlock_irqrestore(&kdev->power.lock, flags2); + + val = jiffies_to_nsecs(val); + val += i915->pmu.sample[__I915_SAMPLE_RC6].cur; + i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = val; + + if (!locked) + spin_unlock_irqrestore(&i915->pmu.lock, flags); + } + + return val; +} + +static u64 __i915_pmu_event_read(struct perf_event *event, bool locked) { struct drm_i915_private *i915 = container_of(event->pmu, typeof(*i915), pmu.base); @@ -447,18 +521,7 @@ static u64 __i915_pmu_event_read(struct perf_event *event) val = count_interrupts(i915); break; case I915_PMU_RC6_RESIDENCY: - intel_runtime_pm_get(i915); - val = intel_rc6_residency_ns(i915, - IS_VALLEYVIEW(i915) ? - VLV_GT_RENDER_RC6 : - GEN6_GT_GFX_RC6); - if (HAS_RC6p(i915)) - val += intel_rc6_residency_ns(i915, - GEN6_GT_GFX_RC6p); - if (HAS_RC6pp(i915)) - val += intel_rc6_residency_ns(i915, - GEN6_GT_GFX_RC6pp); - intel_runtime_pm_put(i915); + val = get_rc6(i915, locked); break; } } @@ -473,7 +536,7 @@ static void i915_pmu_event_read(struct perf_event *event) again: prev = local64_read(&hwc->prev_count); - new = __i915_pmu_event_read(event); + new = __i915_pmu_event_read(event, false); if (local64_cmpxchg(&hwc->prev_count, prev, new) != prev) goto again; @@ -528,7 +591,7 @@ static void i915_pmu_enable(struct perf_event *event) * for all listeners. Even when the event was already enabled and has * an existing non-zero value. */ - local64_set(&event->hw.prev_count, __i915_pmu_event_read(event)); + local64_set(&event->hw.prev_count, __i915_pmu_event_read(event, true)); spin_unlock_irqrestore(&i915->pmu.lock, flags); } diff --git a/drivers/gpu/drm/i915/i915_pmu.h b/drivers/gpu/drm/i915/i915_pmu.h index 40c154d13565..bb62df15afa4 100644 --- a/drivers/gpu/drm/i915/i915_pmu.h +++ b/drivers/gpu/drm/i915/i915_pmu.h @@ -27,6 +27,8 @@ enum { __I915_SAMPLE_FREQ_ACT = 0, __I915_SAMPLE_FREQ_REQ, + __I915_SAMPLE_RC6, + __I915_SAMPLE_RC6_ESTIMATED, __I915_NUM_PMU_SAMPLERS }; @@ -94,6 +96,10 @@ struct i915_pmu { * struct intel_engine_cs. */ struct i915_pmu_sample sample[__I915_NUM_PMU_SAMPLERS]; + /** + * @suspended_jiffies_last: Cached suspend time from PM core. + */ + unsigned long suspended_jiffies_last; }; #ifdef CONFIG_PERF_EVENTS -- cgit v1.2.3 From 4b8b41d15d9db54703958fbd2928a2fd319563f6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 13 Feb 2018 09:57:47 +0000 Subject: drm/i915/pmu: Fix building without CONFIG_PM As we peek inside struct device to query members guarded by CONFIG_PM, so must be the code. Reported-by: kbuild test robot Fixes: 1fe699e30113 ("drm/i915/pmu: Fix sleep under atomic in RC6 readout") Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180207160428.17015-1-chris@chris-wilson.co.uk (cherry picked from commit 05273c950a3c93c5f96be8807eaf24f2cc9f1c1e) Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180213095747.2424-4-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index e13859aaa2a3..0e9b98c32b62 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -409,22 +409,32 @@ static int i915_pmu_event_init(struct perf_event *event) return 0; } -static u64 get_rc6(struct drm_i915_private *i915, bool locked) +static u64 __get_rc6(struct drm_i915_private *i915) { - unsigned long flags; u64 val; - if (intel_runtime_pm_get_if_in_use(i915)) { - val = intel_rc6_residency_ns(i915, IS_VALLEYVIEW(i915) ? - VLV_GT_RENDER_RC6 : - GEN6_GT_GFX_RC6); + val = intel_rc6_residency_ns(i915, + IS_VALLEYVIEW(i915) ? + VLV_GT_RENDER_RC6 : + GEN6_GT_GFX_RC6); - if (HAS_RC6p(i915)) - val += intel_rc6_residency_ns(i915, GEN6_GT_GFX_RC6p); + if (HAS_RC6p(i915)) + val += intel_rc6_residency_ns(i915, GEN6_GT_GFX_RC6p); + + if (HAS_RC6pp(i915)) + val += intel_rc6_residency_ns(i915, GEN6_GT_GFX_RC6pp); + + return val; +} - if (HAS_RC6pp(i915)) - val += intel_rc6_residency_ns(i915, GEN6_GT_GFX_RC6pp); +static u64 get_rc6(struct drm_i915_private *i915, bool locked) +{ +#if IS_ENABLED(CONFIG_PM) + unsigned long flags; + u64 val; + if (intel_runtime_pm_get_if_in_use(i915)) { + val = __get_rc6(i915); intel_runtime_pm_put(i915); /* @@ -481,6 +491,9 @@ static u64 get_rc6(struct drm_i915_private *i915, bool locked) } return val; +#else + return __get_rc6(i915); +#endif } static u64 __i915_pmu_event_read(struct perf_event *event, bool locked) -- cgit v1.2.3 From 37ad4e68783088ed61493f54194cfccd3c87ab35 Mon Sep 17 00:00:00 2001 From: Weinan Li Date: Fri, 9 Feb 2018 16:01:34 +0800 Subject: drm/i915/gvt: add 0xe4f0 into gen9 render list Guest may set this register on KBL platform, it can impact hardware behavior, so add it into the gen9 render list. Otherwise gpu hang issue may happen during different vgpu switch. v2: separate it from patch set. Cc: Zhi Wang Cc: Zhenyu Wang Signed-off-by: Weinan Li Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/mmio_context.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c index 73ad6e90e49d..256f1bb522b7 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.c +++ b/drivers/gpu/drm/i915/gvt/mmio_context.c @@ -118,6 +118,7 @@ static struct engine_mmio gen9_engine_mmio_list[] __cacheline_aligned = { {RCS, HALF_SLICE_CHICKEN3, 0xffff, true}, /* 0xe184 */ {RCS, GEN9_HALF_SLICE_CHICKEN5, 0xffff, true}, /* 0xe188 */ {RCS, GEN9_HALF_SLICE_CHICKEN7, 0xffff, true}, /* 0xe194 */ + {RCS, GEN8_ROW_CHICKEN, 0xffff, true}, /* 0xe4f0 */ {RCS, TRVATTL3PTRDW(0), 0, false}, /* 0x4de0 */ {RCS, TRVATTL3PTRDW(1), 0, false}, /* 0x4de4 */ {RCS, TRNULLDETCT, 0, false}, /* 0x4de8 */ -- cgit v1.2.3 From a26ca6ad4c4aa4afcbfe4c46c33ad98859736245 Mon Sep 17 00:00:00 2001 From: Tina Zhang Date: Sun, 11 Feb 2018 14:59:19 +0800 Subject: drm/i915/gvt: Support BAR0 8-byte reads/writes GGTT is in BAR0 with 8 bytes aligned. With a qemu patch (commit: 38d49e8c1523d97d2191190d3f7b4ce7a0ab5aa3), VFIO can use 8-byte reads/ writes to access it. This patch is to support the 8-byte GGTT reads/writes. Ideally, we would like to support 8-byte reads/writes for the total BAR0. But it needs more work for handling 8-byte MMIO reads/writes. This patch can fix the issue caused by partial updating GGTT entry, during guest booting up. v3: - Use intel_vgpu_get_bar_gpa() stead. (Zhenyu) - Include all the GGTT checking logic in gtt_entry(). (Zhenyu) v2: - Limit to GGTT entry. (Zhenyu) Signed-off-by: Tina Zhang Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/kvmgt.c | 51 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 909499b73d03..021f722e2481 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -733,6 +733,25 @@ static ssize_t intel_vgpu_rw(struct mdev_device *mdev, char *buf, return ret == 0 ? count : ret; } +static bool gtt_entry(struct mdev_device *mdev, loff_t *ppos) +{ + struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); + unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); + struct intel_gvt *gvt = vgpu->gvt; + int offset; + + /* Only allow MMIO GGTT entry access */ + if (index != PCI_BASE_ADDRESS_0) + return false; + + offset = (u64)(*ppos & VFIO_PCI_OFFSET_MASK) - + intel_vgpu_get_bar_gpa(vgpu, PCI_BASE_ADDRESS_0); + + return (offset >= gvt->device_info.gtt_start_offset && + offset < gvt->device_info.gtt_start_offset + gvt_ggtt_sz(gvt)) ? + true : false; +} + static ssize_t intel_vgpu_read(struct mdev_device *mdev, char __user *buf, size_t count, loff_t *ppos) { @@ -742,7 +761,21 @@ static ssize_t intel_vgpu_read(struct mdev_device *mdev, char __user *buf, while (count) { size_t filled; - if (count >= 4 && !(*ppos % 4)) { + /* Only support GGTT entry 8 bytes read */ + if (count >= 8 && !(*ppos % 8) && + gtt_entry(mdev, ppos)) { + u64 val; + + ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val), + ppos, false); + if (ret <= 0) + goto read_err; + + if (copy_to_user(buf, &val, sizeof(val))) + goto read_err; + + filled = 8; + } else if (count >= 4 && !(*ppos % 4)) { u32 val; ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val), @@ -802,7 +835,21 @@ static ssize_t intel_vgpu_write(struct mdev_device *mdev, while (count) { size_t filled; - if (count >= 4 && !(*ppos % 4)) { + /* Only support GGTT entry 8 bytes write */ + if (count >= 8 && !(*ppos % 8) && + gtt_entry(mdev, ppos)) { + u64 val; + + if (copy_from_user(&val, buf, sizeof(val))) + goto write_err; + + ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val), + ppos, true); + if (ret <= 0) + goto write_err; + + filled = 8; + } else if (count >= 4 && !(*ppos % 4)) { u32 val; if (copy_from_user(&val, buf, sizeof(val))) -- cgit v1.2.3 From 3cc7644e4af179e79153b1fd60f9dd937ee32684 Mon Sep 17 00:00:00 2001 From: Weinan Li Date: Mon, 12 Feb 2018 15:28:42 +0800 Subject: drm/i915/gvt: fix one typo of render_mmio trace Fix one typo of render_mmio trace, exchange the mmio value of old and new. Signed-off-by: Weinan Li Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/gvt/trace.h b/drivers/gpu/drm/i915/gvt/trace.h index 7a2511538f34..736bd2bc5127 100644 --- a/drivers/gpu/drm/i915/gvt/trace.h +++ b/drivers/gpu/drm/i915/gvt/trace.h @@ -333,7 +333,7 @@ TRACE_EVENT(render_mmio, TP_PROTO(int old_id, int new_id, char *action, unsigned int reg, unsigned int old_val, unsigned int new_val), - TP_ARGS(old_id, new_id, action, reg, new_val, old_val), + TP_ARGS(old_id, new_id, action, reg, old_val, new_val), TP_STRUCT__entry( __field(int, old_id) -- cgit v1.2.3 From cabe92a55e3a12005a4ac4d3954c9a174b0efe2a Mon Sep 17 00:00:00 2001 From: "Michael Kelley (EOSG)" Date: Wed, 24 Jan 2018 22:49:57 +0000 Subject: scsi: storvsc: Increase cmd_per_lun for higher speed devices Increase cmd_per_lun to allow more I/Os in progress per device, particularly for NVMe's. The Hyper-V host side can handle the higher count with no issues. Signed-off-by: Michael Kelley Reviewed-by: K. Y. Srinivasan Acked-by: K. Y. Srinivasan Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index e07907d91d04..8eadb30115aa 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1656,7 +1656,7 @@ static struct scsi_host_template scsi_driver = { .eh_timed_out = storvsc_eh_timed_out, .slave_alloc = storvsc_device_alloc, .slave_configure = storvsc_device_configure, - .cmd_per_lun = 255, + .cmd_per_lun = 2048, .this_id = -1, .use_clustering = ENABLE_CLUSTERING, /* Make sure we dont get a sg segment crosses a page boundary */ -- cgit v1.2.3 From eaf75d1815dad230dac2f1e8f1dc0349b2d50071 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Thu, 1 Feb 2018 10:33:17 -0800 Subject: scsi: qla2xxx: Fix double free bug after firmware timeout This patch is based on Max's original patch. When the qla2xxx firmware is unavailable, eventually qla2x00_sp_timeout() is reached, which calls the timeout function and frees the srb_t instance. The timeout function always resolves to qla2x00_async_iocb_timeout(), which invokes another callback function called "done". All of these qla2x00_*_sp_done() callbacks also free the srb_t instance; after returning to qla2x00_sp_timeout(), it is freed again. The fix is to remove the "sp->free(sp)" call from qla2x00_sp_timeout() and add it to those code paths in qla2x00_async_iocb_timeout() which do not already free the object. This is how it looks like with KASAN: BUG: KASAN: use-after-free in qla2x00_sp_timeout+0x228/0x250 Read of size 8 at addr ffff88278147a590 by task swapper/2/0 Allocated by task 1502: save_stack+0x33/0xa0 kasan_kmalloc+0xa0/0xd0 kmem_cache_alloc+0xb8/0x1c0 mempool_alloc+0xd6/0x260 qla24xx_async_gnl+0x3c5/0x1100 Freed by task 0: save_stack+0x33/0xa0 kasan_slab_free+0x72/0xc0 kmem_cache_free+0x75/0x200 qla24xx_async_gnl_sp_done+0x556/0x9e0 qla2x00_async_iocb_timeout+0x1c7/0x420 qla2x00_sp_timeout+0x16d/0x250 call_timer_fn+0x36/0x200 The buggy address belongs to the object at ffff88278147a440 which belongs to the cache qla2xxx_srbs of size 344 The buggy address is located 336 bytes inside of 344-byte region [ffff88278147a440, ffff88278147a598) Reported-by: Max Kellermann Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Cc: Max Kellermann Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index aececf664654..2dea1129d396 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -59,8 +59,6 @@ qla2x00_sp_timeout(struct timer_list *t) req->outstanding_cmds[sp->handle] = NULL; iocb = &sp->u.iocb_cmd; iocb->timeout(sp); - if (sp->type != SRB_ELS_DCMD) - sp->free(sp); spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); } @@ -102,7 +100,6 @@ qla2x00_async_iocb_timeout(void *data) srb_t *sp = data; fc_port_t *fcport = sp->fcport; struct srb_iocb *lio = &sp->u.iocb_cmd; - struct event_arg ea; if (fcport) { ql_dbg(ql_dbg_disc, fcport->vha, 0x2071, @@ -117,25 +114,13 @@ qla2x00_async_iocb_timeout(void *data) switch (sp->type) { case SRB_LOGIN_CMD: - if (!fcport) - break; /* Retry as needed. */ lio->u.logio.data[0] = MBS_COMMAND_ERROR; lio->u.logio.data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? QLA_LOGIO_LOGIN_RETRIED : 0; - memset(&ea, 0, sizeof(ea)); - ea.event = FCME_PLOGI_DONE; - ea.fcport = sp->fcport; - ea.data[0] = lio->u.logio.data[0]; - ea.data[1] = lio->u.logio.data[1]; - ea.sp = sp; - qla24xx_handle_plogi_done_event(fcport->vha, &ea); + sp->done(sp, QLA_FUNCTION_TIMEOUT); break; case SRB_LOGOUT_CMD: - if (!fcport) - break; - qlt_logo_completion_handler(fcport, QLA_FUNCTION_TIMEOUT); - break; case SRB_CT_PTHRU_CMD: case SRB_MB_IOCB: case SRB_NACK_PLOGI: @@ -235,12 +220,10 @@ static void qla2x00_async_logout_sp_done(void *ptr, int res) { srb_t *sp = ptr; - struct srb_iocb *lio = &sp->u.iocb_cmd; sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); - if (!test_bit(UNLOADING, &sp->vha->dpc_flags)) - qla2x00_post_async_logout_done_work(sp->vha, sp->fcport, - lio->u.logio.data); + sp->fcport->login_gen++; + qlt_logo_completion_handler(sp->fcport, res); sp->free(sp); } -- cgit v1.2.3 From f3767225021a48fc419d963559793e585da88b3d Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Thu, 1 Feb 2018 10:33:18 -0800 Subject: scsi: qla2xxx: Fix incorrect handle for abort IOCB This patch fixes incorrect handle used for abort IOCB. Fixes: b027a5ace443 ("scsi: qla2xxx: Fix queue ID for async abort with Multiqueue") Signed-off-by: Darren Trapp Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_iocb.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 1b62e943ec49..8d00d559bd26 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -3275,12 +3275,11 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb) memset(abt_iocb, 0, sizeof(struct abort_entry_24xx)); abt_iocb->entry_type = ABORT_IOCB_TYPE; abt_iocb->entry_count = 1; - abt_iocb->handle = - cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no, - aio->u.abt.cmd_hndl)); + abt_iocb->handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle)); abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); abt_iocb->handle_to_abort = - cpu_to_le32(MAKE_HANDLE(req->id, aio->u.abt.cmd_hndl)); + cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no, + aio->u.abt.cmd_hndl)); abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; abt_iocb->port_id[1] = sp->fcport->d_id.b.area; abt_iocb->port_id[2] = sp->fcport->d_id.b.domain; -- cgit v1.2.3 From 1683ce57f568c7c92d53e9234624a53554a29cd5 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Wed, 7 Feb 2018 08:12:35 -0800 Subject: scsi: qedi: Fix truncation of CHAP name and secret The data in NVRAM is not guaranteed to be NUL terminated. Since snprintf expects byte-stream to accommodate null byte, the CHAP secret is truncated. Use sprintf instead of snprintf to fix the truncation of CHAP name and secret. Signed-off-by: Andrew Vasquez Signed-off-by: Nilesh Javali Reviewed-by: Bart Van Assche Acked-by: Chris Leech Acked-by: Lee Duncan Signed-off-by: Martin K. Petersen --- drivers/scsi/qedi/qedi_main.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 58596d17f7d9..7c05be680b94 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -1830,8 +1830,8 @@ static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf) switch (type) { case ISCSI_BOOT_INI_INITIATOR_NAME: - rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n", - initiator->initiator_name.byte); + rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, + initiator->initiator_name.byte); break; default: rc = 0; @@ -1898,8 +1898,8 @@ qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type, switch (type) { case ISCSI_BOOT_TGT_NAME: - rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n", - block->target[idx].target_name.byte); + rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, + block->target[idx].target_name.byte); break; case ISCSI_BOOT_TGT_IP_ADDR: if (ipv6_en) @@ -1920,20 +1920,20 @@ qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type, block->target[idx].lun.value[0]); break; case ISCSI_BOOT_TGT_CHAP_NAME: - rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n", - chap_name); + rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, + chap_name); break; case ISCSI_BOOT_TGT_CHAP_SECRET: - rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n", - chap_secret); + rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, + chap_secret); break; case ISCSI_BOOT_TGT_REV_CHAP_NAME: - rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n", - mchap_name); + rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, + mchap_name); break; case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n", - mchap_secret); + rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, + mchap_secret); break; case ISCSI_BOOT_TGT_FLAGS: rc = snprintf(str, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT); -- cgit v1.2.3 From 2c08fe64e4f3b8528f6880b2bd7a66cce6fbcec3 Mon Sep 17 00:00:00 2001 From: Nilesh Javali Date: Wed, 7 Feb 2018 08:12:36 -0800 Subject: scsi: qedi: Cleanup local str variable Signed-off-by: Nilesh Javali Reviewed-by: Bart Van Assche Acked-by: Chris Leech Acked-by: Lee Duncan Signed-off-by: Martin K. Petersen --- drivers/scsi/qedi/qedi_main.c | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 7c05be680b94..8b637d1fe5a4 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -1723,7 +1723,6 @@ static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf) { struct qedi_ctx *qedi = data; struct nvm_iscsi_initiator *initiator; - char *str = buf; int rc = 1; u32 ipv6_en, dhcp_en, ip_len; struct nvm_iscsi_block *block; @@ -1757,32 +1756,32 @@ static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf) switch (type) { case ISCSI_BOOT_ETH_IP_ADDR: - rc = snprintf(str, ip_len, fmt, ip); + rc = snprintf(buf, ip_len, fmt, ip); break; case ISCSI_BOOT_ETH_SUBNET_MASK: - rc = snprintf(str, ip_len, fmt, sub); + rc = snprintf(buf, ip_len, fmt, sub); break; case ISCSI_BOOT_ETH_GATEWAY: - rc = snprintf(str, ip_len, fmt, gw); + rc = snprintf(buf, ip_len, fmt, gw); break; case ISCSI_BOOT_ETH_FLAGS: - rc = snprintf(str, 3, "%hhd\n", + rc = snprintf(buf, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT); break; case ISCSI_BOOT_ETH_INDEX: - rc = snprintf(str, 3, "0\n"); + rc = snprintf(buf, 3, "0\n"); break; case ISCSI_BOOT_ETH_MAC: - rc = sysfs_format_mac(str, qedi->mac, ETH_ALEN); + rc = sysfs_format_mac(buf, qedi->mac, ETH_ALEN); break; case ISCSI_BOOT_ETH_VLAN: - rc = snprintf(str, 12, "%d\n", + rc = snprintf(buf, 12, "%d\n", GET_FIELD2(initiator->generic_cont0, NVM_ISCSI_CFG_INITIATOR_VLAN)); break; case ISCSI_BOOT_ETH_ORIGIN: if (dhcp_en) - rc = snprintf(str, 3, "3\n"); + rc = snprintf(buf, 3, "3\n"); break; default: rc = 0; @@ -1818,7 +1817,6 @@ static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf) { struct qedi_ctx *qedi = data; struct nvm_iscsi_initiator *initiator; - char *str = buf; int rc; struct nvm_iscsi_block *block; @@ -1830,7 +1828,7 @@ static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf) switch (type) { case ISCSI_BOOT_INI_INITIATOR_NAME: - rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, + rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, initiator->initiator_name.byte); break; default: @@ -1859,7 +1857,6 @@ static ssize_t qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type, char *buf, enum qedi_nvm_tgts idx) { - char *str = buf; int rc = 1; u32 ctrl_flags, ipv6_en, chap_en, mchap_en, ip_len; struct nvm_iscsi_block *block; @@ -1898,48 +1895,48 @@ qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type, switch (type) { case ISCSI_BOOT_TGT_NAME: - rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, + rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, block->target[idx].target_name.byte); break; case ISCSI_BOOT_TGT_IP_ADDR: if (ipv6_en) - rc = snprintf(str, ip_len, "%pI6\n", + rc = snprintf(buf, ip_len, "%pI6\n", block->target[idx].ipv6_addr.byte); else - rc = snprintf(str, ip_len, "%pI4\n", + rc = snprintf(buf, ip_len, "%pI4\n", block->target[idx].ipv4_addr.byte); break; case ISCSI_BOOT_TGT_PORT: - rc = snprintf(str, 12, "%d\n", + rc = snprintf(buf, 12, "%d\n", GET_FIELD2(block->target[idx].generic_cont0, NVM_ISCSI_CFG_TARGET_TCP_PORT)); break; case ISCSI_BOOT_TGT_LUN: - rc = snprintf(str, 22, "%.*d\n", + rc = snprintf(buf, 22, "%.*d\n", block->target[idx].lun.value[1], block->target[idx].lun.value[0]); break; case ISCSI_BOOT_TGT_CHAP_NAME: - rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, + rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, chap_name); break; case ISCSI_BOOT_TGT_CHAP_SECRET: - rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, + rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, chap_secret); break; case ISCSI_BOOT_TGT_REV_CHAP_NAME: - rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, + rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, mchap_name); break; case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, + rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, mchap_secret); break; case ISCSI_BOOT_TGT_FLAGS: - rc = snprintf(str, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT); + rc = snprintf(buf, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT); break; case ISCSI_BOOT_TGT_NIC_ASSOC: - rc = snprintf(str, 3, "0\n"); + rc = snprintf(buf, 3, "0\n"); break; default: rc = 0; -- cgit v1.2.3 From 00c20cdc79259c6c5bf978b21af96c2d3edb646d Mon Sep 17 00:00:00 2001 From: Meelis Roos Date: Fri, 9 Feb 2018 08:57:44 +0200 Subject: scsi: aacraid: fix shutdown crash when init fails When aacraid init fails with "AAC0: adapter self-test failed.", shutdown leads to UBSAN warning and then oops: [154316.118423] ================================================================================ [154316.118508] UBSAN: Undefined behaviour in drivers/scsi/scsi_lib.c:2328:27 [154316.118566] member access within null pointer of type 'struct Scsi_Host' [154316.118631] CPU: 2 PID: 14530 Comm: reboot Tainted: G W 4.15.0-dirty #89 [154316.118701] Hardware name: Hewlett Packard HP NetServer/HP System Board, BIOS 4.06.46 PW 06/25/2003 [154316.118774] Call Trace: [154316.118848] dump_stack+0x48/0x65 [154316.118916] ubsan_epilogue+0xe/0x40 [154316.118976] __ubsan_handle_type_mismatch+0xfb/0x180 [154316.119043] scsi_block_requests+0x20/0x30 [154316.119135] aac_shutdown+0x18/0x40 [aacraid] [154316.119196] pci_device_shutdown+0x33/0x50 [154316.119269] device_shutdown+0x18a/0x390 [...] [154316.123435] BUG: unable to handle kernel NULL pointer dereference at 000000f4 [154316.123515] IP: scsi_block_requests+0xa/0x30 This is because aac_shutdown() does struct Scsi_Host *shost = pci_get_drvdata(dev); scsi_block_requests(shost); and that assumes shost has been assigned with pci_set_drvdata(). However, pci_set_drvdata(pdev, shost) is done in aac_probe_one() far after bailing out with error from calling the init function ((*aac_drivers[index].init)(aac)), and when the init function fails, no error is returned from aac_probe_one() so PCI layer assumes there is driver attached, and tries to shut it down later. Fix it by returning error from aac_probe_one() when card-specific init function fails. This fixes reboot on my HP NetRAID-4M with dead battery. Signed-off-by: Meelis Roos Reviewed-by: Dave Carroll Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/linit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index ad6ec573cc87..b730e8edb8b3 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1690,8 +1690,10 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) * Map in the registers from the adapter. */ aac->base_size = AAC_MIN_FOOTPRINT_SIZE; - if ((*aac_drivers[index].init)(aac)) + if ((*aac_drivers[index].init)(aac)) { + error = -ENODEV; goto out_unmap; + } if (aac->sync_mode) { if (aac_sync_mode) -- cgit v1.2.3 From 1bc5ad3a6acdcf56f83272f2de1cd2389ea9e9e2 Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Sun, 11 Feb 2018 22:48:41 -0800 Subject: scsi: qla4xxx: skip error recovery in case of register disconnect. A system crashes when continuously removing/re-adding the storage controller. Signed-off-by: Manish Rangankar Reviewed-by: Ewan D. Milne Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_def.h | 2 ++ drivers/scsi/qla4xxx/ql4_os.c | 46 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index fc233717355f..817f312023a9 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -168,6 +168,8 @@ #define DEV_DB_NON_PERSISTENT 0 #define DEV_DB_PERSISTENT 1 +#define QL4_ISP_REG_DISCONNECT 0xffffffffU + #define COPY_ISID(dst_isid, src_isid) { \ int i, j; \ for (i = 0, j = ISID_SIZE - 1; i < ISID_SIZE;) \ diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 82e889bbe0ed..fc2c97d9a0d6 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -262,6 +262,24 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { static struct scsi_transport_template *qla4xxx_scsi_transport; +static int qla4xxx_isp_check_reg(struct scsi_qla_host *ha) +{ + u32 reg_val = 0; + int rval = QLA_SUCCESS; + + if (is_qla8022(ha)) + reg_val = readl(&ha->qla4_82xx_reg->host_status); + else if (is_qla8032(ha) || is_qla8042(ha)) + reg_val = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER); + else + reg_val = readw(&ha->reg->ctrl_status); + + if (reg_val == QL4_ISP_REG_DISCONNECT) + rval = QLA_ERROR; + + return rval; +} + static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, uint32_t iface_type, uint32_t payload_size, uint32_t pid, struct sockaddr *dst_addr) @@ -9186,10 +9204,17 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) struct srb *srb = NULL; int ret = SUCCESS; int wait = 0; + int rval; ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Abort command issued cmd=%p, cdb=0x%x\n", ha->host_no, id, lun, cmd, cmd->cmnd[0]); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + spin_lock_irqsave(&ha->hardware_lock, flags); srb = (struct srb *) CMD_SP(cmd); if (!srb) { @@ -9241,6 +9266,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; int ret = FAILED, stat; + int rval; if (!ddb_entry) return ret; @@ -9260,6 +9286,12 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) cmd, jiffies, cmd->request->timeout / HZ, ha->dpc_flags, cmd->result, cmd->allowed)); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + /* FIXME: wait for hba to go online */ stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); if (stat != QLA_SUCCESS) { @@ -9303,6 +9335,7 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; int stat, ret; + int rval; if (!ddb_entry) return FAILED; @@ -9320,6 +9353,12 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, ha->dpc_flags, cmd->result, cmd->allowed)); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + stat = qla4xxx_reset_target(ha, ddb_entry); if (stat != QLA_SUCCESS) { starget_printk(KERN_INFO, scsi_target(cmd->device), @@ -9374,9 +9413,16 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) { int return_status = FAILED; struct scsi_qla_host *ha; + int rval; ha = to_qla_host(cmd->device->host); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba) qla4_83xx_set_idc_dontreset(ha); -- cgit v1.2.3 From fe0e58048f005fdce315eb4d185e5c160be4ac01 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Feb 2018 14:13:59 +0100 Subject: Revert "mmc: meson-gx: include tx phase in the tuning process" This reverts commit 0a44697627d17a66d7dc98f17aeca07ca79c5c20. This commit was initially intended to fix problems with hs200 and hs400 on some boards, mainly the odroid-c2. The OC2 (Rev 0.2) I have performs well in this modes, so I could not confirm these issues. We've had several reports about the issues being still present on (some) OC2, so apparently, this change does not do what it was supposed to do. Maybe the eMMC signal quality is on the edge on the board. This may explain the variability we see in term of stability, but this is just a guess. Lowering the max_frequency to 100Mhz seems to do trick for those affected by the issue Worse, the commit created new issues (CRC errors and hangs) on other boards, such as the kvim 1 and 2, the p200 or the libretech-cc. According to amlogic, the Tx phase should not be tuned and left in its default configuration, so it is best to just revert the commit. Fixes: 0a44697627d1 ("mmc: meson-gx: include tx phase in the tuning process") Cc: # 4.14+ Signed-off-by: Jerome Brunet Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 22438ebfe4e6..4f972b879fe6 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -717,22 +717,6 @@ static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode, static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct meson_host *host = mmc_priv(mmc); - int ret; - - /* - * If this is the initial tuning, try to get a sane Rx starting - * phase before doing the actual tuning. - */ - if (!mmc->doing_retune) { - ret = meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); - - if (ret) - return ret; - } - - ret = meson_mmc_clk_phase_tuning(mmc, opcode, host->tx_clk); - if (ret) - return ret; return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); } @@ -763,9 +747,8 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (!IS_ERR(mmc->supply.vmmc)) mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); - /* Reset phases */ + /* Reset rx phase */ clk_set_phase(host->rx_clk, 0); - clk_set_phase(host->tx_clk, 270); break; -- cgit v1.2.3 From 118032be389009b07ecb5a03ffe219a89d421def Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 12 Feb 2018 21:13:44 +0100 Subject: mmc: bcm2835: Don't overwrite max frequency unconditionally The optional DT parameter max-frequency could init the max bus frequency. So take care of this, before setting the max bus frequency. Fixes: 660fc733bd74 ("mmc: bcm2835: Add new driver for the sdhost controller.") Signed-off-by: Phil Elwell Signed-off-by: Stefan Wahren Cc: # 4.12+ Signed-off-by: Ulf Hansson --- drivers/mmc/host/bcm2835.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index 229dc18f0581..768972af8b85 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -1265,7 +1265,8 @@ static int bcm2835_add_host(struct bcm2835_host *host) char pio_limit_string[20]; int ret; - mmc->f_max = host->max_clk; + if (!mmc->f_max || mmc->f_max > host->max_clk) + mmc->f_max = host->max_clk; mmc->f_min = host->max_clk / SDCDIV_MAX_CDIV; mmc->max_busy_timeout = ~0 / (mmc->f_max / 1000); -- cgit v1.2.3 From fa08a3b4eba59429cf7e241a7af089103e79160f Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 18 Dec 2017 17:21:23 +0100 Subject: virtio/s390: implement PM operations for virtio_ccw Suspend/Resume to/from disk currently fails. Let us wire up the necessary callbacks. This is mostly just forwarding the requests to the virtio drivers. The only thing that has to be done in virtio_ccw itself is to re-set the virtio revision. Suggested-by: Thomas Huth Signed-off-by: Christian Borntraeger Message-Id: <20171207141102.70190-2-borntraeger@de.ibm.com> Reviewed-by: David Hildenbrand [CH: merged <20171218083706.223836-1-borntraeger@de.ibm.com> to fix !CONFIG_PM configs] Signed-off-by: Cornelia Huck Signed-off-by: Michael S. Tsirkin --- drivers/s390/virtio/virtio_ccw.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index ba2e0856d22c..8f5c1d7f751a 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -1297,6 +1297,9 @@ static int virtio_ccw_cio_notify(struct ccw_device *cdev, int event) vcdev->device_lost = true; rc = NOTIFY_DONE; break; + case CIO_OPER: + rc = NOTIFY_OK; + break; default: rc = NOTIFY_DONE; break; @@ -1309,6 +1312,27 @@ static struct ccw_device_id virtio_ids[] = { {}, }; +#ifdef CONFIG_PM_SLEEP +static int virtio_ccw_freeze(struct ccw_device *cdev) +{ + struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev); + + return virtio_device_freeze(&vcdev->vdev); +} + +static int virtio_ccw_restore(struct ccw_device *cdev) +{ + struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev); + int ret; + + ret = virtio_ccw_set_transport_rev(vcdev); + if (ret) + return ret; + + return virtio_device_restore(&vcdev->vdev); +} +#endif + static struct ccw_driver virtio_ccw_driver = { .driver = { .owner = THIS_MODULE, @@ -1321,6 +1345,11 @@ static struct ccw_driver virtio_ccw_driver = { .set_online = virtio_ccw_online, .notify = virtio_ccw_cio_notify, .int_class = IRQIO_VIR, +#ifdef CONFIG_PM_SLEEP + .freeze = virtio_ccw_freeze, + .thaw = virtio_ccw_restore, + .restore = virtio_ccw_restore, +#endif }; static int __init pure_hex(char **cp, unsigned int *val, int min_digit, -- cgit v1.2.3 From 7756f72ccd4359c6df61fc431cd3b5b0a8639837 Mon Sep 17 00:00:00 2001 From: Israel Rukshin Date: Tue, 30 Jan 2018 10:07:01 +0000 Subject: nvmet: Change return code of discard command if not supported Execute discard command on block device that doesn't support it should return success. Returning internal error while using multi-path fails the path. Reviewed-by: Max Gurtovoy Signed-off-by: Israel Rukshin Signed-off-by: Sagi Grimberg --- drivers/nvme/target/io-cmd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/target/io-cmd.c b/drivers/nvme/target/io-cmd.c index 0a4372a016f2..28bbdff4a88b 100644 --- a/drivers/nvme/target/io-cmd.c +++ b/drivers/nvme/target/io-cmd.c @@ -105,10 +105,13 @@ static void nvmet_execute_flush(struct nvmet_req *req) static u16 nvmet_discard_range(struct nvmet_ns *ns, struct nvme_dsm_range *range, struct bio **bio) { - if (__blkdev_issue_discard(ns->bdev, + int ret; + + ret = __blkdev_issue_discard(ns->bdev, le64_to_cpu(range->slba) << (ns->blksize_shift - 9), le32_to_cpu(range->nlb) << (ns->blksize_shift - 9), - GFP_KERNEL, 0, bio)) + GFP_KERNEL, 0, bio); + if (ret && ret != -EOPNOTSUPP) return NVME_SC_INTERNAL | NVME_SC_DNR; return 0; } -- cgit v1.2.3 From 8000d1fdb07e365e6565c2415aefdfed15413794 Mon Sep 17 00:00:00 2001 From: Nitzan Carmi Date: Wed, 17 Jan 2018 11:01:14 +0000 Subject: nvme-rdma: fix sysfs invoked reset_ctrl error flow When reset_controller that is invoked by sysfs fails, it enters an error flow which practically removes the nvme ctrl entirely (similar to delete_ctrl flow). It causes the system to hang, since a sysfs attribute cannot be unregistered by one of its own methods. This can be fixed by calling delete_ctrl as a work rather than sequential code. In addition, it should give the ctrl a chance to recover using reconnection mechanism (consistant with FC reset_ctrl error flow). Also, while we're here, return suitable errno in case the reset ended with non live ctrl. Signed-off-by: Nitzan Carmi Reviewed-by: Max Gurtovoy Signed-off-by: Sagi Grimberg --- drivers/nvme/host/core.c | 6 +++++- drivers/nvme/host/rdma.c | 7 ++----- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 52b3626fb64e..0fe7ea35c221 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -120,8 +120,12 @@ int nvme_reset_ctrl_sync(struct nvme_ctrl *ctrl) int ret; ret = nvme_reset_ctrl(ctrl); - if (!ret) + if (!ret) { flush_work(&ctrl->reset_work); + if (ctrl->state != NVME_CTRL_LIVE) + ret = -ENETRESET; + } + return ret; } EXPORT_SYMBOL_GPL(nvme_reset_ctrl_sync); diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 5e2cc4f0d207..3a51ed50eff2 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -1784,11 +1784,8 @@ static void nvme_rdma_reset_ctrl_work(struct work_struct *work) return; out_fail: - dev_warn(ctrl->ctrl.device, "Removing after reset failure\n"); - nvme_remove_namespaces(&ctrl->ctrl); - nvme_rdma_shutdown_ctrl(ctrl, true); - nvme_uninit_ctrl(&ctrl->ctrl); - nvme_put_ctrl(&ctrl->ctrl); + ++ctrl->ctrl.nr_reconnects; + nvme_rdma_reconnect_or_remove(ctrl); } static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = { -- cgit v1.2.3 From e6dbe9397ea754e80f59d852a74fc289fa8b0f3a Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 13 Feb 2018 17:59:22 +0100 Subject: Revert "net: thunderx: Add support for xdp redirect" This reverts commit aa136d0c82fcd6af14535853c30e219e02b2692d. As I previously[1] pointed out this implementation of XDP_REDIRECT is wrong. XDP_REDIRECT is a facility that must work between different NIC drivers. Another NIC driver can call ndo_xdp_xmit/nicvf_xdp_xmit, but your driver patch assumes payload data (at top of page) will contain a queue index and a DMA addr, this is not true and worse will likely contain garbage. Given you have not fixed this in due time (just reached v4.16-rc1), the only option I see is a revert. [1] http://lkml.kernel.org/r/20171211130902.482513d3@redhat.com Cc: Sunil Goutham Cc: Christina Jacob Cc: Aleksey Makarov Fixes: aa136d0c82fc ("net: thunderx: Add support for xdp redirect") Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/thunder/nicvf_main.c | 110 +++++---------------- drivers/net/ethernet/cavium/thunder/nicvf_queues.c | 11 +-- drivers/net/ethernet/cavium/thunder/nicvf_queues.h | 4 - 3 files changed, 31 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index b68cde9f17d2..7d9c5ffbd041 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -67,11 +67,6 @@ module_param(cpi_alg, int, S_IRUGO); MODULE_PARM_DESC(cpi_alg, "PFC algorithm (0=none, 1=VLAN, 2=VLAN16, 3=IP Diffserv)"); -struct nicvf_xdp_tx { - u64 dma_addr; - u8 qidx; -}; - static inline u8 nicvf_netdev_qidx(struct nicvf *nic, u8 qidx) { if (nic->sqs_mode) @@ -507,29 +502,14 @@ static int nicvf_init_resources(struct nicvf *nic) return 0; } -static void nicvf_unmap_page(struct nicvf *nic, struct page *page, u64 dma_addr) -{ - /* Check if it's a recycled page, if not unmap the DMA mapping. - * Recycled page holds an extra reference. - */ - if (page_ref_count(page) == 1) { - dma_addr &= PAGE_MASK; - dma_unmap_page_attrs(&nic->pdev->dev, dma_addr, - RCV_FRAG_LEN + XDP_HEADROOM, - DMA_FROM_DEVICE, - DMA_ATTR_SKIP_CPU_SYNC); - } -} - static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, struct cqe_rx_t *cqe_rx, struct snd_queue *sq, struct rcv_queue *rq, struct sk_buff **skb) { struct xdp_buff xdp; struct page *page; - struct nicvf_xdp_tx *xdp_tx = NULL; u32 action; - u16 len, err, offset = 0; + u16 len, offset = 0; u64 dma_addr, cpu_addr; void *orig_data; @@ -543,7 +523,7 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, cpu_addr = (u64)phys_to_virt(cpu_addr); page = virt_to_page((void *)cpu_addr); - xdp.data_hard_start = page_address(page) + RCV_BUF_HEADROOM; + xdp.data_hard_start = page_address(page); xdp.data = (void *)cpu_addr; xdp_set_data_meta_invalid(&xdp); xdp.data_end = xdp.data + len; @@ -563,7 +543,18 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, switch (action) { case XDP_PASS: - nicvf_unmap_page(nic, page, dma_addr); + /* Check if it's a recycled page, if not + * unmap the DMA mapping. + * + * Recycled page holds an extra reference. + */ + if (page_ref_count(page) == 1) { + dma_addr &= PAGE_MASK; + dma_unmap_page_attrs(&nic->pdev->dev, dma_addr, + RCV_FRAG_LEN + XDP_PACKET_HEADROOM, + DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + } /* Build SKB and pass on packet to network stack */ *skb = build_skb(xdp.data, @@ -576,20 +567,6 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, case XDP_TX: nicvf_xdp_sq_append_pkt(nic, sq, (u64)xdp.data, dma_addr, len); return true; - case XDP_REDIRECT: - /* Save DMA address for use while transmitting */ - xdp_tx = (struct nicvf_xdp_tx *)page_address(page); - xdp_tx->dma_addr = dma_addr; - xdp_tx->qidx = nicvf_netdev_qidx(nic, cqe_rx->rq_idx); - - err = xdp_do_redirect(nic->pnicvf->netdev, &xdp, prog); - if (!err) - return true; - - /* Free the page on error */ - nicvf_unmap_page(nic, page, dma_addr); - put_page(page); - break; default: bpf_warn_invalid_xdp_action(action); /* fall through */ @@ -597,7 +574,18 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, trace_xdp_exception(nic->netdev, prog, action); /* fall through */ case XDP_DROP: - nicvf_unmap_page(nic, page, dma_addr); + /* Check if it's a recycled page, if not + * unmap the DMA mapping. + * + * Recycled page holds an extra reference. + */ + if (page_ref_count(page) == 1) { + dma_addr &= PAGE_MASK; + dma_unmap_page_attrs(&nic->pdev->dev, dma_addr, + RCV_FRAG_LEN + XDP_PACKET_HEADROOM, + DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + } put_page(page); return true; } @@ -1864,50 +1852,6 @@ static int nicvf_xdp(struct net_device *netdev, struct netdev_bpf *xdp) } } -static int nicvf_xdp_xmit(struct net_device *netdev, struct xdp_buff *xdp) -{ - struct nicvf *nic = netdev_priv(netdev); - struct nicvf *snic = nic; - struct nicvf_xdp_tx *xdp_tx; - struct snd_queue *sq; - struct page *page; - int err, qidx; - - if (!netif_running(netdev) || !nic->xdp_prog) - return -EINVAL; - - page = virt_to_page(xdp->data); - xdp_tx = (struct nicvf_xdp_tx *)page_address(page); - qidx = xdp_tx->qidx; - - if (xdp_tx->qidx >= nic->xdp_tx_queues) - return -EINVAL; - - /* Get secondary Qset's info */ - if (xdp_tx->qidx >= MAX_SND_QUEUES_PER_QS) { - qidx = xdp_tx->qidx / MAX_SND_QUEUES_PER_QS; - snic = (struct nicvf *)nic->snicvf[qidx - 1]; - if (!snic) - return -EINVAL; - qidx = xdp_tx->qidx % MAX_SND_QUEUES_PER_QS; - } - - sq = &snic->qs->sq[qidx]; - err = nicvf_xdp_sq_append_pkt(snic, sq, (u64)xdp->data, - xdp_tx->dma_addr, - xdp->data_end - xdp->data); - if (err) - return -ENOMEM; - - nicvf_xdp_sq_doorbell(snic, sq, qidx); - return 0; -} - -static void nicvf_xdp_flush(struct net_device *dev) -{ - return; -} - static int nicvf_config_hwtstamp(struct net_device *netdev, struct ifreq *ifr) { struct hwtstamp_config config; @@ -1986,8 +1930,6 @@ static const struct net_device_ops nicvf_netdev_ops = { .ndo_fix_features = nicvf_fix_features, .ndo_set_features = nicvf_set_features, .ndo_bpf = nicvf_xdp, - .ndo_xdp_xmit = nicvf_xdp_xmit, - .ndo_xdp_flush = nicvf_xdp_flush, .ndo_do_ioctl = nicvf_ioctl, }; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index 3eae9ff9b53a..d42704d07484 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -204,7 +204,7 @@ static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, struct rbdr *rbdr, /* Reserve space for header modifications by BPF program */ if (rbdr->is_xdp) - buf_len += XDP_HEADROOM; + buf_len += XDP_PACKET_HEADROOM; /* Check if it's recycled */ if (pgcache) @@ -224,9 +224,8 @@ ret: nic->rb_page = NULL; return -ENOMEM; } - if (pgcache) - pgcache->dma_addr = *rbuf + XDP_HEADROOM; + pgcache->dma_addr = *rbuf + XDP_PACKET_HEADROOM; nic->rb_page_offset += buf_len; } @@ -1244,7 +1243,7 @@ int nicvf_xdp_sq_append_pkt(struct nicvf *nic, struct snd_queue *sq, int qentry; if (subdesc_cnt > sq->xdp_free_cnt) - return -1; + return 0; qentry = nicvf_get_sq_desc(sq, subdesc_cnt); @@ -1255,7 +1254,7 @@ int nicvf_xdp_sq_append_pkt(struct nicvf *nic, struct snd_queue *sq, sq->xdp_desc_cnt += subdesc_cnt; - return 0; + return 1; } /* Calculate no of SQ subdescriptors needed to transmit all @@ -1656,7 +1655,7 @@ static void nicvf_unmap_rcv_buffer(struct nicvf *nic, u64 dma_addr, if (page_ref_count(page) != 1) return; - len += XDP_HEADROOM; + len += XDP_PACKET_HEADROOM; /* Receive buffers in XDP mode are mapped from page start */ dma_addr &= PAGE_MASK; } diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h index ce1eed7a6d63..5e9a03cf1b4d 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h @@ -11,7 +11,6 @@ #include #include -#include #include #include "q_struct.h" @@ -94,9 +93,6 @@ #define RCV_FRAG_LEN (SKB_DATA_ALIGN(DMA_BUFFER_LEN + NET_SKB_PAD) + \ SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) -#define RCV_BUF_HEADROOM 128 /* To store dma address for XDP redirect */ -#define XDP_HEADROOM (XDP_PACKET_HEADROOM + RCV_BUF_HEADROOM) - #define MAX_CQES_FOR_TX ((SND_QUEUE_LEN / MIN_SQ_DESC_PER_PKT_XMIT) * \ MAX_CQE_PER_PKT_XMIT) -- cgit v1.2.3 From cc85c02edfe48a34865ae00f7d22298a3fdd17aa Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Tue, 13 Feb 2018 15:32:50 -0600 Subject: ibmvnic: Wait until reset is complete to set carrier on Pushes back setting the carrier on until the end of the reset code. This resolves a bug where a watchdog timer was detecting that a TX queue had stalled before the adapter reset was complete. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 27447260215d..1a2d8d66f527 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1670,8 +1670,6 @@ static int do_reset(struct ibmvnic_adapter *adapter, return 0; } - netif_carrier_on(netdev); - /* kick napi */ for (i = 0; i < adapter->req_rx_queues; i++) napi_schedule(&adapter->napi[i]); @@ -1679,6 +1677,8 @@ static int do_reset(struct ibmvnic_adapter *adapter, if (adapter->reset_reason != VNIC_RESET_FAILOVER) netdev_notify_peers(netdev); + netif_carrier_on(netdev); + return 0; } -- cgit v1.2.3 From 34f0f4e3f48810b0ba080bf2a65370b0cc179c51 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Tue, 13 Feb 2018 18:23:40 -0600 Subject: ibmvnic: Fix login buffer memory leaks During device bringup, the driver exchanges login buffers with firmware. These buffers contain information such number of TX and RX queues alloted to the device, RX buffer size, etc. These buffers weren't being properly freed on device reset or close. We can free the buffer we send to firmware as soon as we get a response. There is information in the response buffer that the driver needs for normal operation so retain it until the next reset or removal. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 1a2d8d66f527..8625f5e5b6d4 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -791,6 +791,18 @@ static int ibmvnic_login(struct net_device *netdev) return 0; } +static void release_login_buffer(struct ibmvnic_adapter *adapter) +{ + kfree(adapter->login_buf); + adapter->login_buf = NULL; +} + +static void release_login_rsp_buffer(struct ibmvnic_adapter *adapter) +{ + kfree(adapter->login_rsp_buf); + adapter->login_rsp_buf = NULL; +} + static void release_resources(struct ibmvnic_adapter *adapter) { int i; @@ -813,6 +825,8 @@ static void release_resources(struct ibmvnic_adapter *adapter) } } } + + release_login_rsp_buffer(adapter); } static int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state) @@ -3013,6 +3027,7 @@ static void send_login(struct ibmvnic_adapter *adapter) struct vnic_login_client_data *vlcd; int i; + release_login_rsp_buffer(adapter); client_data_len = vnic_client_data_len(adapter); buffer_size = @@ -3708,6 +3723,7 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq, dma_unmap_single(dev, adapter->login_buf_token, adapter->login_buf_sz, DMA_BIDIRECTIONAL); + release_login_buffer(adapter); dma_unmap_single(dev, adapter->login_rsp_buf_token, adapter->login_rsp_buf_sz, DMA_BIDIRECTIONAL); -- cgit v1.2.3 From 6e4842ddfc2b08931ebd6c0bc95322dd56e5232b Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Tue, 13 Feb 2018 18:23:41 -0600 Subject: ibmvnic: Fix NAPI structures memory leak This memory is allocated during initialization but never freed, so do that now. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 8625f5e5b6d4..23e0b423025a 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -825,6 +825,8 @@ static void release_resources(struct ibmvnic_adapter *adapter) } } } + kfree(adapter->napi); + adapter->napi = NULL; release_login_rsp_buffer(adapter); } -- cgit v1.2.3 From 4b9b0f01350500173f17e2b2e65beb4df4ef99c7 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Tue, 13 Feb 2018 18:23:42 -0600 Subject: ibmvnic: Free RX socket buffer in case of adapter error If a RX buffer is returned to the client driver with an error, free the corresponding socket buffer before continuing. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 23e0b423025a..bc93fa2be7fa 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1869,6 +1869,7 @@ restart_poll: be16_to_cpu(next->rx_comp.rc)); /* free the entry */ next->rx_comp.first = 0; + dev_kfree_skb_any(rx_buff->skb); remove_buff_from_pool(adapter, rx_buff); continue; } -- cgit v1.2.3 From d0869c0071e40c4407d1a4d7c9497653cf47253b Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Tue, 13 Feb 2018 18:23:43 -0600 Subject: ibmvnic: Clean RX pool buffers during device close During device close or reset, there were some cases of outstanding RX socket buffers not being freed. Include a function similar to the one that already exists to clean TX socket buffers in this case. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index bc93fa2be7fa..996f47568f9e 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1073,6 +1073,35 @@ static int ibmvnic_open(struct net_device *netdev) return rc; } +static void clean_rx_pools(struct ibmvnic_adapter *adapter) +{ + struct ibmvnic_rx_pool *rx_pool; + u64 rx_entries; + int rx_scrqs; + int i, j; + + if (!adapter->rx_pool) + return; + + rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); + rx_entries = adapter->req_rx_add_entries_per_subcrq; + + /* Free any remaining skbs in the rx buffer pools */ + for (i = 0; i < rx_scrqs; i++) { + rx_pool = &adapter->rx_pool[i]; + if (!rx_pool) + continue; + + netdev_dbg(adapter->netdev, "Cleaning rx_pool[%d]\n", i); + for (j = 0; j < rx_entries; j++) { + if (rx_pool->rx_buff[j].skb) { + dev_kfree_skb_any(rx_pool->rx_buff[j].skb); + rx_pool->rx_buff[j].skb = NULL; + } + } + } +} + static void clean_tx_pools(struct ibmvnic_adapter *adapter) { struct ibmvnic_tx_pool *tx_pool; @@ -1150,7 +1179,7 @@ static int __ibmvnic_close(struct net_device *netdev) } } } - + clean_rx_pools(adapter); clean_tx_pools(adapter); adapter->state = VNIC_CLOSED; return rc; -- cgit v1.2.3 From 405cacc947f7b58969b2a8ab1568c2d98b245308 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 20 Dec 2017 11:50:17 +0100 Subject: drm/i915/vlv: Add cdclk workaround for DSI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least on the Chuwi Vi8 (non pro/plus) the LCD panel will show an image shifted aprox. 20% to the left (with wraparound) and sometimes also wrong colors, showing that the panel controller is starting with sampling the datastream somewhere mid-line. This happens after the first blanking and re-init of the panel. After looking at drm.debug output I noticed that initially we inherit the cdclk of 333333 KHz set by the GOP, but after the re-init we picked 266667 KHz, which turns out to be the cause of this problem, a quick hack to hard code the cdclk to 333333 KHz makes the problem go away. I've tested this on various Bay Trail devices, to make sure this not does cause regressions on other devices and the higher cdclk does not cause any problems on the following devices: -GP-electronic T701 1024x600 333333 KHz cdclk after this patch -PEAQ C1010 1920x1200 333333 KHz cdclk after this patch -PoV mobii-wintab-800w 800x1280 333333 KHz cdclk after this patch -Asus Transformer-T100TA 1368x768 320000 KHz cdclk after this patch Also interesting wrt this is the comment in vlv_calc_cdclk about the existing workaround to avoid 200 Mhz as clock because that causes issues in some cases. This commit extends the "do not use 200 Mhz" workaround with an extra check to require atleast 320000 KHz (avoiding 266667 KHz) when a DSI panel is active. Changes in v2: -Change the commit message and the code comment to not treat the GOP as a reference, the GOP should not be treated as a reference Acked-by: Ville Syrjälä Signed-off-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20171220105017.11259-1-hdegoede@redhat.com (cherry picked from commit c8dae55a8ced625038d52d26e48273707fab2688) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/intel_cdclk.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index 5dc118f26b51..1704c8897afd 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -1952,6 +1952,14 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state) if (crtc_state->has_audio && INTEL_GEN(dev_priv) >= 9) min_cdclk = max(2 * 96000, min_cdclk); + /* + * On Valleyview some DSI panels lose (v|h)sync when the clock is lower + * than 320000KHz. + */ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) && + IS_VALLEYVIEW(dev_priv)) + min_cdclk = max(320000, min_cdclk); + if (min_cdclk > dev_priv->max_cdclk_freq) { DRM_DEBUG_KMS("required cdclk (%d kHz) exceeds max (%d kHz)\n", min_cdclk, dev_priv->max_cdclk_freq); -- cgit v1.2.3 From 7928e9bb09dc7f108a1a2b589ef1c7b86843569c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 14 Feb 2018 09:21:49 +0100 Subject: drm/i915: Add intel_bios_cleanup() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an intel_bios_cleanup() function to act as counterpart of intel_bios_init() and move the cleanup of vbt related resources there, putting it in the same file as the allocation. Changed in v2: -While touching the code anyways, remove the unnecessary: if (dev_priv->vbt.child_dev) done before kfree(dev_priv->vbt.child_dev) Reviewed-by: Ville Syrjälä Signed-off-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20180214082151.25015-1-hdegoede@redhat.com (cherry picked from commit 785f076b3ba781804f2b22b347b4431e3efb0ab3) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_drv.c | 14 +------------- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_bios.c | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 173d0095e3b2..2f5209de0391 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1433,19 +1433,7 @@ void i915_driver_unload(struct drm_device *dev) intel_modeset_cleanup(dev); - /* - * free the memory space allocated for the child device - * config parsed from VBT - */ - if (dev_priv->vbt.child_dev && dev_priv->vbt.child_dev_num) { - kfree(dev_priv->vbt.child_dev); - dev_priv->vbt.child_dev = NULL; - dev_priv->vbt.child_dev_num = 0; - } - kfree(dev_priv->vbt.sdvo_lvds_vbt_mode); - dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; - kfree(dev_priv->vbt.lfp_lvds_vbt_mode); - dev_priv->vbt.lfp_lvds_vbt_mode = NULL; + intel_bios_cleanup(dev_priv); vga_switcheroo_unregister_client(pdev); vga_client_register(pdev, NULL, NULL, NULL); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a42deebedb0f..d2fc519bc592 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3657,6 +3657,7 @@ extern void intel_i2c_reset(struct drm_i915_private *dev_priv); /* intel_bios.c */ void intel_bios_init(struct drm_i915_private *dev_priv); +void intel_bios_cleanup(struct drm_i915_private *dev_priv); bool intel_bios_is_valid_vbt(const void *buf, size_t size); bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv); bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 *i2c_pin); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index f7f771749e48..57db816f962b 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1588,6 +1588,21 @@ out: pci_unmap_rom(pdev, bios); } +/** + * intel_bios_cleanup - Free any resources allocated by intel_bios_init() + * @dev_priv: i915 device instance + */ +void intel_bios_cleanup(struct drm_i915_private *dev_priv) +{ + kfree(dev_priv->vbt.child_dev); + dev_priv->vbt.child_dev = NULL; + dev_priv->vbt.child_dev_num = 0; + kfree(dev_priv->vbt.sdvo_lvds_vbt_mode); + dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; + kfree(dev_priv->vbt.lfp_lvds_vbt_mode); + dev_priv->vbt.lfp_lvds_vbt_mode = NULL; +} + /** * intel_bios_is_tv_present - is integrated TV present in VBT * @dev_priv: i915 device instance -- cgit v1.2.3 From ed0545a7fbb5241a27f45a084dd71522cdaea5b9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 14 Feb 2018 09:21:50 +0100 Subject: drm/i915: Free memdup-ed DSI VBT data structures on driver_unload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make intel_bios_cleanup function free the DSI VBT data structures which are memdup-ed by parse_mipi_config() and parse_mipi_sequence(). Reviewed-by: Ville Syrjälä Signed-off-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20180214082151.25015-2-hdegoede@redhat.com (cherry picked from commit e1b86c85f6c2029c31dba99823b6f3d9e15eaacd) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/intel_bios.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 57db816f962b..9a9b62c93889 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1601,6 +1601,12 @@ void intel_bios_cleanup(struct drm_i915_private *dev_priv) dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; kfree(dev_priv->vbt.lfp_lvds_vbt_mode); dev_priv->vbt.lfp_lvds_vbt_mode = NULL; + kfree(dev_priv->vbt.dsi.data); + dev_priv->vbt.dsi.data = NULL; + kfree(dev_priv->vbt.dsi.pps); + dev_priv->vbt.dsi.pps = NULL; + kfree(dev_priv->vbt.dsi.config); + dev_priv->vbt.dsi.config = NULL; } /** -- cgit v1.2.3 From ee622fe757f6de612dad0f01805eea815a5b3025 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 14 Feb 2018 09:21:51 +0100 Subject: drm/i915: Fix DSI panels with v1 MIPI sequences without a DEASSERT sequence v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far models of the Dell Venue 8 Pro, with a panel with MIPI panel index = 3, one of which has been kindly provided to me by Jan Brummer, where not working with the i915 driver, giving a black screen on the first modeset. The problem with at least these Dells is that their VBT defines a MIPI ASSERT sequence, but not a DEASSERT sequence. Instead they DEASSERT the reset in their INIT_OTP sequence, but the deassert must be done before calling intel_dsi_device_ready(), so that is too late. Simply doing the INIT_OTP sequence earlier is not enough to fix this, because the INIT_OTP sequence also sends various MIPI packets to the panel, which can only happen after calling intel_dsi_device_ready(). This commit fixes this by splitting the INIT_OTP sequence into everything before the first DSI packet and everything else, including the first DSI packet. The first part (everything before the first DSI packet) is then used as deassert sequence. Changed in v2: -Split the init OTP sequence into a deassert reset and the actual init OTP sequence, instead of calling it earlier and then having the first mipi_exec_send_packet() call call intel_dsi_device_ready(). Changes in v3: -Move the whole shebang to intel_bios.c Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=82880 References: https://bugs.freedesktop.org/show_bug.cgi?id=101205 Cc: Jan-Michael Brummer Reported-by: Jan-Michael Brummer Tested-by: Hans de Goede Reviewed-by: Ville Syrjälä Acked-by: Jani Nikula Signed-off-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20180214082151.25015-3-hdegoede@redhat.com (cherry picked from commit fb38e7ade9af4f3e96f5916c3f6f19bfc7d5f961) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_bios.c | 84 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d2fc519bc592..d307429a5ae0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1349,6 +1349,7 @@ struct intel_vbt_data { u32 size; u8 *data; const u8 *sequence[MIPI_SEQ_MAX]; + u8 *deassert_seq; /* Used by fixup_mipi_sequences() */ } dsi; int crt_ddc_pin; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 9a9b62c93889..b49a2df44430 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -947,6 +947,86 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total) return 0; } +/* + * Get len of pre-fixed deassert fragment from a v1 init OTP sequence, + * skip all delay + gpio operands and stop at the first DSI packet op. + */ +static int get_init_otp_deassert_fragment_len(struct drm_i915_private *dev_priv) +{ + const u8 *data = dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; + int index, len; + + if (WARN_ON(!data || dev_priv->vbt.dsi.seq_version != 1)) + return 0; + + /* index = 1 to skip sequence byte */ + for (index = 1; data[index] != MIPI_SEQ_ELEM_END; index += len) { + switch (data[index]) { + case MIPI_SEQ_ELEM_SEND_PKT: + return index == 1 ? 0 : index; + case MIPI_SEQ_ELEM_DELAY: + len = 5; /* 1 byte for operand + uint32 */ + break; + case MIPI_SEQ_ELEM_GPIO: + len = 3; /* 1 byte for op, 1 for gpio_nr, 1 for value */ + break; + default: + return 0; + } + } + + return 0; +} + +/* + * Some v1 VBT MIPI sequences do the deassert in the init OTP sequence. + * The deassert must be done before calling intel_dsi_device_ready, so for + * these devices we split the init OTP sequence into a deassert sequence and + * the actual init OTP part. + */ +static void fixup_mipi_sequences(struct drm_i915_private *dev_priv) +{ + u8 *init_otp; + int len; + + /* Limit this to VLV for now. */ + if (!IS_VALLEYVIEW(dev_priv)) + return; + + /* Limit this to v1 vid-mode sequences */ + if (dev_priv->vbt.dsi.config->is_cmd_mode || + dev_priv->vbt.dsi.seq_version != 1) + return; + + /* Only do this if there are otp and assert seqs and no deassert seq */ + if (!dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] || + !dev_priv->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET] || + dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET]) + return; + + /* The deassert-sequence ends at the first DSI packet */ + len = get_init_otp_deassert_fragment_len(dev_priv); + if (!len) + return; + + DRM_DEBUG_KMS("Using init OTP fragment to deassert reset\n"); + + /* Copy the fragment, update seq byte and terminate it */ + init_otp = (u8 *)dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; + dev_priv->vbt.dsi.deassert_seq = kmemdup(init_otp, len + 1, GFP_KERNEL); + if (!dev_priv->vbt.dsi.deassert_seq) + return; + dev_priv->vbt.dsi.deassert_seq[0] = MIPI_SEQ_DEASSERT_RESET; + dev_priv->vbt.dsi.deassert_seq[len] = MIPI_SEQ_ELEM_END; + /* Use the copy for deassert */ + dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET] = + dev_priv->vbt.dsi.deassert_seq; + /* Replace the last byte of the fragment with init OTP seq byte */ + init_otp[len - 1] = MIPI_SEQ_INIT_OTP; + /* And make MIPI_MIPI_SEQ_INIT_OTP point to it */ + dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] = init_otp + len - 1; +} + static void parse_mipi_sequence(struct drm_i915_private *dev_priv, const struct bdb_header *bdb) @@ -1016,6 +1096,8 @@ parse_mipi_sequence(struct drm_i915_private *dev_priv, dev_priv->vbt.dsi.size = seq_size; dev_priv->vbt.dsi.seq_version = sequence->version; + fixup_mipi_sequences(dev_priv); + DRM_DEBUG_DRIVER("MIPI related VBT parsing complete\n"); return; @@ -1607,6 +1689,8 @@ void intel_bios_cleanup(struct drm_i915_private *dev_priv) dev_priv->vbt.dsi.pps = NULL; kfree(dev_priv->vbt.dsi.config); dev_priv->vbt.dsi.config = NULL; + kfree(dev_priv->vbt.dsi.deassert_seq); + dev_priv->vbt.dsi.deassert_seq = NULL; } /** -- cgit v1.2.3 From b399151cb48db30ad1e0e93dd40d68c6d007b637 Mon Sep 17 00:00:00 2001 From: Jia Zhang Date: Mon, 1 Jan 2018 09:52:10 +0800 Subject: x86/cpu: Rename cpu_data.x86_mask to cpu_data.x86_stepping x86_mask is a confusing name which is hard to associate with the processor's stepping. Additionally, correct an indent issue in lib/cpu.c. Signed-off-by: Jia Zhang [ Updated it to more recent kernels. ] Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: bp@alien8.de Cc: tony.luck@intel.com Link: http://lkml.kernel.org/r/1514771530-70829-1-git-send-email-qianyue.zj@alibaba-inc.com Signed-off-by: Ingo Molnar --- drivers/char/hw_random/via-rng.c | 2 +- drivers/cpufreq/acpi-cpufreq.c | 2 +- drivers/cpufreq/longhaul.c | 6 +++--- drivers/cpufreq/p4-clockmod.c | 2 +- drivers/cpufreq/powernow-k7.c | 2 +- drivers/cpufreq/speedstep-centrino.c | 4 ++-- drivers/cpufreq/speedstep-lib.c | 6 +++--- drivers/crypto/padlock-aes.c | 2 +- drivers/edac/amd64_edac.c | 2 +- drivers/hwmon/coretemp.c | 6 +++--- drivers/hwmon/hwmon-vid.c | 2 +- drivers/hwmon/k10temp.c | 2 +- drivers/hwmon/k8temp.c | 2 +- drivers/video/fbdev/geode/video_gx.c | 2 +- 14 files changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index d1f5bb534e0e..6e9df558325b 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -162,7 +162,7 @@ static int via_rng_init(struct hwrng *rng) /* Enable secondary noise source on CPUs where it is present. */ /* Nehemiah stepping 8 and higher */ - if ((c->x86_model == 9) && (c->x86_mask > 7)) + if ((c->x86_model == 9) && (c->x86_stepping > 7)) lo |= VIA_NOISESRC2; /* Esther */ diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 3a2ca0f79daf..d0c34df0529c 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -629,7 +629,7 @@ static int acpi_cpufreq_blacklist(struct cpuinfo_x86 *c) if (c->x86_vendor == X86_VENDOR_INTEL) { if ((c->x86 == 15) && (c->x86_model == 6) && - (c->x86_mask == 8)) { + (c->x86_stepping == 8)) { pr_info("Intel(R) Xeon(R) 7100 Errata AL30, processors may lock up on frequency changes: disabling acpi-cpufreq\n"); return -ENODEV; } diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index c46a12df40dd..d5e27bc7585a 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -775,7 +775,7 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) break; case 7: - switch (c->x86_mask) { + switch (c->x86_stepping) { case 0: longhaul_version = TYPE_LONGHAUL_V1; cpu_model = CPU_SAMUEL2; @@ -787,7 +787,7 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) break; case 1 ... 15: longhaul_version = TYPE_LONGHAUL_V2; - if (c->x86_mask < 8) { + if (c->x86_stepping < 8) { cpu_model = CPU_SAMUEL2; cpuname = "C3 'Samuel 2' [C5B]"; } else { @@ -814,7 +814,7 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) numscales = 32; memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults)); memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr)); - switch (c->x86_mask) { + switch (c->x86_stepping) { case 0 ... 1: cpu_model = CPU_NEHEMIAH; cpuname = "C3 'Nehemiah A' [C5XLOE]"; diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c index fd77812313f3..a25741b1281b 100644 --- a/drivers/cpufreq/p4-clockmod.c +++ b/drivers/cpufreq/p4-clockmod.c @@ -168,7 +168,7 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) #endif /* Errata workaround */ - cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask; + cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_stepping; switch (cpuid) { case 0x0f07: case 0x0f0a: diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c index 80ac313e6c59..302e9ce793a0 100644 --- a/drivers/cpufreq/powernow-k7.c +++ b/drivers/cpufreq/powernow-k7.c @@ -131,7 +131,7 @@ static int check_powernow(void) return 0; } - if ((c->x86_model == 6) && (c->x86_mask == 0)) { + if ((c->x86_model == 6) && (c->x86_stepping == 0)) { pr_info("K7 660[A0] core detected, enabling errata workarounds\n"); have_a0 = 1; } diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c index 41bc5397f4bb..4fa5adf16c70 100644 --- a/drivers/cpufreq/speedstep-centrino.c +++ b/drivers/cpufreq/speedstep-centrino.c @@ -37,7 +37,7 @@ struct cpu_id { __u8 x86; /* CPU family */ __u8 x86_model; /* model */ - __u8 x86_mask; /* stepping */ + __u8 x86_stepping; /* stepping */ }; enum { @@ -277,7 +277,7 @@ static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, { if ((c->x86 == x->x86) && (c->x86_model == x->x86_model) && - (c->x86_mask == x->x86_mask)) + (c->x86_stepping == x->x86_stepping)) return 1; return 0; } diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c index 8085ec9000d1..e3a9962ee410 100644 --- a/drivers/cpufreq/speedstep-lib.c +++ b/drivers/cpufreq/speedstep-lib.c @@ -272,9 +272,9 @@ unsigned int speedstep_detect_processor(void) ebx = cpuid_ebx(0x00000001); ebx &= 0x000000FF; - pr_debug("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask); + pr_debug("ebx value is %x, x86_stepping is %x\n", ebx, c->x86_stepping); - switch (c->x86_mask) { + switch (c->x86_stepping) { case 4: /* * B-stepping [M-P4-M] @@ -361,7 +361,7 @@ unsigned int speedstep_detect_processor(void) msr_lo, msr_hi); if ((msr_hi & (1<<18)) && (relaxed_check ? 1 : (msr_hi & (3<<24)))) { - if (c->x86_mask == 0x01) { + if (c->x86_stepping == 0x01) { pr_debug("early PIII version\n"); return SPEEDSTEP_CPU_PIII_C_EARLY; } else diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index 4b6642a25df5..1c6cbda56afe 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -512,7 +512,7 @@ static int __init padlock_init(void) printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n"); - if (c->x86 == 6 && c->x86_model == 15 && c->x86_mask == 2) { + if (c->x86 == 6 && c->x86_model == 15 && c->x86_stepping == 2) { ecb_fetch_blocks = MAX_ECB_FETCH_BLOCKS; cbc_fetch_blocks = MAX_CBC_FETCH_BLOCKS; printk(KERN_NOTICE PFX "VIA Nano stepping 2 detected: enabling workaround.\n"); diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 8b16ec595fa7..329cb96f886f 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -3147,7 +3147,7 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt) struct amd64_family_type *fam_type = NULL; pvt->ext_model = boot_cpu_data.x86_model >> 4; - pvt->stepping = boot_cpu_data.x86_mask; + pvt->stepping = boot_cpu_data.x86_stepping; pvt->model = boot_cpu_data.x86_model; pvt->fam = boot_cpu_data.x86; diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index c13a4fd86b3c..a42744c7665b 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -268,13 +268,13 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) for (i = 0; i < ARRAY_SIZE(tjmax_model_table); i++) { const struct tjmax_model *tm = &tjmax_model_table[i]; if (c->x86_model == tm->model && - (tm->mask == ANY || c->x86_mask == tm->mask)) + (tm->mask == ANY || c->x86_stepping == tm->mask)) return tm->tjmax; } /* Early chips have no MSR for TjMax */ - if (c->x86_model == 0xf && c->x86_mask < 4) + if (c->x86_model == 0xf && c->x86_stepping < 4) usemsr_ee = 0; if (c->x86_model > 0xe && usemsr_ee) { @@ -425,7 +425,7 @@ static int chk_ucode_version(unsigned int cpu) * Readings might stop update when processor visited too deep sleep, * fixed for stepping D0 (6EC). */ - if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) { + if (c->x86_model == 0xe && c->x86_stepping < 0xc && c->microcode < 0x39) { pr_err("Errata AE18 not fixed, update BIOS or microcode of the CPU!\n"); return -ENODEV; } diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c index ef91b8a67549..84e91286fc4f 100644 --- a/drivers/hwmon/hwmon-vid.c +++ b/drivers/hwmon/hwmon-vid.c @@ -293,7 +293,7 @@ u8 vid_which_vrm(void) if (c->x86 < 6) /* Any CPU with family lower than 6 */ return 0; /* doesn't have VID */ - vrm_ret = find_vrm(c->x86, c->x86_model, c->x86_mask, c->x86_vendor); + vrm_ret = find_vrm(c->x86, c->x86_model, c->x86_stepping, c->x86_vendor); if (vrm_ret == 134) vrm_ret = get_via_model_d_vrm(); if (vrm_ret == 0) diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 0721e175664a..b960015cb073 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -226,7 +226,7 @@ static bool has_erratum_319(struct pci_dev *pdev) * and AM3 formats, but that's the best we can do. */ return boot_cpu_data.x86_model < 4 || - (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_mask <= 2); + (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_stepping <= 2); } static int k10temp_probe(struct pci_dev *pdev, diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index 5a632bcf869b..e59f9113fb93 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -187,7 +187,7 @@ static int k8temp_probe(struct pci_dev *pdev, return -ENOMEM; model = boot_cpu_data.x86_model; - stepping = boot_cpu_data.x86_mask; + stepping = boot_cpu_data.x86_stepping; /* feature available since SH-C0, exclude older revisions */ if ((model == 4 && stepping == 0) || diff --git a/drivers/video/fbdev/geode/video_gx.c b/drivers/video/fbdev/geode/video_gx.c index 6082f653c68a..67773e8bbb95 100644 --- a/drivers/video/fbdev/geode/video_gx.c +++ b/drivers/video/fbdev/geode/video_gx.c @@ -127,7 +127,7 @@ void gx_set_dclk_frequency(struct fb_info *info) int timeout = 1000; /* Rev. 1 Geode GXs use a 14 MHz reference clock instead of 48 MHz. */ - if (cpu_data(0).x86_mask == 1) { + if (cpu_data(0).x86_stepping == 1) { pll_table = gx_pll_table_14MHz; pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz); } else { -- cgit v1.2.3 From c927b080c67e3e97193c81fc1d27f4251bf4e036 Mon Sep 17 00:00:00 2001 From: Kamil Konieczny Date: Wed, 7 Feb 2018 16:52:09 +0100 Subject: crypto: s5p-sss - Fix kernel Oops in AES-ECB mode In AES-ECB mode crypt is done with key only, so any use of IV can cause kernel Oops. Use IV only in AES-CBC and AES-CTR. Signed-off-by: Kamil Konieczny Reported-by: Anand Moon Reviewed-by: Krzysztof Kozlowski Tested-by: Anand Moon Cc: stable@vger.kernel.org # can be applied after commit 8f9702aad138 Signed-off-by: Herbert Xu --- drivers/crypto/s5p-sss.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 188f44b7eb27..5d64c08b7f47 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -1922,15 +1922,21 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) uint32_t aes_control; unsigned long flags; int err; + u8 *iv; aes_control = SSS_AES_KEY_CHANGE_MODE; if (mode & FLAGS_AES_DECRYPT) aes_control |= SSS_AES_MODE_DECRYPT; - if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) + if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) { aes_control |= SSS_AES_CHAIN_MODE_CBC; - else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) + iv = req->info; + } else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) { aes_control |= SSS_AES_CHAIN_MODE_CTR; + iv = req->info; + } else { + iv = NULL; /* AES_ECB */ + } if (dev->ctx->keylen == AES_KEYSIZE_192) aes_control |= SSS_AES_KEY_SIZE_192; @@ -1961,7 +1967,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) goto outdata_error; SSS_AES_WRITE(dev, AES_CONTROL, aes_control); - s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen); + s5p_set_aes(dev, dev->ctx->aes_key, iv, dev->ctx->keylen); s5p_set_dma_indata(dev, dev->sg_src); s5p_set_dma_outdata(dev, dev->sg_dst); -- cgit v1.2.3 From 6e1d8ea90932f77843730ada0bfea63093b7212a Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Wed, 14 Feb 2018 14:55:24 +0300 Subject: platform/x86: wmi: fix off-by-one write in wmi_dev_probe() wmi_dev_probe() allocates one byte less than necessary, thus subsequent sprintf() call writes trailing zero past the end of the 'buf': BUG: KASAN: slab-out-of-bounds in vsnprintf+0xda4/0x1240 Write of size 1 at addr ffff880423529caf by task kworker/1:1/32 Call Trace: dump_stack+0xb3/0x14d print_address_description+0xd7/0x380 kasan_report+0x166/0x2b0 vsnprintf+0xda4/0x1240 sprintf+0x9b/0xd0 wmi_dev_probe+0x1c3/0x400 driver_probe_device+0x5d1/0x990 bus_for_each_drv+0x109/0x190 __device_attach+0x217/0x360 bus_probe_device+0x1ad/0x260 deferred_probe_work_func+0x10f/0x5d0 process_one_work+0xa8b/0x1dc0 worker_thread+0x20d/0x17d0 kthread+0x311/0x3d0 ret_from_fork+0x3a/0x50 Allocated by task 32: kasan_kmalloc+0xa0/0xd0 __kmalloc+0x14f/0x3e0 wmi_dev_probe+0x182/0x400 driver_probe_device+0x5d1/0x990 bus_for_each_drv+0x109/0x190 __device_attach+0x217/0x360 bus_probe_device+0x1ad/0x260 deferred_probe_work_func+0x10f/0x5d0 process_one_work+0xa8b/0x1dc0 worker_thread+0x20d/0x17d0 kthread+0x311/0x3d0 ret_from_fork+0x3a/0x50 Increment allocation size to fix this. Fixes: 44b6b7661132 ("platform/x86: wmi: create userspace interface for drivers") Signed-off-by: Andrey Ryabinin Cc: Signed-off-by: Andy Shevchenko --- drivers/platform/x86/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index daa68acbc900..c0c8945603cb 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -933,7 +933,7 @@ static int wmi_dev_probe(struct device *dev) goto probe_failure; } - buf = kmalloc(strlen(wdriver->driver.name) + 4, GFP_KERNEL); + buf = kmalloc(strlen(wdriver->driver.name) + 5, GFP_KERNEL); if (!buf) { ret = -ENOMEM; goto probe_string_failure; -- cgit v1.2.3 From ed5b9ba7bef7f277cbdf315e385b44e0e3b1a9ab Mon Sep 17 00:00:00 2001 From: Aaron Ma Date: Sun, 11 Feb 2018 17:18:49 +0800 Subject: platform/x86: ideapad-laptop: Increase timeout to wait for EC answer Lenovo E41-20 needs more time than 100ms to read VPC, the funtion keys always failed responding. Increase timeout to get the value from VPC, then the funtion keys like mic mute key work well. Signed-off-by: Aaron Ma Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 5b6f18b18801..535199c9e6bc 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -113,7 +113,7 @@ MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth."); /* * ACPI Helpers */ -#define IDEAPAD_EC_TIMEOUT (100) /* in ms */ +#define IDEAPAD_EC_TIMEOUT (200) /* in ms */ static int read_method_int(acpi_handle handle, const char *method, int *val) { -- cgit v1.2.3 From eca39e7f0cdb9bde4003a29149fa695e876c6f73 Mon Sep 17 00:00:00 2001 From: Laszlo Toth Date: Tue, 13 Feb 2018 21:43:43 +0100 Subject: platform/x86: dell-laptop: fix kbd_get_state's request value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 9862b43624a5 ("platform/x86: dell-laptop: Allocate buffer on heap rather than globally") broke one request, changed it back to the original value. Tested on a Dell E6540, backlight came back. Fixes: 9862b43624a5 ("platform/x86: dell-laptop: Allocate buffer on heap rather than globally") Signed-off-by: Laszlo Toth Reviewed-by: Pali Rohár Reviewed-by: Mario Limonciello Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 2a68f59d2228..a37cff9fd8d4 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -1279,7 +1279,7 @@ static int kbd_get_state(struct kbd_state *state) struct calling_interface_buffer buffer; int ret; - dell_fill_request(&buffer, 0, 0, 0, 0); + dell_fill_request(&buffer, 0x1, 0, 0, 0); ret = dell_send_request(&buffer, CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); if (ret) -- cgit v1.2.3 From c8ba9db2a790c0fcf2f6c4cafd45ff3a0751800e Mon Sep 17 00:00:00 2001 From: Alexander Abrosimov Date: Thu, 8 Feb 2018 01:12:26 +0300 Subject: platform/x86: dell-laptop: Removed duplicates in DMI whitelist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed a mistake in which several entries were duplicated in the DMI list from the below commit fe486138 platform/x86: dell-laptop: Add 2-in-1 devices to the DMI whitelist Signed-off-by: Alexander Abrosimov Reviewed-by: Pali Rohár Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-laptop.c | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index a37cff9fd8d4..c52c6723374b 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -126,24 +126,6 @@ static const struct dmi_system_id dell_device_table[] __initconst = { DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/ }, }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_CHASSIS_TYPE, "30"), /*Tablet*/ - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /*Convertible*/ - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/ - }, - }, { .ident = "Dell Computer Corporation", .matches = { -- cgit v1.2.3 From 8874ae5f15f3feef3b4a415b9aed51edcf449aa1 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 23 Jan 2018 09:35:14 +0000 Subject: USB: gadget: udc: Add missing platform_device_put() on error in bdc_pci_probe() Add the missing platform_device_put() before return from bdc_pci_probe() in the platform_device_add_resources() error handling case. Fixes: efed421a94e6 ("usb: gadget: Add UDC driver for Broadcom USB3.0 device controller IP BDC") Signed-off-by: Wei Yongjun Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/bdc/bdc_pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/bdc/bdc_pci.c b/drivers/usb/gadget/udc/bdc/bdc_pci.c index 1e940f054cb8..6dbc489513cd 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_pci.c +++ b/drivers/usb/gadget/udc/bdc/bdc_pci.c @@ -77,6 +77,7 @@ static int bdc_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) if (ret) { dev_err(&pci->dev, "couldn't add resources to bdc device\n"); + platform_device_put(bdc); return ret; } -- cgit v1.2.3 From 98112041bcca164676367e261c8c1073ef70cb51 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 12 Feb 2018 15:30:08 +0200 Subject: usb: dwc3: core: Fix ULPI PHYs and prevent phy_get/ulpi_init during suspend/resume In order for ULPI PHYs to work, dwc3_phy_setup() and dwc3_ulpi_init() must be doene before dwc3_core_get_phy(). commit 541768b08a40 ("usb: dwc3: core: Call dwc3_core_get_phy() before initializing phys") broke this. The other issue is that dwc3_core_get_phy() and dwc3_ulpi_init() should be called only once during the life cycle of the driver. However, as dwc3_core_init() is called during system suspend/resume it will result in multiple calls to dwc3_core_get_phy() and dwc3_ulpi_init() which is wrong. Fix this by moving dwc3_ulpi_init() out of dwc3_phy_setup() into dwc3_core_ulpi_init(). Use a flag 'ulpi_ready' to ensure that dwc3_core_ulpi_init() is called only once from dwc3_core_init(). Use another flag 'phys_ready' to call dwc3_core_get_phy() only once from dwc3_core_init(). Fixes: 541768b08a40 ("usb: dwc3: core: Call dwc3_core_get_phy() before initializing phys") Fixes: f54edb539c11 ("usb: dwc3: core: initialize ULPI before trying to get the PHY") Cc: linux-stable # >= v4.13 Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 47 ++++++++++++++++++++++++++++++++++++----------- drivers/usb/dwc3/core.h | 5 +++++ 2 files changed, 41 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 59511f2cd3ac..f1d838a4acd6 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -486,6 +486,22 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc) parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); } +static int dwc3_core_ulpi_init(struct dwc3 *dwc) +{ + int intf; + int ret = 0; + + intf = DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3); + + if (intf == DWC3_GHWPARAMS3_HSPHY_IFC_ULPI || + (intf == DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI && + dwc->hsphy_interface && + !strncmp(dwc->hsphy_interface, "ulpi", 4))) + ret = dwc3_ulpi_init(dwc); + + return ret; +} + /** * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core * @dwc: Pointer to our controller context structure @@ -497,7 +513,6 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc) static int dwc3_phy_setup(struct dwc3 *dwc) { u32 reg; - int ret; reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); @@ -568,9 +583,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc) } /* FALLTHROUGH */ case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI: - ret = dwc3_ulpi_init(dwc); - if (ret) - return ret; /* FALLTHROUGH */ default: break; @@ -727,6 +739,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) } static int dwc3_core_get_phy(struct dwc3 *dwc); +static int dwc3_core_ulpi_init(struct dwc3 *dwc); /** * dwc3_core_init - Low-level initialization of DWC3 Core @@ -758,17 +771,27 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc->maximum_speed = USB_SPEED_HIGH; } - ret = dwc3_core_get_phy(dwc); + ret = dwc3_phy_setup(dwc); if (ret) goto err0; - ret = dwc3_core_soft_reset(dwc); - if (ret) - goto err0; + if (!dwc->ulpi_ready) { + ret = dwc3_core_ulpi_init(dwc); + if (ret) + goto err0; + dwc->ulpi_ready = true; + } - ret = dwc3_phy_setup(dwc); + if (!dwc->phys_ready) { + ret = dwc3_core_get_phy(dwc); + if (ret) + goto err0a; + dwc->phys_ready = true; + } + + ret = dwc3_core_soft_reset(dwc); if (ret) - goto err0; + goto err0a; dwc3_core_setup_global_control(dwc); dwc3_core_num_eps(dwc); @@ -841,6 +864,9 @@ err1: phy_exit(dwc->usb2_generic_phy); phy_exit(dwc->usb3_generic_phy); +err0a: + dwc3_ulpi_exit(dwc); + err0: return ret; } @@ -1235,7 +1261,6 @@ err4: err3: dwc3_free_event_buffers(dwc); - dwc3_ulpi_exit(dwc); err2: pm_runtime_allow(&pdev->dev); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 185b9603fd98..860d2bc184d1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -797,7 +797,9 @@ struct dwc3_scratchpad_array { * @usb3_phy: pointer to USB3 PHY * @usb2_generic_phy: pointer to USB2 PHY * @usb3_generic_phy: pointer to USB3 PHY + * @phys_ready: flag to indicate that PHYs are ready * @ulpi: pointer to ulpi interface + * @ulpi_ready: flag to indicate that ULPI is initialized * @u2sel: parameter from Set SEL request. * @u2pel: parameter from Set SEL request. * @u1sel: parameter from Set SEL request. @@ -895,7 +897,10 @@ struct dwc3 { struct phy *usb2_generic_phy; struct phy *usb3_generic_phy; + bool phys_ready; + struct ulpi *ulpi; + bool ulpi_ready; void __iomem *regs; size_t regs_size; -- cgit v1.2.3 From d39b6ea4f8c90e9e5f03a06b6a4fd4af11e2f617 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 15 Feb 2018 09:18:55 -0800 Subject: bus: ti-sysc: Fix checking of no-reset-on-init quirk We are currently only checking for the first entry in the table while we should check them all. Usual no-idle-on-init is together with no-reset-on-init, so this has gone unnoticed. Fixes: 566a9b05e1fa ("bus: ti-sysc: Handle module quirks based dts configuration") Signed-off-by: Tony Lindgren --- drivers/bus/ti-sysc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 4d46003c46cf..cdaeeea7999c 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -630,7 +630,7 @@ static int sysc_init_dts_quirks(struct sysc *ddata) for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) { prop = of_get_property(np, sysc_dts_quirks[i].name, &len); if (!prop) - break; + continue; ddata->cfg.quirks |= sysc_dts_quirks[i].mask; } -- cgit v1.2.3 From bde0716d1f076e4c913c7946bcc858f71243c7a0 Mon Sep 17 00:00:00 2001 From: Joe Lee Date: Mon, 12 Feb 2018 14:24:46 +0200 Subject: xhci: workaround for AMD Promontory disabled ports wakeup For AMD Promontory xHCI host, although you can disable USB ports in BIOS settings, those ports will be enabled anyway after you remove a device on that port and re-plug it in again. It's a known limitation of the chip. As a workaround we can clear the PORT_WAKE_BITS. [commit and code comment rephrasing -Mathias] Signed-off-by: Joe Lee Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 109 ++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/pci-quirks.h | 5 ++ drivers/usb/host/xhci-hub.c | 7 +++ drivers/usb/host/xhci-pci.c | 11 +++++ drivers/usb/host/xhci.h | 2 +- 5 files changed, 133 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 161536717025..67ad4bb6919a 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -66,6 +66,23 @@ #define AX_INDXC 0x30 #define AX_DATAC 0x34 +#define PT_ADDR_INDX 0xE8 +#define PT_READ_INDX 0xE4 +#define PT_SIG_1_ADDR 0xA520 +#define PT_SIG_2_ADDR 0xA521 +#define PT_SIG_3_ADDR 0xA522 +#define PT_SIG_4_ADDR 0xA523 +#define PT_SIG_1_DATA 0x78 +#define PT_SIG_2_DATA 0x56 +#define PT_SIG_3_DATA 0x34 +#define PT_SIG_4_DATA 0x12 +#define PT4_P1_REG 0xB521 +#define PT4_P2_REG 0xB522 +#define PT2_P1_REG 0xD520 +#define PT2_P2_REG 0xD521 +#define PT1_P1_REG 0xD522 +#define PT1_P2_REG 0xD523 + #define NB_PCIE_INDX_ADDR 0xe0 #define NB_PCIE_INDX_DATA 0xe4 #define PCIE_P_CNTL 0x10040 @@ -512,6 +529,98 @@ void usb_amd_dev_put(void) } EXPORT_SYMBOL_GPL(usb_amd_dev_put); +/* + * Check if port is disabled in BIOS on AMD Promontory host. + * BIOS Disabled ports may wake on connect/disconnect and need + * driver workaround to keep them disabled. + * Returns true if port is marked disabled. + */ +bool usb_amd_pt_check_port(struct device *device, int port) +{ + unsigned char value, port_shift; + struct pci_dev *pdev; + u16 reg; + + pdev = to_pci_dev(device); + pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_1_ADDR); + + pci_read_config_byte(pdev, PT_READ_INDX, &value); + if (value != PT_SIG_1_DATA) + return false; + + pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_2_ADDR); + + pci_read_config_byte(pdev, PT_READ_INDX, &value); + if (value != PT_SIG_2_DATA) + return false; + + pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_3_ADDR); + + pci_read_config_byte(pdev, PT_READ_INDX, &value); + if (value != PT_SIG_3_DATA) + return false; + + pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_4_ADDR); + + pci_read_config_byte(pdev, PT_READ_INDX, &value); + if (value != PT_SIG_4_DATA) + return false; + + /* Check disabled port setting, if bit is set port is enabled */ + switch (pdev->device) { + case 0x43b9: + case 0x43ba: + /* + * device is AMD_PROMONTORYA_4(0x43b9) or PROMONTORYA_3(0x43ba) + * PT4_P1_REG bits[7..1] represents USB2.0 ports 6 to 0 + * PT4_P2_REG bits[6..0] represents ports 13 to 7 + */ + if (port > 6) { + reg = PT4_P2_REG; + port_shift = port - 7; + } else { + reg = PT4_P1_REG; + port_shift = port + 1; + } + break; + case 0x43bb: + /* + * device is AMD_PROMONTORYA_2(0x43bb) + * PT2_P1_REG bits[7..5] represents USB2.0 ports 2 to 0 + * PT2_P2_REG bits[5..0] represents ports 9 to 3 + */ + if (port > 2) { + reg = PT2_P2_REG; + port_shift = port - 3; + } else { + reg = PT2_P1_REG; + port_shift = port + 5; + } + break; + case 0x43bc: + /* + * device is AMD_PROMONTORYA_1(0x43bc) + * PT1_P1_REG[7..4] represents USB2.0 ports 3 to 0 + * PT1_P2_REG[5..0] represents ports 9 to 4 + */ + if (port > 3) { + reg = PT1_P2_REG; + port_shift = port - 4; + } else { + reg = PT1_P1_REG; + port_shift = port + 4; + } + break; + default: + return false; + } + pci_write_config_word(pdev, PT_ADDR_INDX, reg); + pci_read_config_byte(pdev, PT_READ_INDX, &value); + + return !(value & BIT(port_shift)); +} +EXPORT_SYMBOL_GPL(usb_amd_pt_check_port); + /* * Make sure the controller is completely inactive, unable to * generate interrupts or do DMA. diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index b68dcb5dd0fd..4ca0d9b7e463 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -17,6 +17,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev); void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); void sb800_prefetch(struct device *dev, int on); bool usb_xhci_needs_pci_reset(struct pci_dev *pdev); +bool usb_amd_pt_check_port(struct device *device, int port); #else struct pci_dev; static inline void usb_amd_quirk_pll_disable(void) {} @@ -25,6 +26,10 @@ static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {} static inline void usb_amd_dev_put(void) {} static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} static inline void sb800_prefetch(struct device *dev, int on) {} +static inline bool usb_amd_pt_check_port(struct device *device, int port) +{ + return false; +} #endif /* CONFIG_USB_PCI */ #endif /* __LINUX_USB_PCI_QUIRKS_H */ diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 46d5e08f05f1..1df0c362c436 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1522,6 +1522,13 @@ int xhci_bus_suspend(struct usb_hcd *hcd) t2 |= PORT_WKOC_E | PORT_WKCONN_E; t2 &= ~PORT_WKDISC_E; } + + if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) && + (hcd->speed < HCD_USB3)) { + if (usb_amd_pt_check_port(hcd->self.controller, + port_index)) + t2 &= ~PORT_WAKE_BITS; + } } else t2 &= ~PORT_WAKE_BITS; diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 6c79037876db..5262fa571a5d 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -42,6 +42,10 @@ #define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8 #define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0 +#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9 +#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba +#define PCI_DEVICE_ID_AMD_PROMONTORYA_2 0x43bb +#define PCI_DEVICE_ID_AMD_PROMONTORYA_1 0x43bc #define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142 static const char hcd_name[] = "xhci_hcd"; @@ -125,6 +129,13 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_AMD) xhci->quirks |= XHCI_TRUST_TX_LENGTH; + if ((pdev->vendor == PCI_VENDOR_ID_AMD) && + ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) || + (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_3) || + (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2) || + (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1))) + xhci->quirks |= XHCI_U2_DISABLE_WAKE; + if (pdev->vendor == PCI_VENDOR_ID_INTEL) { xhci->quirks |= XHCI_LPM_SUPPORT; xhci->quirks |= XHCI_INTEL_HOST; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 96099a245c69..e4d7d3d06a75 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1822,7 +1822,7 @@ struct xhci_hcd { /* For controller with a broken Port Disable implementation */ #define XHCI_BROKEN_PORT_PED (1 << 25) #define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26) -/* Reserved. It was XHCI_U2_DISABLE_WAKE */ +#define XHCI_U2_DISABLE_WAKE (1 << 27) #define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28) #define XHCI_HW_LPM_DISABLE (1 << 29) -- cgit v1.2.3 From 1208d8a84fdcae6b395c57911cdf907450d30e70 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 12 Feb 2018 14:24:47 +0200 Subject: xhci: Don't print a warning when setting link state for disabled ports When disabling a USB3 port the hub driver will set the port link state to U3 to prevent "ejected" or "safely removed" devices that are still physically connected from immediately re-enumerating. If the device was really unplugged, then error messages were printed as the hub tries to set the U3 link state for a port that is no longer enabled. xhci-hcd ee000000.usb: Cannot set link state. usb usb8-port1: cannot disable (err = -32) Don't print error message in xhci-hub if hub tries to set port link state for a disabled port. Return -ENODEV instead which also silences hub driver. Signed-off-by: Mathias Nyman Tested-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 1df0c362c436..72ebbc908e19 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1224,17 +1224,17 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp = readl(port_array[wIndex]); break; } - - /* Software should not attempt to set - * port link state above '3' (U3) and the port - * must be enabled. - */ - if ((temp & PORT_PE) == 0 || - (link_state > USB_SS_PORT_LS_U3)) { - xhci_warn(xhci, "Cannot set link state.\n"); + /* Port must be enabled */ + if (!(temp & PORT_PE)) { + retval = -ENODEV; + break; + } + /* Can't set port link state above '3' (U3) */ + if (link_state > USB_SS_PORT_LS_U3) { + xhci_warn(xhci, "Cannot set port %d link state %d\n", + wIndex, link_state); goto error; } - if (link_state == USB_SS_PORT_LS_U3) { slot_id = xhci_find_slot_id_by_port(hcd, xhci, wIndex + 1); -- cgit v1.2.3 From fa2dfd0ec22e0069c84dfae162972cbbc7c75488 Mon Sep 17 00:00:00 2001 From: Zhengjun Xing Date: Mon, 12 Feb 2018 14:24:48 +0200 Subject: xhci: Fix NULL pointer in xhci debugfs Commit dde634057da7 ("xhci: Fix use-after-free in xhci debugfs") causes a null pointer dereference while fixing xhci-debugfs usage of ring pointers that were freed during hibernate. The fix passed addresses to ring pointers instead, but forgot to do this change for the xhci_ring_trb_show function. The address of the ring pointer passed to xhci-debugfs was of a temporary ring pointer "new_ring" instead of the actual ring "ring" pointer. The temporary new_ring pointer will be set to NULL later causing the NULL pointer dereference. This issue was seen when reading xhci related files in debugfs: cat /sys/kernel/debug/usb/xhci/*/devices/*/ep*/trbs [ 184.604861] BUG: unable to handle kernel NULL pointer dereference at (null) [ 184.613776] IP: xhci_ring_trb_show+0x3a/0x890 [ 184.618733] PGD 264193067 P4D 264193067 PUD 263238067 PMD 0 [ 184.625184] Oops: 0000 [#1] SMP [ 184.726410] RIP: 0010:xhci_ring_trb_show+0x3a/0x890 [ 184.731944] RSP: 0018:ffffba8243c0fd90 EFLAGS: 00010246 [ 184.737880] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 00000000000295d6 [ 184.746020] RDX: 00000000000295d5 RSI: 0000000000000001 RDI: ffff971a6418d400 [ 184.754121] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 [ 184.762222] R10: ffff971a64c98a80 R11: ffff971a62a00e40 R12: ffff971a62a85500 [ 184.770325] R13: 0000000000020000 R14: ffff971a6418d400 R15: ffff971a6418d400 [ 184.778448] FS: 00007fe725a79700(0000) GS:ffff971a6ec00000(0000) knlGS:0000000000000000 [ 184.787644] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 184.794168] CR2: 0000000000000000 CR3: 000000025f365005 CR4: 00000000003606f0 [ 184.802318] Call Trace: [ 184.805094] ? seq_read+0x281/0x3b0 [ 184.809068] seq_read+0xeb/0x3b0 [ 184.812735] full_proxy_read+0x4d/0x70 [ 184.817007] __vfs_read+0x23/0x120 [ 184.820870] vfs_read+0x91/0x130 [ 184.824538] SyS_read+0x42/0x90 [ 184.828106] entry_SYSCALL_64_fastpath+0x1a/0x7d Fixes: dde634057da7 ("xhci: Fix use-after-free in xhci debugfs") Cc: # v4.15 Signed-off-by: Zhengjun Xing Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index e26e685d8a57..5851052d4668 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -211,7 +211,7 @@ static void xhci_ring_dump_segment(struct seq_file *s, static int xhci_ring_trb_show(struct seq_file *s, void *unused) { int i; - struct xhci_ring *ring = s->private; + struct xhci_ring *ring = *(struct xhci_ring **)s->private; struct xhci_segment *seg = ring->first_seg; for (i = 0; i < ring->num_segs; i++) { @@ -387,7 +387,7 @@ void xhci_debugfs_create_endpoint(struct xhci_hcd *xhci, snprintf(epriv->name, sizeof(epriv->name), "ep%02d", ep_index); epriv->root = xhci_debugfs_create_ring_dir(xhci, - &dev->eps[ep_index].new_ring, + &dev->eps[ep_index].ring, epriv->name, spriv->root); spriv->eps[ep_index] = epriv; -- cgit v1.2.3 From d91676717261578f429d3577dbe9154b26e8abf7 Mon Sep 17 00:00:00 2001 From: Zhengjun Xing Date: Mon, 12 Feb 2018 14:24:49 +0200 Subject: xhci: Fix xhci debugfs devices node disappearance after hibernation During system resume from hibernation, xhci host is reset, all the nodes in devices folder are removed in xhci_mem_cleanup function. Later nodes in /sys/kernel/debug/usb/xhci/* are created again in function xhci_run, but the nodes already exist, so the nodes still keep the old ones, finally device nodes in xhci debugfs folder /sys/kernel/debug/usb/xhci/*/devices/* are disappeared. This fix removed xhci debugfs nodes before the nodes are re-created, so all the nodes in xhci debugfs can be re-created successfully. Fixes: 02b6fdc2a153 ("usb: xhci: Add debugfs interface for xHCI driver") Cc: # v4.15 Signed-off-by: Zhengjun Xing Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1eeb3396300f..b01bd643f905 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1014,6 +1014,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) xhci_dbg(xhci, "cleaning up memory\n"); xhci_mem_cleanup(xhci); + xhci_debugfs_exit(xhci); xhci_dbg(xhci, "xhci_stop completed - status = %x\n", readl(&xhci->op_regs->status)); -- cgit v1.2.3 From 8c5a93ebf7ac56d47f879b3c7c2f8c83b40c2cdb Mon Sep 17 00:00:00 2001 From: Zhengjun Xing Date: Mon, 12 Feb 2018 14:24:50 +0200 Subject: xhci: xhci debugfs device nodes weren't removed after device plugged out There is a bug after plugged out USB device, the device and its ep00 nodes are still kept, we need to remove the nodes in xhci_free_dev when USB device is plugged out. Fixes: 052f71e25a7e ("xhci: Fix xhci debugfs NULL pointer dereference in resume from hibernate") Cc: # v4.15 Signed-off-by: Zhengjun Xing Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index b01bd643f905..4adb6da0bd38 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3545,12 +3545,10 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING; del_timer_sync(&virt_dev->eps[i].stop_cmd_timer); } - + xhci_debugfs_remove_slot(xhci, udev->slot_id); ret = xhci_disable_slot(xhci, udev->slot_id); - if (ret) { - xhci_debugfs_remove_slot(xhci, udev->slot_id); + if (ret) xhci_free_virt_device(xhci, udev->slot_id); - } } int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id) -- cgit v1.2.3 From 11cd764dc9a030991880ad4d51db93918afa5822 Mon Sep 17 00:00:00 2001 From: Zhengjun Xing Date: Mon, 12 Feb 2018 14:24:51 +0200 Subject: xhci: fix xhci debugfs errors in xhci_stop In function xhci_stop, xhci_debugfs_exit called before xhci_mem_cleanup. xhci_debugfs_exit removed the xhci debugfs root nodes, xhci_mem_cleanup called function xhci_free_virt_devices_depth_first which in turn called function xhci_debugfs_remove_slot. Function xhci_debugfs_remove_slot removed the nodes for devices, the nodes folders are sub folder of xhci debugfs. It is unreasonable to remove xhci debugfs root folder before xhci debugfs sub folder. Function xhci_mem_cleanup should be called before function xhci_debugfs_exit. Fixes: 02b6fdc2a153 ("usb: xhci: Add debugfs interface for xHCI driver") Cc: # v4.15 Signed-off-by: Zhengjun Xing Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 4adb6da0bd38..25d4b748a56f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -646,8 +646,6 @@ static void xhci_stop(struct usb_hcd *hcd) return; } - xhci_debugfs_exit(xhci); - xhci_dbc_exit(xhci); spin_lock_irq(&xhci->lock); @@ -680,6 +678,7 @@ static void xhci_stop(struct usb_hcd *hcd) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory"); xhci_mem_cleanup(xhci); + xhci_debugfs_exit(xhci); xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_stop completed - status = %x", readl(&xhci->op_regs->status)); -- cgit v1.2.3 From 71a0483d56e784b1e11f38f10d7e22d265dbe244 Mon Sep 17 00:00:00 2001 From: Kristian Evensen Date: Thu, 1 Feb 2018 10:32:32 +0100 Subject: USB: serial: option: Add support for Quectel EP06 The Quectel EP06 is a Cat. 6 LTE modem, and the interface mapping is as follows: 0: Diag 1: NMEA 2: AT 3: Modem Interface 4 is QMI and interface 5 is ADB, so they are blacklisted. This patch should also be considered for -stable. The QMI-patch for this modem is already in the -stable-queue. v1->v2: * Updated commit prefix (thanks Johan Hovold) * Updated commit message slightly. Signed-off-by: Kristian Evensen Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5db8ed517e0e..2d8d9150da0c 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -241,6 +241,7 @@ static void option_instat_callback(struct urb *urb); #define QUECTEL_PRODUCT_EC21 0x0121 #define QUECTEL_PRODUCT_EC25 0x0125 #define QUECTEL_PRODUCT_BG96 0x0296 +#define QUECTEL_PRODUCT_EP06 0x0306 #define CMOTECH_VENDOR_ID 0x16d8 #define CMOTECH_PRODUCT_6001 0x6001 @@ -689,6 +690,10 @@ static const struct option_blacklist_info yuga_clm920_nc5_blacklist = { .reserved = BIT(1) | BIT(4), }; +static const struct option_blacklist_info quectel_ep06_blacklist = { + .reserved = BIT(4) | BIT(5), +}; + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -1203,6 +1208,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06), + .driver_info = (kernel_ulong_t)&quectel_ep06_blacklist }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), -- cgit v1.2.3 From b2685bdacdaab065c172b97b55ab46c6be77a037 Mon Sep 17 00:00:00 2001 From: Shigeru Yoshida Date: Fri, 2 Feb 2018 13:51:39 +0800 Subject: ohci-hcd: Fix race condition caused by ohci_urb_enqueue() and io_watchdog_func() Running io_watchdog_func() while ohci_urb_enqueue() is running can cause a race condition where ohci->prev_frame_no is corrupted and the watchdog can mis-detect following error: ohci-platform 664a0800.usb: frame counter not updating; disabled ohci-platform 664a0800.usb: HC died; cleaning up Specifically, following scenario causes a race condition: 1. ohci_urb_enqueue() calls spin_lock_irqsave(&ohci->lock, flags) and enters the critical section 2. ohci_urb_enqueue() calls timer_pending(&ohci->io_watchdog) and it returns false 3. ohci_urb_enqueue() sets ohci->prev_frame_no to a frame number read by ohci_frame_no(ohci) 4. ohci_urb_enqueue() schedules io_watchdog_func() with mod_timer() 5. ohci_urb_enqueue() calls spin_unlock_irqrestore(&ohci->lock, flags) and exits the critical section 6. Later, ohci_urb_enqueue() is called 7. ohci_urb_enqueue() calls spin_lock_irqsave(&ohci->lock, flags) and enters the critical section 8. The timer scheduled on step 4 expires and io_watchdog_func() runs 9. io_watchdog_func() calls spin_lock_irqsave(&ohci->lock, flags) and waits on it because ohci_urb_enqueue() is already in the critical section on step 7 10. ohci_urb_enqueue() calls timer_pending(&ohci->io_watchdog) and it returns false 11. ohci_urb_enqueue() sets ohci->prev_frame_no to new frame number read by ohci_frame_no(ohci) because the frame number proceeded between step 3 and 6 12. ohci_urb_enqueue() schedules io_watchdog_func() with mod_timer() 13. ohci_urb_enqueue() calls spin_unlock_irqrestore(&ohci->lock, flags) and exits the critical section, then wake up io_watchdog_func() which is waiting on step 9 14. io_watchdog_func() enters the critical section 15. io_watchdog_func() calls ohci_frame_no(ohci) and set frame_no variable to the frame number 16. io_watchdog_func() compares frame_no and ohci->prev_frame_no On step 16, because this calling of io_watchdog_func() is scheduled on step 4, the frame number set in ohci->prev_frame_no is expected to the number set on step 3. However, ohci->prev_frame_no is overwritten on step 11. Because step 16 is executed soon after step 11, the frame number might not proceed, so ohci->prev_frame_no must equals to frame_no. To address above scenario, this patch introduces a special sentinel value IO_WATCHDOG_OFF and set this value to ohci->prev_frame_no when the watchdog is not pending or running. When ohci_urb_enqueue() schedules the watchdog (step 4 and 12 above), it compares ohci->prev_frame_no to IO_WATCHDOG_OFF so that ohci->prev_frame_no is not overwritten while io_watchdog_func() is running. Signed-off-by: Shigeru Yoshida Signed-off-by: Haiqing Bai Acked-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 10 +++++++--- drivers/usb/host/ohci-hub.c | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index ee9676349333..84f88fa411cd 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -74,6 +74,7 @@ static const char hcd_name [] = "ohci_hcd"; #define STATECHANGE_DELAY msecs_to_jiffies(300) #define IO_WATCHDOG_DELAY msecs_to_jiffies(275) +#define IO_WATCHDOG_OFF 0xffffff00 #include "ohci.h" #include "pci-quirks.h" @@ -231,7 +232,7 @@ static int ohci_urb_enqueue ( } /* Start up the I/O watchdog timer, if it's not running */ - if (!timer_pending(&ohci->io_watchdog) && + if (ohci->prev_frame_no == IO_WATCHDOG_OFF && list_empty(&ohci->eds_in_use) && !(ohci->flags & OHCI_QUIRK_QEMU)) { ohci->prev_frame_no = ohci_frame_no(ohci); @@ -501,6 +502,7 @@ static int ohci_init (struct ohci_hcd *ohci) return 0; timer_setup(&ohci->io_watchdog, io_watchdog_func, 0); + ohci->prev_frame_no = IO_WATCHDOG_OFF; ohci->hcca = dma_alloc_coherent (hcd->self.controller, sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL); @@ -730,7 +732,7 @@ static void io_watchdog_func(struct timer_list *t) u32 head; struct ed *ed; struct td *td, *td_start, *td_next; - unsigned frame_no; + unsigned frame_no, prev_frame_no = IO_WATCHDOG_OFF; unsigned long flags; spin_lock_irqsave(&ohci->lock, flags); @@ -835,7 +837,7 @@ static void io_watchdog_func(struct timer_list *t) } } if (!list_empty(&ohci->eds_in_use)) { - ohci->prev_frame_no = frame_no; + prev_frame_no = frame_no; ohci->prev_wdh_cnt = ohci->wdh_cnt; ohci->prev_donehead = ohci_readl(ohci, &ohci->regs->donehead); @@ -845,6 +847,7 @@ static void io_watchdog_func(struct timer_list *t) } done: + ohci->prev_frame_no = prev_frame_no; spin_unlock_irqrestore(&ohci->lock, flags); } @@ -973,6 +976,7 @@ static void ohci_stop (struct usb_hcd *hcd) if (quirk_nec(ohci)) flush_work(&ohci->nec_work); del_timer_sync(&ohci->io_watchdog); + ohci->prev_frame_no = IO_WATCHDOG_OFF; ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); ohci_usb_reset(ohci); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index fb7aaa3b9d06..634f3c7bf774 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -311,8 +311,10 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) rc = ohci_rh_suspend (ohci, 0); spin_unlock_irq (&ohci->lock); - if (rc == 0) + if (rc == 0) { del_timer_sync(&ohci->io_watchdog); + ohci->prev_frame_no = IO_WATCHDOG_OFF; + } return rc; } -- cgit v1.2.3 From 009f41aed4b3e11e6dc1e3c07377a10c20f1a5ed Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 26 Jan 2018 11:56:50 -0700 Subject: usbip: keep usbip_device sockfd state in sync with tcp_socket Keep usbip_device sockfd state in sync with tcp_socket. When tcp_socket is reset to null, reset sockfd to -1 to keep it in sync. Signed-off-by: Shuah Khan Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/stub_dev.c | 3 +++ drivers/usb/usbip/vhci_hcd.c | 2 ++ 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c index 49e552472c3f..dd8ef36ab10e 100644 --- a/drivers/usb/usbip/stub_dev.c +++ b/drivers/usb/usbip/stub_dev.c @@ -73,6 +73,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a goto err; sdev->ud.tcp_socket = socket; + sdev->ud.sockfd = sockfd; spin_unlock_irq(&sdev->ud.lock); @@ -172,6 +173,7 @@ static void stub_shutdown_connection(struct usbip_device *ud) if (ud->tcp_socket) { sockfd_put(ud->tcp_socket); ud->tcp_socket = NULL; + ud->sockfd = -1; } /* 3. free used data */ @@ -266,6 +268,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev) sdev->ud.status = SDEV_ST_AVAILABLE; spin_lock_init(&sdev->ud.lock); sdev->ud.tcp_socket = NULL; + sdev->ud.sockfd = -1; INIT_LIST_HEAD(&sdev->priv_init); INIT_LIST_HEAD(&sdev->priv_tx); diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index c3e1008aa491..20e3d4609583 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -984,6 +984,7 @@ static void vhci_shutdown_connection(struct usbip_device *ud) if (vdev->ud.tcp_socket) { sockfd_put(vdev->ud.tcp_socket); vdev->ud.tcp_socket = NULL; + vdev->ud.sockfd = -1; } pr_info("release socket\n"); @@ -1030,6 +1031,7 @@ static void vhci_device_reset(struct usbip_device *ud) if (ud->tcp_socket) { sockfd_put(ud->tcp_socket); ud->tcp_socket = NULL; + ud->sockfd = -1; } ud->status = VDEV_ST_NULL; -- cgit v1.2.3 From 02a10f061a3f8bca1b37332672f50a107198adbe Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 1 Feb 2018 12:26:43 +0800 Subject: usb: host: ehci: use correct device pointer for dma ops commit a8c06e407ef9 ("usb: separate out sysdev pointer from usb_bus") converted to use hcd->self.sysdev for DMA operations instead of hcd->self.controller, but forgot to do it for hcd test mode. Replace the correct one in this commit. Fixes: a8c06e407ef9 ("usb: separate out sysdev pointer from usb_bus") Signed-off-by: Peter Chen Acked-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index facafdf8fb95..d7641cbdee43 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -774,12 +774,12 @@ static struct urb *request_single_step_set_feature_urb( atomic_inc(&urb->use_count); atomic_inc(&urb->dev->urbnum); urb->setup_dma = dma_map_single( - hcd->self.controller, + hcd->self.sysdev, urb->setup_packet, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); urb->transfer_dma = dma_map_single( - hcd->self.controller, + hcd->self.sysdev, urb->transfer_buffer, urb->transfer_buffer_length, DMA_FROM_DEVICE); -- cgit v1.2.3 From d6efa938ac366fe8cb92d6157f74d43cc35f1c67 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 5 Feb 2018 17:12:35 +0900 Subject: usb: renesas_usbhs: missed the "running" flag in usb_dmac with rx path This fixes an issue that a gadget driver (usb_f_fs) is possible to stop rx transactions after the usb-dmac is used because the following functions missed to set/check the "running" flag. - usbhsf_dma_prepare_pop_with_usb_dmac() - usbhsf_dma_pop_done_with_usb_dmac() So, if next transaction uses pio, the usbhsf_prepare_pop() can not start the transaction because the "running" flag is 0. Fixes: 8355b2b3082d ("usb: renesas_usbhs: fix the behavior of some usbhs_pkt_handle") Cc: # v3.19+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/fifo.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 5925d111bd47..39fa2fc1b8b7 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -982,6 +982,10 @@ static int usbhsf_dma_prepare_pop_with_usb_dmac(struct usbhs_pkt *pkt, if ((uintptr_t)pkt->buf & (USBHS_USB_DMAC_XFER_SIZE - 1)) goto usbhsf_pio_prepare_pop; + /* return at this time if the pipe is running */ + if (usbhs_pipe_is_running(pipe)) + return 0; + usbhs_pipe_config_change_bfre(pipe, 1); ret = usbhsf_fifo_select(pipe, fifo, 0); @@ -1172,6 +1176,7 @@ static int usbhsf_dma_pop_done_with_usb_dmac(struct usbhs_pkt *pkt, usbhsf_fifo_clear(pipe, fifo); pkt->actual = usbhs_dma_calc_received_size(pkt, chan, rcv_len); + usbhs_pipe_running(pipe, 0); usbhsf_dma_stop(pipe, fifo); usbhsf_dma_unmap(pkt); usbhsf_fifo_unselect(pipe, pipe->fifo); -- cgit v1.2.3 From 52ad2bd8918158266fc88a05f95429b56b6a33c5 Mon Sep 17 00:00:00 2001 From: Karsten Koop Date: Fri, 9 Feb 2018 09:12:06 +0000 Subject: usb: ldusb: add PIDs for new CASSY devices supported by this driver This patch adds support for new CASSY devices to the ldusb driver. The PIDs are also added to the ignore list in hid-quirks. Signed-off-by: Karsten Koop Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-quirks.c | 3 +++ drivers/usb/misc/ldusb.c | 6 ++++++ 3 files changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 43ddcdfbd0da..9454ac134ce2 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -645,6 +645,9 @@ #define USB_DEVICE_ID_LD_MICROCASSYTIME 0x1033 #define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035 #define USB_DEVICE_ID_LD_MICROCASSYPH 0x1038 +#define USB_DEVICE_ID_LD_POWERANALYSERCASSY 0x1040 +#define USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY 0x1042 +#define USB_DEVICE_ID_LD_MACHINETESTCASSY 0x1043 #define USB_DEVICE_ID_LD_JWM 0x1080 #define USB_DEVICE_ID_LD_DMMP 0x1081 #define USB_DEVICE_ID_LD_UMIP 0x1090 diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 5f6035a5ce36..e92b77fa574a 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -809,6 +809,9 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) }, diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 63b9e85dc0e9..236a60f53099 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -42,6 +42,9 @@ #define USB_DEVICE_ID_LD_MICROCASSYTIME 0x1033 /* USB Product ID of Micro-CASSY Time (reserved) */ #define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035 /* USB Product ID of Micro-CASSY Temperature */ #define USB_DEVICE_ID_LD_MICROCASSYPH 0x1038 /* USB Product ID of Micro-CASSY pH */ +#define USB_DEVICE_ID_LD_POWERANALYSERCASSY 0x1040 /* USB Product ID of Power Analyser CASSY */ +#define USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY 0x1042 /* USB Product ID of Converter Controller CASSY */ +#define USB_DEVICE_ID_LD_MACHINETESTCASSY 0x1043 /* USB Product ID of Machine Test CASSY */ #define USB_DEVICE_ID_LD_JWM 0x1080 /* USB Product ID of Joule and Wattmeter */ #define USB_DEVICE_ID_LD_DMMP 0x1081 /* USB Product ID of Digital Multimeter P (reserved) */ #define USB_DEVICE_ID_LD_UMIP 0x1090 /* USB Product ID of UMI P */ @@ -84,6 +87,9 @@ static const struct usb_device_id ld_usb_table[] = { { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) }, { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) }, { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) }, { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) }, { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) }, { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) }, -- cgit v1.2.3 From 91b119359c1c3033a6621909d3c5dbbdf201d6b4 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Mon, 5 Feb 2018 11:50:56 +0800 Subject: usb: host: ehci: always enable interrupt for qtd completion at test mode At former code, the SETUP stage does not enable interrupt for qtd completion, it relies on IAA watchdog to complete interrupt, then the transcation would be considered timeout if the flag need_io_watchdog is cleared by platform code. In this commit, we always add enable interrupt for qtd completion, then the qtd completion can be notified by hardware interrupt. Signed-off-by: Peter Chen Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-q.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 88158324dcae..327630405695 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -1188,10 +1188,10 @@ static int submit_single_step_set_feature( * 15 secs after the setup */ if (is_setup) { - /* SETUP pid */ + /* SETUP pid, and interrupt after SETUP completion */ qtd_fill(ehci, qtd, urb->setup_dma, sizeof(struct usb_ctrlrequest), - token | (2 /* "setup" */ << 8), 8); + QTD_IOC | token | (2 /* "setup" */ << 8), 8); submit_async(ehci, urb, &qtd_list, GFP_ATOMIC); return 0; /*Return now; we shall come back after 15 seconds*/ @@ -1228,12 +1228,8 @@ static int submit_single_step_set_feature( qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma); list_add_tail(&qtd->qtd_list, head); - /* dont fill any data in such packets */ - qtd_fill(ehci, qtd, 0, 0, token, 0); - - /* by default, enable interrupt on urb completion */ - if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT))) - qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC); + /* Interrupt after STATUS completion */ + qtd_fill(ehci, qtd, 0, 0, token | QTD_IOC, 0); submit_async(ehci, urb, &qtd_list, GFP_KERNEL); -- cgit v1.2.3 From 46408ea558df13b110e0866b99624384a33bdeba Mon Sep 17 00:00:00 2001 From: AMAN DEEP Date: Thu, 8 Feb 2018 11:55:01 +0800 Subject: usb: ohci: Proper handling of ed_rm_list to handle race condition between usb_kill_urb() and finish_unlinks() There is a race condition between finish_unlinks->finish_urb() function and usb_kill_urb() in ohci controller case. The finish_urb calls spin_unlock(&ohci->lock) before usb_hcd_giveback_urb() function call, then if during this time, usb_kill_urb is called for another endpoint, then new ed will be added to ed_rm_list at beginning for unlink, and ed_rm_list will point to newly added. When finish_urb() is completed in finish_unlinks() and ed->td_list becomes empty as in below code (in finish_unlinks() function): if (list_empty(&ed->td_list)) { *last = ed->ed_next; ed->ed_next = NULL; } else if (ohci->rh_state == OHCI_RH_RUNNING) { *last = ed->ed_next; ed->ed_next = NULL; ed_schedule(ohci, ed); } The *last = ed->ed_next will make ed_rm_list to point to ed->ed_next and previously added ed by usb_kill_urb will be left unreferenced by ed_rm_list. This causes usb_kill_urb() hang forever waiting for finish_unlink to remove added ed from ed_rm_list. The main reason for hang in this race condtion is addition and removal of ed from ed_rm_list in the beginning during usb_kill_urb and later last* is modified in finish_unlinks(). As suggested by Alan Stern, the solution for proper handling of ohci->ed_rm_list is to remove ed from the ed_rm_list before finishing any URBs. Then at the end, we can add ed back to the list if necessary. This properly handle the updated ohci->ed_rm_list in usb_kill_urb(). Fixes: 977dcfdc6031 ("USB: OHCI: don't lose track of EDs when a controller dies") Acked-by: Alan Stern CC: Signed-off-by: Aman Deep Signed-off-by: Jeffy Chen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-q.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index b2ec8c399363..4ccb85a67bb3 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -1019,6 +1019,8 @@ skip_ed: * have modified this list. normally it's just prepending * entries (which we'd ignore), but paranoia won't hurt. */ + *last = ed->ed_next; + ed->ed_next = NULL; modified = 0; /* unlink urbs as requested, but rescan the list after @@ -1077,21 +1079,22 @@ rescan_this: goto rescan_this; /* - * If no TDs are queued, take ED off the ed_rm_list. + * If no TDs are queued, ED is now idle. * Otherwise, if the HC is running, reschedule. - * If not, leave it on the list for further dequeues. + * If the HC isn't running, add ED back to the + * start of the list for later processing. */ if (list_empty(&ed->td_list)) { - *last = ed->ed_next; - ed->ed_next = NULL; ed->state = ED_IDLE; list_del(&ed->in_use_list); } else if (ohci->rh_state == OHCI_RH_RUNNING) { - *last = ed->ed_next; - ed->ed_next = NULL; ed_schedule(ohci, ed); } else { - last = &ed->ed_next; + ed->ed_next = ohci->ed_rm_list; + ohci->ed_rm_list = ed; + /* Don't loop on the same ED */ + if (last == &ohci->ed_rm_list) + last = &ed->ed_next; } if (modified) -- cgit v1.2.3 From 7a1646d922577b5b48c0d222e03831141664bb59 Mon Sep 17 00:00:00 2001 From: Jack Stocker Date: Thu, 15 Feb 2018 18:24:10 +0000 Subject: Add delay-init quirk for Corsair K70 RGB keyboards Following on from this patch: https://lkml.org/lkml/2017/11/3/516, Corsair K70 RGB keyboards also require the DELAY_INIT quirk to start correctly at boot. Device ids found here: usb 3-3: New USB device found, idVendor=1b1c, idProduct=1b13 usb 3-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3 usb 3-3: Product: Corsair K70 RGB Gaming Keyboard Signed-off-by: Jack Stocker Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 4024926c1d68..f4a548471f0f 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -226,6 +226,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1a0a, 0x0200), .driver_info = USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + /* Corsair K70 RGB */ + { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Corsair Strafe RGB */ { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT }, -- cgit v1.2.3 From ec897569ad7dbc6d595873a487c3fac23f463f76 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 31 Jan 2018 22:24:45 +0000 Subject: usb: Move USB_UHCI_BIG_ENDIAN_* out of USB_SUPPORT Move the Kconfig symbols USB_UHCI_BIG_ENDIAN_MMIO and USB_UHCI_BIG_ENDIAN_DESC out of drivers/usb/host/Kconfig, which is conditional upon USB && USB_SUPPORT, so that it can be freely selected by platform Kconfig symbols in architecture code. For example once the MIPS_GENERIC platform selects are fixed in commit 2e6522c56552 ("MIPS: Fix typo BIG_ENDIAN to CPU_BIG_ENDIAN"), the MIPS 32r6_defconfig warns like so: warning: (MIPS_GENERIC) selects USB_UHCI_BIG_ENDIAN_MMIO which has unmet direct dependencies (USB_SUPPORT && USB) warning: (MIPS_GENERIC) selects USB_UHCI_BIG_ENDIAN_DESC which has unmet direct dependencies (USB_SUPPORT && USB) Fixes: 2e6522c56552 ("MIPS: Fix typo BIG_ENDIAN to CPU_BIG_ENDIAN") Signed-off-by: James Hogan Cc: Corentin Labbe Cc: Ralf Baechle Cc: Paul Burton Cc: linux-usb@vger.kernel.org Cc: linux-mips@linux-mips.org Acked-by: Greg Kroah-Hartman Patchwork: https://patchwork.linux-mips.org/patch/18559/ --- drivers/usb/Kconfig | 8 ++++++++ drivers/usb/host/Kconfig | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index f699abab1787..65812a2f60b4 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -19,6 +19,14 @@ config USB_EHCI_BIG_ENDIAN_MMIO config USB_EHCI_BIG_ENDIAN_DESC bool +config USB_UHCI_BIG_ENDIAN_MMIO + bool + default y if SPARC_LEON + +config USB_UHCI_BIG_ENDIAN_DESC + bool + default y if SPARC_LEON + menuconfig USB_SUPPORT bool "USB support" depends on HAS_IOMEM diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 6150bed7cfa8..4fcfb3084b36 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -633,14 +633,6 @@ config USB_UHCI_ASPEED bool default y if ARCH_ASPEED -config USB_UHCI_BIG_ENDIAN_MMIO - bool - default y if SPARC_LEON - -config USB_UHCI_BIG_ENDIAN_DESC - bool - default y if SPARC_LEON - config USB_FHCI_HCD tristate "Freescale QE USB Host Controller support" depends on OF_GPIO && QE_GPIO && QUICC_ENGINE -- cgit v1.2.3 From 5efad9eee33ee5fc4bf3059f74f3932a638534d1 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 31 Jan 2018 22:24:46 +0000 Subject: sparc,leon: Select USB_UHCI_BIG_ENDIAN_{MMIO,DESC} Now that USB_UHCI_BIG_ENDIAN_MMIO and USB_UHCI_BIG_ENDIAN_DESC are moved outside of the USB_SUPPORT conditional, simply select them from SPARC_LEON rather than by the symbol's defaults in drivers/usb/Kconfig, similar to how it is done for USB_EHCI_BIG_ENDIAN_MMIO and USB_EHCI_BIG_ENDIAN_DESC. Signed-off-by: James Hogan Cc: "David S. Miller" Cc: Greg Kroah-Hartman Cc: Corentin Labbe Cc: sparclinux@vger.kernel.org Cc: linux-usb@vger.kernel.org Acked-by: David S. Miller Patchwork: https://patchwork.linux-mips.org/patch/18560/ --- drivers/usb/Kconfig | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 65812a2f60b4..148f3ee70286 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -21,11 +21,9 @@ config USB_EHCI_BIG_ENDIAN_DESC config USB_UHCI_BIG_ENDIAN_MMIO bool - default y if SPARC_LEON config USB_UHCI_BIG_ENDIAN_DESC bool - default y if SPARC_LEON menuconfig USB_SUPPORT bool "USB support" -- cgit v1.2.3 From 14fa91e0fef8e4d6feb8b1fa2a807828e0abe815 Mon Sep 17 00:00:00 2001 From: Alaa Hleihel Date: Tue, 13 Feb 2018 12:18:27 +0200 Subject: IB/ipoib: Do not warn if IPoIB debugfs doesn't exist netdev_wait_allrefs() could rebroadcast NETDEV_UNREGISTER event multiple times until all refs are gone, which will result in calling ipoib_delete_debug_files multiple times and printing a warning. Remove the WARN_ONCE since checks of NULL pointers before calling debugfs_remove are not needed. Fixes: 771a52584096 ("IB/IPoIB: ibX: failed to create mcg debug file") Signed-off-by: Alaa Hleihel Signed-off-by: Leon Romanovsky Reviewed-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/ulp/ipoib/ipoib_fs.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c index 11f74cbe6660..ea302b054601 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c @@ -281,8 +281,6 @@ void ipoib_delete_debug_files(struct net_device *dev) { struct ipoib_dev_priv *priv = ipoib_priv(dev); - WARN_ONCE(!priv->mcg_dentry, "null mcg debug file\n"); - WARN_ONCE(!priv->path_dentry, "null path debug file\n"); debugfs_remove(priv->mcg_dentry); debugfs_remove(priv->path_dentry); priv->mcg_dentry = priv->path_dentry = NULL; -- cgit v1.2.3 From 415bb699d793f7ad9c67c04a766d1e655fa6b203 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 13 Feb 2018 12:18:28 +0200 Subject: RDMA/restrack: Remove unimplemented XRCD object Resource tracking of XRCD objects is not implemented in current version of restrack and hence can be removed. Fixes: 02d8883f520e ("RDMA/restrack: Add general infrastructure to track RDMA resources") Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/restrack.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c index 857637bf46da..d8dc709a3715 100644 --- a/drivers/infiniband/core/restrack.c +++ b/drivers/infiniband/core/restrack.c @@ -63,7 +63,6 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res) { enum rdma_restrack_type type = res->type; struct ib_device *dev; - struct ib_xrcd *xrcd; struct ib_pd *pd; struct ib_cq *cq; struct ib_qp *qp; @@ -81,10 +80,6 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res) qp = container_of(res, struct ib_qp, res); dev = qp->device; break; - case RDMA_RESTRACK_XRCD: - xrcd = container_of(res, struct ib_xrcd, res); - dev = xrcd->device; - break; default: WARN_ONCE(true, "Wrong resource tracking type %u\n", type); return NULL; -- cgit v1.2.3 From 89d9e8d3f14d807bbd7725f8f6f5eeb7f6f5c42f Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Tue, 13 Feb 2018 12:18:29 +0200 Subject: IB/uverbs: Always use the attribute size provided by the user This fixes several bugs around the copy_to/from user path: - copy_to used the user provided size of the attribute and could copy data beyond the end of the kernel buffer into userspace. - copy_from didn't know the size of the kernel buffer and could have left kernel memory unexpectedly un-initialized. - copy_from did not use the user length to determine if the attribute data is inlined or not. Signed-off-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_std_types.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_std_types.c b/drivers/infiniband/core/uverbs_std_types.c index cab0ac3556eb..c6502c7b7c46 100644 --- a/drivers/infiniband/core/uverbs_std_types.c +++ b/drivers/infiniband/core/uverbs_std_types.c @@ -323,7 +323,8 @@ static int uverbs_create_cq_handler(struct ib_device *ib_dev, cq->res.type = RDMA_RESTRACK_CQ; rdma_restrack_add(&cq->res); - ret = uverbs_copy_to(attrs, CREATE_CQ_RESP_CQE, &cq->cqe); + ret = uverbs_copy_to(attrs, CREATE_CQ_RESP_CQE, &cq->cqe, + sizeof(cq->cqe)); if (ret) goto err_cq; @@ -375,7 +376,7 @@ static int uverbs_destroy_cq_handler(struct ib_device *ib_dev, resp.comp_events_reported = obj->comp_events_reported; resp.async_events_reported = obj->async_events_reported; - return uverbs_copy_to(attrs, DESTROY_CQ_RESP, &resp); + return uverbs_copy_to(attrs, DESTROY_CQ_RESP, &resp, sizeof(resp)); } static DECLARE_UVERBS_METHOD( -- cgit v1.2.3 From 6c976c30ad1c205bd6e34182c5ba9a1267d752ca Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 13 Feb 2018 12:18:30 +0200 Subject: IB/uverbs: Use inline data transfer for UHW_IN The rule for the API is pointers less than 8 bytes are inlined into the .data field of the attribute. Fix the creation of the driver udata struct to follow this rule and point to the .data itself when the size is less than 8 bytes. Otherwise if the UHW struct is less than 8 bytes the driver will get EFAULT during copy_from_user. Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_std_types.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_std_types.c b/drivers/infiniband/core/uverbs_std_types.c index c6502c7b7c46..7b0e4d778d79 100644 --- a/drivers/infiniband/core/uverbs_std_types.c +++ b/drivers/infiniband/core/uverbs_std_types.c @@ -234,8 +234,11 @@ static void create_udata(struct uverbs_attr_bundle *ctx, uverbs_attr_get(ctx, UVERBS_UHW_OUT); if (!IS_ERR(uhw_in)) { - udata->inbuf = uhw_in->ptr_attr.ptr; udata->inlen = uhw_in->ptr_attr.len; + if (uverbs_attr_ptr_is_inline(uhw_in)) + udata->inbuf = &uhw_in->uattr->data; + else + udata->inbuf = uhw_in->ptr_attr.ptr; } else { udata->inbuf = NULL; udata->inlen = 0; -- cgit v1.2.3 From 2f36028ce98ef8e9c04809cc20b9dc498cc1a508 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 13 Feb 2018 12:18:31 +0200 Subject: IB/uverbs: Use u64_to_user_ptr() not a union The union approach will get the endianness wrong sometimes if the kernel's pointer size is 32 bits resulting in EFAULTs when trying to copy to/from user. Signed-off-by: Leon Romanovsky Reviewed-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_std_types.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_std_types.c b/drivers/infiniband/core/uverbs_std_types.c index 7b0e4d778d79..df1360e6774f 100644 --- a/drivers/infiniband/core/uverbs_std_types.c +++ b/drivers/infiniband/core/uverbs_std_types.c @@ -238,14 +238,14 @@ static void create_udata(struct uverbs_attr_bundle *ctx, if (uverbs_attr_ptr_is_inline(uhw_in)) udata->inbuf = &uhw_in->uattr->data; else - udata->inbuf = uhw_in->ptr_attr.ptr; + udata->inbuf = u64_to_user_ptr(uhw_in->ptr_attr.data); } else { udata->inbuf = NULL; udata->inlen = 0; } if (!IS_ERR(uhw_out)) { - udata->outbuf = uhw_out->ptr_attr.ptr; + udata->outbuf = u64_to_user_ptr(uhw_out->ptr_attr.data); udata->outlen = uhw_out->ptr_attr.len; } else { udata->outbuf = NULL; -- cgit v1.2.3 From 3d89459e2ef92cc0e5a50dde868780ccda9786c1 Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Tue, 13 Feb 2018 12:18:32 +0200 Subject: IB/uverbs: Fix method merging in uverbs_ioctl_merge Fix a bug in uverbs_ioctl_merge that looked at the object's iterator number instead of the method's iterator number when merging methods. While we're at it, make the uverbs_ioctl_merge code a bit more clear and faster. Fixes: 118620d3686b ('IB/core: Add uverbs merge trees functionality') Signed-off-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_ioctl_merge.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_ioctl_merge.c b/drivers/infiniband/core/uverbs_ioctl_merge.c index 062485f9300d..62e1eb1d2a28 100644 --- a/drivers/infiniband/core/uverbs_ioctl_merge.c +++ b/drivers/infiniband/core/uverbs_ioctl_merge.c @@ -114,6 +114,7 @@ static size_t get_elements_above_id(const void **iters, short min = SHRT_MAX; const void *elem; int i, j, last_stored = -1; + unsigned int equal_min = 0; for_each_element(elem, i, j, elements, num_elements, num_offset, data_offset) { @@ -136,6 +137,10 @@ static size_t get_elements_above_id(const void **iters, */ iters[last_stored == i ? num_iters - 1 : num_iters++] = elem; last_stored = i; + if (min == GET_ID(id)) + equal_min++; + else + equal_min = 1; min = GET_ID(id); } @@ -146,15 +151,10 @@ static size_t get_elements_above_id(const void **iters, * Therefore, we need to clean the beginning of the array to make sure * all ids of final elements are equal to min. */ - for (i = num_iters - 1; i >= 0 && - GET_ID(*(u16 *)(iters[i] + id_offset)) == min; i--) - ; - - num_iters -= i + 1; - memmove(iters, iters + i + 1, sizeof(*iters) * num_iters); + memmove(iters, iters + num_iters - equal_min, sizeof(*iters) * equal_min); *min_id = min; - return num_iters; + return equal_min; } #define find_max_element_entry_id(num_elements, elements, num_objects_fld, \ @@ -322,7 +322,7 @@ static struct uverbs_method_spec *build_method_with_attrs(const struct uverbs_me hash = kzalloc(sizeof(*hash) + ALIGN(sizeof(*hash->attrs) * (attr_max_bucket + 1), sizeof(long)) + - BITS_TO_LONGS(attr_max_bucket) * sizeof(long), + BITS_TO_LONGS(attr_max_bucket + 1) * sizeof(long), GFP_KERNEL); if (!hash) { res = -ENOMEM; @@ -509,7 +509,7 @@ static struct uverbs_object_spec *build_object_with_methods(const struct uverbs_ * first handler which != NULL. This also defines the * set of flags used for this handler. */ - for (i = num_object_defs - 1; + for (i = num_method_defs - 1; i >= 0 && !method_defs[i]->handler; i--) ; hash->methods[min_id++] = method; -- cgit v1.2.3 From 9dfb2ff400f6c0a52f63014b5331b64ee7bd5c19 Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Tue, 13 Feb 2018 12:18:34 +0200 Subject: IB/uverbs: Add ioctl support for 32bit processes 32 bit processes running on a 64 bit kernel call compat_ioctl so that implementations can revise any structure layout issues. Point compat_ioctl at our normal ioctl because: - All our structures are designed to be the same on 32 and 64 bit, ie we use __aligned_u64 when required and are careful to manage padding. - Any pointers are stored in u64's and userspace is expected to prepare them properly. Signed-off-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 395a3b091229..cd72555ad457 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -942,6 +942,7 @@ static const struct file_operations uverbs_fops = { .llseek = no_llseek, #if IS_ENABLED(CONFIG_INFINIBAND_EXP_USER_ACCESS) .unlocked_ioctl = ib_uverbs_ioctl, + .compat_ioctl = ib_uverbs_ioctl, #endif }; @@ -954,6 +955,7 @@ static const struct file_operations uverbs_mmap_fops = { .llseek = no_llseek, #if IS_ENABLED(CONFIG_INFINIBAND_EXP_USER_ACCESS) .unlocked_ioctl = ib_uverbs_ioctl, + .compat_ioctl = ib_uverbs_ioctl, #endif }; -- cgit v1.2.3 From 4d39a959bc1f3d164b5a54147fdeb19f84b1ed58 Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Tue, 13 Feb 2018 12:18:35 +0200 Subject: IB/uverbs: Fix possible oops with duplicate ioctl attributes If the same attribute is listed twice by the user in the ioctl attribute list then error unwind can cause the kernel to deref garbage. This happens when an object with WRITE access is sent twice. The second parse properly fails but corrupts the state required for the error unwind it triggers. Fixing this by making duplicates in the attribute list invalid. This is not something we need to support. The ioctl interface is currently recommended to be disabled in kConfig. Signed-off-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_ioctl.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index d96dc1d17be1..339b85145044 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -59,6 +59,9 @@ static int uverbs_process_attr(struct ib_device *ibdev, return 0; } + if (test_bit(attr_id, attr_bundle_h->valid_bitmap)) + return -EINVAL; + spec = &attr_spec_bucket->attrs[attr_id]; e = &elements[attr_id]; e->uattr = uattr_ptr; -- cgit v1.2.3 From d9dc7a3500a58de9bf3861d1a96ffeab42624b4f Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 13 Feb 2018 12:18:36 +0200 Subject: IB/uverbs: Hold the uobj write lock after allocate This clarifies the design intention that time between allocate and commit has the uobj exclusive to the caller. We already guarantee this by delaying publishing the uobj pointer via idr_insert, fd_install, list_add, etc. Additionally holding the usecnt lock during this period provides extra clarity and more protection against future mistakes. Fixes: 3832125624b7 ("IB/core: Add support for idr types") Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/rdma_core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index 85b5ee4defa4..3fe6035abde6 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -141,7 +141,12 @@ static struct ib_uobject *alloc_uobj(struct ib_ucontext *context, */ uobj->context = context; uobj->type = type; - atomic_set(&uobj->usecnt, 0); + /* + * Allocated objects start out as write locked to deny any other + * syscalls from accessing them until they are committed. See + * rdma_alloc_commit_uobject + */ + atomic_set(&uobj->usecnt, -1); kref_init(&uobj->ref); return uobj; @@ -527,6 +532,10 @@ int rdma_alloc_commit_uobject(struct ib_uobject *uobj) return ret; } + /* matches atomic_set(-1) in alloc_uobj */ + lockdep_check(uobj, true); + atomic_set(&uobj->usecnt, 0); + uobj->type->type_class->alloc_commit(uobj); up_read(&uobj->context->cleanup_rwsem); -- cgit v1.2.3 From 6623e3e3cd78020016d3fa42555763178e94ab64 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 13 Feb 2018 12:18:37 +0200 Subject: RDMA/uverbs: Protect from races between lookup and destroy of uobjects The race is between lookup_get_idr_uobject and uverbs_idr_remove_uobj -> uverbs_uobject_put. We deliberately do not call sychronize_rcu after the idr_remove in uverbs_idr_remove_uobj for performance reasons, instead we call kfree_rcu() during uverbs_uobject_put. However, this means we can obtain pointers to uobj's that have already been released and must protect against krefing them using kref_get_unless_zero. ================================================================== BUG: KASAN: use-after-free in copy_ah_attr_from_uverbs.isra.2+0x860/0xa00 Read of size 4 at addr ffff88005fda1ac8 by task syz-executor2/441 CPU: 1 PID: 441 Comm: syz-executor2 Not tainted 4.15.0-rc2+ #56 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 Call Trace: dump_stack+0x8d/0xd4 print_address_description+0x73/0x290 kasan_report+0x25c/0x370 ? copy_ah_attr_from_uverbs.isra.2+0x860/0xa00 copy_ah_attr_from_uverbs.isra.2+0x860/0xa00 ? uverbs_try_lock_object+0x68/0xc0 ? modify_qp.isra.7+0xdc4/0x10e0 modify_qp.isra.7+0xdc4/0x10e0 ib_uverbs_modify_qp+0xfe/0x170 ? ib_uverbs_query_qp+0x970/0x970 ? __lock_acquire+0xa11/0x1da0 ib_uverbs_write+0x55a/0xad0 ? ib_uverbs_query_qp+0x970/0x970 ? ib_uverbs_query_qp+0x970/0x970 ? ib_uverbs_open+0x760/0x760 ? futex_wake+0x147/0x410 ? sched_clock_cpu+0x18/0x180 ? check_prev_add+0x1680/0x1680 ? do_futex+0x3b6/0xa30 ? sched_clock_cpu+0x18/0x180 __vfs_write+0xf7/0x5c0 ? ib_uverbs_open+0x760/0x760 ? kernel_read+0x110/0x110 ? lock_acquire+0x370/0x370 ? __fget+0x264/0x3b0 vfs_write+0x18a/0x460 SyS_write+0xc7/0x1a0 ? SyS_read+0x1a0/0x1a0 ? trace_hardirqs_on_thunk+0x1a/0x1c entry_SYSCALL_64_fastpath+0x18/0x85 RIP: 0033:0x448e29 RSP: 002b:00007f443fee0c58 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 00007f443fee16bc RCX: 0000000000448e29 RDX: 0000000000000078 RSI: 00000000209f8000 RDI: 0000000000000012 RBP: 000000000070bea0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00000000ffffffff R13: 0000000000008e98 R14: 00000000006ebf38 R15: 0000000000000000 Allocated by task 1: kmem_cache_alloc_trace+0x16c/0x2f0 mlx5_alloc_cmd_msg+0x12e/0x670 cmd_exec+0x419/0x1810 mlx5_cmd_exec+0x40/0x70 mlx5_core_mad_ifc+0x187/0x220 mlx5_MAD_IFC+0xd7/0x1b0 mlx5_query_mad_ifc_gids+0x1f3/0x650 mlx5_ib_query_gid+0xa4/0xc0 ib_query_gid+0x152/0x1a0 ib_query_port+0x21e/0x290 mlx5_port_immutable+0x30f/0x490 ib_register_device+0x5dd/0x1130 mlx5_ib_add+0x3e7/0x700 mlx5_add_device+0x124/0x510 mlx5_register_interface+0x11f/0x1c0 mlx5_ib_init+0x56/0x61 do_one_initcall+0xa3/0x250 kernel_init_freeable+0x309/0x3b8 kernel_init+0x14/0x180 ret_from_fork+0x24/0x30 Freed by task 1: kfree+0xeb/0x2f0 mlx5_free_cmd_msg+0xcd/0x140 cmd_exec+0xeba/0x1810 mlx5_cmd_exec+0x40/0x70 mlx5_core_mad_ifc+0x187/0x220 mlx5_MAD_IFC+0xd7/0x1b0 mlx5_query_mad_ifc_gids+0x1f3/0x650 mlx5_ib_query_gid+0xa4/0xc0 ib_query_gid+0x152/0x1a0 ib_query_port+0x21e/0x290 mlx5_port_immutable+0x30f/0x490 ib_register_device+0x5dd/0x1130 mlx5_ib_add+0x3e7/0x700 mlx5_add_device+0x124/0x510 mlx5_register_interface+0x11f/0x1c0 mlx5_ib_init+0x56/0x61 do_one_initcall+0xa3/0x250 kernel_init_freeable+0x309/0x3b8 kernel_init+0x14/0x180 ret_from_fork+0x24/0x30 The buggy address belongs to the object at ffff88005fda1ab0 which belongs to the cache kmalloc-32 of size 32 The buggy address is located 24 bytes inside of 32-byte region [ffff88005fda1ab0, ffff88005fda1ad0) The buggy address belongs to the page: page:00000000d5655c19 count:1 mapcount:0 mapping: (null) index:0xffff88005fda1fc0 flags: 0x4000000000000100(slab) raw: 4000000000000100 0000000000000000 ffff88005fda1fc0 0000000180550008 raw: ffffea00017f6780 0000000400000004 ffff88006c803980 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff88005fda1980: fc fc fb fb fb fb fc fc fb fb fb fb fc fc fb fb ffff88005fda1a00: fb fb fc fc fb fb fb fb fc fc 00 00 00 00 fc fc ffff88005fda1a80: fb fb fb fb fc fc fb fb fb fb fc fc fb fb fb fb ffff88005fda1b00: fc fc 00 00 00 00 fc fc fb fb fb fb fc fc fb fb ffff88005fda1b80: fb fb fc fc fb fb fb fb fc fc fb fb fb fb fc fc ==================================================================@ Cc: syzkaller Cc: # 4.11 Fixes: 3832125624b7 ("IB/core: Add support for idr types") Reported-by: Noa Osherovich Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/rdma_core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index 3fe6035abde6..f1f805a0d31a 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -201,7 +201,15 @@ static struct ib_uobject *lookup_get_idr_uobject(const struct uverbs_obj_type *t goto free; } - uverbs_uobject_get(uobj); + /* + * The idr_find is guaranteed to return a pointer to something that + * isn't freed yet, or NULL, as the free after idr_remove goes through + * kfree_rcu(). However the object may still have been released and + * kfree() could be called at any time. + */ + if (!kref_get_unless_zero(&uobj->ref)) + uobj = ERR_PTR(-ENOENT); + free: rcu_read_unlock(); return uobj; -- cgit v1.2.3 From 104f268d439b3c21c83708e52946a4d8d37f3d0f Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 13 Feb 2018 12:18:38 +0200 Subject: IB/uverbs: Improve lockdep_check This is really being used as an assert that the expected usecnt is being held and implicitly that the usecnt is valid. Rename it to assert_uverbs_usecnt and tighten the checks to only accept valid values of usecnt (eg 0 and < -1 are invalid). The tigher checkes make the assertion cover more cases and is more likely to find bugs via syzkaller/etc. Fixes: 3832125624b7 ("IB/core: Add support for idr types") Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/rdma_core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index f1f805a0d31a..cfd257e34e02 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -412,13 +412,13 @@ static int __must_check remove_commit_fd_uobject(struct ib_uobject *uobj, return ret; } -static void lockdep_check(struct ib_uobject *uobj, bool exclusive) +static void assert_uverbs_usecnt(struct ib_uobject *uobj, bool exclusive) { #ifdef CONFIG_LOCKDEP if (exclusive) - WARN_ON(atomic_read(&uobj->usecnt) > 0); + WARN_ON(atomic_read(&uobj->usecnt) != -1); else - WARN_ON(atomic_read(&uobj->usecnt) == -1); + WARN_ON(atomic_read(&uobj->usecnt) <= 0); #endif } @@ -457,7 +457,7 @@ int __must_check rdma_remove_commit_uobject(struct ib_uobject *uobj) WARN(true, "ib_uverbs: Cleanup is running while removing an uobject\n"); return 0; } - lockdep_check(uobj, true); + assert_uverbs_usecnt(uobj, true); ret = _rdma_remove_commit_uobject(uobj, RDMA_REMOVE_DESTROY); up_read(&ucontext->cleanup_rwsem); @@ -487,7 +487,7 @@ int rdma_explicit_destroy(struct ib_uobject *uobject) WARN(true, "ib_uverbs: Cleanup is running while removing an uobject\n"); return 0; } - lockdep_check(uobject, true); + assert_uverbs_usecnt(uobject, true); ret = uobject->type->type_class->remove_commit(uobject, RDMA_REMOVE_DESTROY); if (ret) @@ -541,7 +541,7 @@ int rdma_alloc_commit_uobject(struct ib_uobject *uobj) } /* matches atomic_set(-1) in alloc_uobj */ - lockdep_check(uobj, true); + assert_uverbs_usecnt(uobj, true); atomic_set(&uobj->usecnt, 0); uobj->type->type_class->alloc_commit(uobj); @@ -578,7 +578,7 @@ static void lookup_put_fd_uobject(struct ib_uobject *uobj, bool exclusive) void rdma_lookup_put_uobject(struct ib_uobject *uobj, bool exclusive) { - lockdep_check(uobj, exclusive); + assert_uverbs_usecnt(uobj, exclusive); uobj->type->type_class->lookup_put(uobj, exclusive); /* * In order to unlock an object, either decrease its usecnt for -- cgit v1.2.3 From ec6f8401c48a86809237e86878a6fac6b281118f Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 13 Feb 2018 12:18:40 +0200 Subject: IB/uverbs: Fix unbalanced unlock on error path for rdma_explicit_destroy If remove_commit fails then the lock is left locked while the uobj still exists. Eventually the kernel will deadlock. lockdep detects this and says: test/4221 is leaving the kernel with locks still held! 1 lock held by test/4221: #0: (&ucontext->cleanup_rwsem){.+.+}, at: [<000000001e5c7523>] rdma_explicit_destroy+0x37/0x120 [ib_uverbs] Fixes: 4da70da23e9b ("IB/core: Explicitly destroy an object while keeping uobject") Signed-off-by: Leon Romanovsky Reviewed-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/rdma_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index cfd257e34e02..d8eead5d106d 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -491,12 +491,13 @@ int rdma_explicit_destroy(struct ib_uobject *uobject) ret = uobject->type->type_class->remove_commit(uobject, RDMA_REMOVE_DESTROY); if (ret) - return ret; + goto out; uobject->type = &null_obj_type; +out: up_read(&ucontext->cleanup_rwsem); - return 0; + return ret; } static void alloc_commit_idr_uobject(struct ib_uobject *uobj) -- cgit v1.2.3 From 3f802b162dbf4a558ff98986449eddc717826209 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 13 Feb 2018 12:18:41 +0200 Subject: RDMA/uverbs: Protect from command mask overflow The command number is not bounds checked against the command mask before it is shifted, resulting in an ubsan hit. This does not cause malfunction since the command number is eventually bounds checked, but we can make this ubsan clean by moving the bounds check to before the mask check. ================================================================================ UBSAN: Undefined behaviour in drivers/infiniband/core/uverbs_main.c:647:21 shift exponent 207 is too large for 64-bit type 'long long unsigned int' CPU: 0 PID: 446 Comm: syz-executor3 Not tainted 4.15.0-rc2+ #61 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 Call Trace: dump_stack+0xde/0x164 ? dma_virt_map_sg+0x22c/0x22c ubsan_epilogue+0xe/0x81 __ubsan_handle_shift_out_of_bounds+0x293/0x2f7 ? debug_check_no_locks_freed+0x340/0x340 ? __ubsan_handle_load_invalid_value+0x19b/0x19b ? lock_acquire+0x440/0x440 ? lock_acquire+0x19d/0x440 ? __might_fault+0xf4/0x240 ? ib_uverbs_write+0x68d/0xe20 ib_uverbs_write+0x68d/0xe20 ? __lock_acquire+0xcf7/0x3940 ? uverbs_devnode+0x110/0x110 ? cyc2ns_read_end+0x10/0x10 ? sched_clock_cpu+0x18/0x200 ? sched_clock_cpu+0x18/0x200 __vfs_write+0x10d/0x700 ? uverbs_devnode+0x110/0x110 ? kernel_read+0x170/0x170 ? __fget+0x35b/0x5d0 ? security_file_permission+0x93/0x260 vfs_write+0x1b0/0x550 SyS_write+0xc7/0x1a0 ? SyS_read+0x1a0/0x1a0 ? trace_hardirqs_on_thunk+0x1a/0x1c entry_SYSCALL_64_fastpath+0x18/0x85 RIP: 0033:0x448e29 RSP: 002b:00007f033f567c58 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 00007f033f5686bc RCX: 0000000000448e29 RDX: 0000000000000060 RSI: 0000000020001000 RDI: 0000000000000012 RBP: 000000000070bea0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00000000ffffffff R13: 00000000000056a0 R14: 00000000006e8740 R15: 0000000000000000 ================================================================================ Cc: syzkaller Cc: # 4.5 Fixes: 2dbd5186a39c ("IB/core: IB/core: Allow legacy verbs through extended interfaces") Reported-by: Noa Osherovich Reviewed-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_main.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index cd72555ad457..b1ca223aa380 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -650,12 +650,21 @@ static int verify_command_mask(struct ib_device *ib_dev, __u32 command) return -1; } +static bool verify_command_idx(u32 command, bool extended) +{ + if (extended) + return command < ARRAY_SIZE(uverbs_ex_cmd_table); + + return command < ARRAY_SIZE(uverbs_cmd_table); +} + static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos) { struct ib_uverbs_file *file = filp->private_data; struct ib_device *ib_dev; struct ib_uverbs_cmd_hdr hdr; + bool extended_command; __u32 command; __u32 flags; int srcu_key; @@ -688,6 +697,15 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, } command = hdr.command & IB_USER_VERBS_CMD_COMMAND_MASK; + flags = (hdr.command & + IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT; + + extended_command = flags & IB_USER_VERBS_CMD_FLAG_EXTENDED; + if (!verify_command_idx(command, extended_command)) { + ret = -EINVAL; + goto out; + } + if (verify_command_mask(ib_dev, command)) { ret = -EOPNOTSUPP; goto out; @@ -699,12 +717,8 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, goto out; } - flags = (hdr.command & - IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT; - if (!flags) { - if (command >= ARRAY_SIZE(uverbs_cmd_table) || - !uverbs_cmd_table[command]) { + if (!uverbs_cmd_table[command]) { ret = -EINVAL; goto out; } @@ -725,8 +739,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, struct ib_udata uhw; size_t written_count = count; - if (command >= ARRAY_SIZE(uverbs_ex_cmd_table) || - !uverbs_ex_cmd_table[command]) { + if (!uverbs_ex_cmd_table[command]) { ret = -ENOSYS; goto out; } -- cgit v1.2.3 From 0cba0efcc7238d47a045a8d7a4079f6a22993546 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 14 Feb 2018 12:35:37 +0200 Subject: RDMA/restrack: Increment CQ restrack object before committing Once the uobj is committed it is immediately possible another thread could destroy it, which worst case, can result in a use-after-free of the restrack objects. Cc: syzkaller Fixes: 08f294a1524b ("RDMA/core: Add resource tracking for create and destroy CQs") Reported-by: Noa Osherovich Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_cmd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 256934d1f64f..4e55f8325049 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1030,14 +1030,14 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file, resp.response_length = offsetof(typeof(resp), response_length) + sizeof(resp.response_length); + cq->res.type = RDMA_RESTRACK_CQ; + rdma_restrack_add(&cq->res); + ret = cb(file, obj, &resp, ucore, context); if (ret) goto err_cb; uobj_alloc_commit(&obj->uobject); - cq->res.type = RDMA_RESTRACK_CQ; - rdma_restrack_add(&cq->res); - return obj; err_cb: -- cgit v1.2.3 From 5c2e1c4f926856717f3fd31932e926dc3fe77ebd Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 14 Feb 2018 12:35:38 +0200 Subject: RDMA/uverbs: Fix bad unlock balance in ib_uverbs_close_xrcd There is no matching lock for this mutex. Git history suggests this is just a missed remnant from an earlier version of the function before this locking was moved into uverbs_free_xrcd. Originally this lock was protecting the xrcd_table_delete() ===================================== WARNING: bad unlock balance detected! 4.15.0+ #87 Not tainted ------------------------------------- syzkaller223405/269 is trying to release lock (&uverbs_dev->xrcd_tree_mutex) at: [<00000000b8703372>] ib_uverbs_close_xrcd+0x195/0x1f0 but there are no more locks to release! other info that might help us debug this: 1 lock held by syzkaller223405/269: #0: (&uverbs_dev->disassociate_srcu){....}, at: [<000000005af3b960>] ib_uverbs_write+0x265/0xef0 stack backtrace: CPU: 0 PID: 269 Comm: syzkaller223405 Not tainted 4.15.0+ #87 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 Call Trace: dump_stack+0xde/0x164 ? dma_virt_map_sg+0x22c/0x22c ? ib_uverbs_write+0x265/0xef0 ? console_unlock+0x502/0xbd0 ? ib_uverbs_close_xrcd+0x195/0x1f0 print_unlock_imbalance_bug+0x131/0x160 lock_release+0x59d/0x1100 ? ib_uverbs_close_xrcd+0x195/0x1f0 ? lock_acquire+0x440/0x440 ? lock_acquire+0x440/0x440 __mutex_unlock_slowpath+0x88/0x670 ? wait_for_completion+0x4c0/0x4c0 ? rdma_lookup_get_uobject+0x145/0x2f0 ib_uverbs_close_xrcd+0x195/0x1f0 ? ib_uverbs_open_xrcd+0xdd0/0xdd0 ib_uverbs_write+0x7f9/0xef0 ? cyc2ns_read_end+0x10/0x10 ? ib_uverbs_open_xrcd+0xdd0/0xdd0 ? uverbs_devnode+0x110/0x110 ? cyc2ns_read_end+0x10/0x10 ? cyc2ns_read_end+0x10/0x10 ? sched_clock_cpu+0x18/0x200 __vfs_write+0x10d/0x700 ? uverbs_devnode+0x110/0x110 ? kernel_read+0x170/0x170 ? __fget+0x358/0x5d0 ? security_file_permission+0x93/0x260 vfs_write+0x1b0/0x550 SyS_write+0xc7/0x1a0 ? SyS_read+0x1a0/0x1a0 ? trace_hardirqs_on_thunk+0x1a/0x1c entry_SYSCALL_64_fastpath+0x1e/0x8b RIP: 0033:0x4335c9 Cc: syzkaller Cc: # 4.11 Fixes: fd3c7904db6e ("IB/core: Change idr objects to use the new schema") Reported-by: Noa Osherovich Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_cmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 4e55f8325049..1187b757d911 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -603,10 +603,8 @@ ssize_t ib_uverbs_close_xrcd(struct ib_uverbs_file *file, uobj = uobj_get_write(uobj_get_type(xrcd), cmd.xrcd_handle, file->ucontext); - if (IS_ERR(uobj)) { - mutex_unlock(&file->device->xrcd_tree_mutex); + if (IS_ERR(uobj)) return PTR_ERR(uobj); - } ret = uobj_remove_commit(uobj); return ret ?: in_len; -- cgit v1.2.3 From 1ff5325c3ca1843228a86549318bbd3b414b9207 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 14 Feb 2018 12:35:39 +0200 Subject: RDMA/uverbs: Fix circular locking dependency Avoid circular locking dependency by calling to uobj_alloc_commit() outside of xrcd_tree_mutex lock. ====================================================== WARNING: possible circular locking dependency detected 4.15.0+ #87 Not tainted ------------------------------------------------------ syzkaller401056/269 is trying to acquire lock: (&uverbs_dev->xrcd_tree_mutex){+.+.}, at: [<000000006c12d2cd>] uverbs_free_xrcd+0xd2/0x360 but task is already holding lock: (&ucontext->uobjects_lock){+.+.}, at: [<00000000da010f09>] uverbs_cleanup_ucontext+0x168/0x730 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&ucontext->uobjects_lock){+.+.}: __mutex_lock+0x111/0x1720 rdma_alloc_commit_uobject+0x22c/0x600 ib_uverbs_open_xrcd+0x61a/0xdd0 ib_uverbs_write+0x7f9/0xef0 __vfs_write+0x10d/0x700 vfs_write+0x1b0/0x550 SyS_write+0xc7/0x1a0 entry_SYSCALL_64_fastpath+0x1e/0x8b -> #0 (&uverbs_dev->xrcd_tree_mutex){+.+.}: lock_acquire+0x19d/0x440 __mutex_lock+0x111/0x1720 uverbs_free_xrcd+0xd2/0x360 remove_commit_idr_uobject+0x6d/0x110 uverbs_cleanup_ucontext+0x2f0/0x730 ib_uverbs_cleanup_ucontext.constprop.3+0x52/0x120 ib_uverbs_close+0xf2/0x570 __fput+0x2cd/0x8d0 task_work_run+0xec/0x1d0 do_exit+0x6a1/0x1520 do_group_exit+0xe8/0x380 SyS_exit_group+0x1e/0x20 entry_SYSCALL_64_fastpath+0x1e/0x8b other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&ucontext->uobjects_lock); lock(&uverbs_dev->xrcd_tree_mutex); lock(&ucontext->uobjects_lock); lock(&uverbs_dev->xrcd_tree_mutex); *** DEADLOCK *** 3 locks held by syzkaller401056/269: #0: (&file->cleanup_mutex){+.+.}, at: [<00000000c9f0c252>] ib_uverbs_close+0xac/0x570 #1: (&ucontext->cleanup_rwsem){++++}, at: [<00000000b6994d49>] uverbs_cleanup_ucontext+0xf6/0x730 #2: (&ucontext->uobjects_lock){+.+.}, at: [<00000000da010f09>] uverbs_cleanup_ucontext+0x168/0x730 stack backtrace: CPU: 0 PID: 269 Comm: syzkaller401056 Not tainted 4.15.0+ #87 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 Call Trace: dump_stack+0xde/0x164 ? dma_virt_map_sg+0x22c/0x22c ? uverbs_cleanup_ucontext+0x168/0x730 ? console_unlock+0x502/0xbd0 print_circular_bug.isra.24+0x35e/0x396 ? print_circular_bug_header+0x12e/0x12e ? find_usage_backwards+0x30/0x30 ? entry_SYSCALL_64_fastpath+0x1e/0x8b validate_chain.isra.28+0x25d1/0x40c0 ? check_usage+0xb70/0xb70 ? graph_lock+0x160/0x160 ? find_usage_backwards+0x30/0x30 ? cyc2ns_read_end+0x10/0x10 ? print_irqtrace_events+0x280/0x280 ? __lock_acquire+0x93d/0x1630 __lock_acquire+0x93d/0x1630 lock_acquire+0x19d/0x440 ? uverbs_free_xrcd+0xd2/0x360 __mutex_lock+0x111/0x1720 ? uverbs_free_xrcd+0xd2/0x360 ? uverbs_free_xrcd+0xd2/0x360 ? __mutex_lock+0x828/0x1720 ? mutex_lock_io_nested+0x1550/0x1550 ? uverbs_cleanup_ucontext+0x168/0x730 ? __lock_acquire+0x9a9/0x1630 ? mutex_lock_io_nested+0x1550/0x1550 ? uverbs_cleanup_ucontext+0xf6/0x730 ? lock_contended+0x11a0/0x11a0 ? uverbs_free_xrcd+0xd2/0x360 uverbs_free_xrcd+0xd2/0x360 remove_commit_idr_uobject+0x6d/0x110 uverbs_cleanup_ucontext+0x2f0/0x730 ? sched_clock_cpu+0x18/0x200 ? uverbs_close_fd+0x1c0/0x1c0 ib_uverbs_cleanup_ucontext.constprop.3+0x52/0x120 ib_uverbs_close+0xf2/0x570 ? ib_uverbs_remove_one+0xb50/0xb50 ? ib_uverbs_remove_one+0xb50/0xb50 __fput+0x2cd/0x8d0 task_work_run+0xec/0x1d0 do_exit+0x6a1/0x1520 ? fsnotify_first_mark+0x220/0x220 ? exit_notify+0x9f0/0x9f0 ? entry_SYSCALL_64_fastpath+0x5/0x8b ? entry_SYSCALL_64_fastpath+0x5/0x8b ? trace_hardirqs_on_thunk+0x1a/0x1c ? time_hardirqs_on+0x27/0x670 ? time_hardirqs_off+0x27/0x490 ? syscall_return_slowpath+0x6c/0x460 ? entry_SYSCALL_64_fastpath+0x5/0x8b do_group_exit+0xe8/0x380 SyS_exit_group+0x1e/0x20 entry_SYSCALL_64_fastpath+0x1e/0x8b RIP: 0033:0x431ce9 Cc: syzkaller Cc: # 4.11 Fixes: fd3c7904db6e ("IB/core: Change idr objects to use the new schema") Reported-by: Noa Osherovich Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_cmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 1187b757d911..6941faaaf1c3 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -562,9 +562,10 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file, if (f.file) fdput(f); + mutex_unlock(&file->device->xrcd_tree_mutex); + uobj_alloc_commit(&obj->uobject); - mutex_unlock(&file->device->xrcd_tree_mutex); return in_len; err_copy: -- cgit v1.2.3 From 5d4c05c3ee36f67ddc107ab5ea0898af01a62cc1 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 14 Feb 2018 12:35:40 +0200 Subject: RDMA/uverbs: Sanitize user entered port numbers prior to access it ================================================================== BUG: KASAN: use-after-free in copy_ah_attr_from_uverbs+0x6f2/0x8c0 Read of size 4 at addr ffff88006476a198 by task syzkaller697701/265 CPU: 0 PID: 265 Comm: syzkaller697701 Not tainted 4.15.0+ #90 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 Call Trace: dump_stack+0xde/0x164 ? dma_virt_map_sg+0x22c/0x22c ? show_regs_print_info+0x17/0x17 ? lock_contended+0x11a0/0x11a0 print_address_description+0x83/0x3e0 kasan_report+0x18c/0x4b0 ? copy_ah_attr_from_uverbs+0x6f2/0x8c0 ? copy_ah_attr_from_uverbs+0x6f2/0x8c0 ? lookup_get_idr_uobject+0x120/0x200 ? copy_ah_attr_from_uverbs+0x6f2/0x8c0 copy_ah_attr_from_uverbs+0x6f2/0x8c0 ? modify_qp+0xd0e/0x1350 modify_qp+0xd0e/0x1350 ib_uverbs_modify_qp+0xf9/0x170 ? ib_uverbs_query_qp+0xa70/0xa70 ib_uverbs_write+0x7f9/0xef0 ? attach_entity_load_avg+0x8b0/0x8b0 ? ib_uverbs_query_qp+0xa70/0xa70 ? uverbs_devnode+0x110/0x110 ? cyc2ns_read_end+0x10/0x10 ? print_irqtrace_events+0x280/0x280 ? sched_clock_cpu+0x18/0x200 ? _raw_spin_unlock_irq+0x29/0x40 ? _raw_spin_unlock_irq+0x29/0x40 ? _raw_spin_unlock_irq+0x29/0x40 ? time_hardirqs_on+0x27/0x670 __vfs_write+0x10d/0x700 ? uverbs_devnode+0x110/0x110 ? kernel_read+0x170/0x170 ? _raw_spin_unlock_irq+0x29/0x40 ? finish_task_switch+0x1bd/0x7a0 ? finish_task_switch+0x194/0x7a0 ? prandom_u32_state+0xe/0x180 ? rcu_read_unlock+0x80/0x80 ? security_file_permission+0x93/0x260 vfs_write+0x1b0/0x550 SyS_write+0xc7/0x1a0 ? SyS_read+0x1a0/0x1a0 ? trace_hardirqs_on_thunk+0x1a/0x1c entry_SYSCALL_64_fastpath+0x1e/0x8b RIP: 0033:0x433c29 RSP: 002b:00007ffcf2be82a8 EFLAGS: 00000217 Allocated by task 62: kasan_kmalloc+0xa0/0xd0 kmem_cache_alloc+0x141/0x480 dup_fd+0x101/0xcc0 copy_process.part.62+0x166f/0x4390 _do_fork+0x1cb/0xe90 kernel_thread+0x34/0x40 call_usermodehelper_exec_work+0x112/0x260 process_one_work+0x929/0x1aa0 worker_thread+0x5c6/0x12a0 kthread+0x346/0x510 ret_from_fork+0x3a/0x50 Freed by task 259: kasan_slab_free+0x71/0xc0 kmem_cache_free+0xf3/0x4c0 put_files_struct+0x225/0x2c0 exit_files+0x88/0xc0 do_exit+0x67c/0x1520 do_group_exit+0xe8/0x380 SyS_exit_group+0x1e/0x20 entry_SYSCALL_64_fastpath+0x1e/0x8b The buggy address belongs to the object at ffff88006476a000 which belongs to the cache files_cache of size 832 The buggy address is located 408 bytes inside of 832-byte region [ffff88006476a000, ffff88006476a340) The buggy address belongs to the page: page:ffffea000191da80 count:1 mapcount:0 mapping: (null) index:0x0 compound_mapcount: 0 flags: 0x4000000000008100(slab|head) raw: 4000000000008100 0000000000000000 0000000000000000 0000000100080008 raw: 0000000000000000 0000000100000001 ffff88006bcf7a80 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff88006476a080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff88006476a100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb >ffff88006476a180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ^ ffff88006476a200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff88006476a280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ================================================================== Cc: syzkaller Cc: # 4.11 Fixes: 44c58487d51a ("IB/core: Define 'ib' and 'roce' rdma_ah_attr types") Reported-by: Noa Osherovich Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_cmd.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 6941faaaf1c3..cd9fbd7c82b0 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1970,8 +1970,15 @@ static int modify_qp(struct ib_uverbs_file *file, goto release_qp; } + if ((cmd->base.attr_mask & IB_QP_AV) && + !rdma_is_port_valid(qp->device, cmd->base.dest.port_num)) { + ret = -EINVAL; + goto release_qp; + } + if ((cmd->base.attr_mask & IB_QP_ALT_PATH) && - !rdma_is_port_valid(qp->device, cmd->base.alt_port_num)) { + (!rdma_is_port_valid(qp->device, cmd->base.alt_port_num) || + !rdma_is_port_valid(qp->device, cmd->base.alt_dest.port_num))) { ret = -EINVAL; goto release_qp; } -- cgit v1.2.3 From 1f5a6c47aabc4606f91ad2e6ef71a1ff1924101c Mon Sep 17 00:00:00 2001 From: Adit Ranadive Date: Thu, 15 Feb 2018 12:36:46 -0800 Subject: RDMA/vmw_pvrdma: Fix usage of user response structures in ABI file This ensures that we return the right structures back to userspace. Otherwise, it looks like the reserved fields in the response structures in userspace might have uninitialized data in them. Fixes: 8b10ba783c9d ("RDMA/vmw_pvrdma: Add shared receive queue support") Fixes: 29c8d9eba550 ("IB: Add vmw_pvrdma driver") Suggested-by: Jason Gunthorpe Reviewed-by: Bryan Tan Reviewed-by: Aditya Sarwade Reviewed-by: Jorgen Hansen Signed-off-by: Adit Ranadive Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c | 4 +++- drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c | 4 +++- drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c index faa9478c14a6..f95b97646c25 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c @@ -114,6 +114,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev, union pvrdma_cmd_resp rsp; struct pvrdma_cmd_create_cq *cmd = &req.create_cq; struct pvrdma_cmd_create_cq_resp *resp = &rsp.create_cq_resp; + struct pvrdma_create_cq_resp cq_resp = {0}; struct pvrdma_create_cq ucmd; BUILD_BUG_ON(sizeof(struct pvrdma_cqe) != 64); @@ -197,6 +198,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev, cq->ibcq.cqe = resp->cqe; cq->cq_handle = resp->cq_handle; + cq_resp.cqn = resp->cq_handle; spin_lock_irqsave(&dev->cq_tbl_lock, flags); dev->cq_tbl[cq->cq_handle % dev->dsr->caps.max_cq] = cq; spin_unlock_irqrestore(&dev->cq_tbl_lock, flags); @@ -205,7 +207,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev, cq->uar = &(to_vucontext(context)->uar); /* Copy udata back. */ - if (ib_copy_to_udata(udata, &cq->cq_handle, sizeof(__u32))) { + if (ib_copy_to_udata(udata, &cq_resp, sizeof(cq_resp))) { dev_warn(&dev->pdev->dev, "failed to copy back udata\n"); pvrdma_destroy_cq(&cq->ibcq); diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c index 5acebb1ef631..af235967a9c2 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c @@ -113,6 +113,7 @@ struct ib_srq *pvrdma_create_srq(struct ib_pd *pd, union pvrdma_cmd_resp rsp; struct pvrdma_cmd_create_srq *cmd = &req.create_srq; struct pvrdma_cmd_create_srq_resp *resp = &rsp.create_srq_resp; + struct pvrdma_create_srq_resp srq_resp = {0}; struct pvrdma_create_srq ucmd; unsigned long flags; int ret; @@ -204,12 +205,13 @@ struct ib_srq *pvrdma_create_srq(struct ib_pd *pd, } srq->srq_handle = resp->srqn; + srq_resp.srqn = resp->srqn; spin_lock_irqsave(&dev->srq_tbl_lock, flags); dev->srq_tbl[srq->srq_handle % dev->dsr->caps.max_srq] = srq; spin_unlock_irqrestore(&dev->srq_tbl_lock, flags); /* Copy udata back. */ - if (ib_copy_to_udata(udata, &srq->srq_handle, sizeof(__u32))) { + if (ib_copy_to_udata(udata, &srq_resp, sizeof(srq_resp))) { dev_warn(&dev->pdev->dev, "failed to copy back udata\n"); pvrdma_destroy_srq(&srq->ibsrq); return ERR_PTR(-EINVAL); diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c index 16b96616ef7e..a51463cd2f37 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c @@ -447,6 +447,7 @@ struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev, union pvrdma_cmd_resp rsp; struct pvrdma_cmd_create_pd *cmd = &req.create_pd; struct pvrdma_cmd_create_pd_resp *resp = &rsp.create_pd_resp; + struct pvrdma_alloc_pd_resp pd_resp = {0}; int ret; void *ptr; @@ -475,9 +476,10 @@ struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev, pd->privileged = !context; pd->pd_handle = resp->pd_handle; pd->pdn = resp->pd_handle; + pd_resp.pdn = resp->pd_handle; if (context) { - if (ib_copy_to_udata(udata, &pd->pdn, sizeof(__u32))) { + if (ib_copy_to_udata(udata, &pd_resp, sizeof(pd_resp))) { dev_warn(&dev->pdev->dev, "failed to copy back protection domain\n"); pvrdma_dealloc_pd(&pd->ibpd); -- cgit v1.2.3 From 9ff97fa8db94caeab59a3c5401e975df468b4d8e Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Wed, 14 Feb 2018 00:10:52 -0800 Subject: scsi: megaraid_sas: Do not use 32-bit atomic request descriptor for Ventura controllers Problem Statement: Sending I/O through 32 bit descriptors to Ventura series of controller results in IO timeout on certain conditions. This error only occurs on systems with high I/O activity on Ventura series controllers. Changes in this patch will prevent driver from using 32 bit descriptor and use 64 bit Descriptors. Cc: Signed-off-by: Kashyap Desai Signed-off-by: Shivasharan S Reviewed-by: Hannes Reinecke Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 42 ++++++++++------------------- 1 file changed, 14 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 073ced07e662..dc8e850fbfd2 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -216,36 +216,30 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance, /** * megasas_fire_cmd_fusion - Sends command to the FW * @instance: Adapter soft state - * @req_desc: 32bit or 64bit Request descriptor + * @req_desc: 64bit Request descriptor * - * Perform PCI Write. Ventura supports 32 bit Descriptor. - * Prior to Ventura (12G) MR controller supports 64 bit Descriptor. + * Perform PCI Write. */ static void megasas_fire_cmd_fusion(struct megasas_instance *instance, union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc) { - if (instance->adapter_type == VENTURA_SERIES) - writel(le32_to_cpu(req_desc->u.low), - &instance->reg_set->inbound_single_queue_port); - else { #if defined(writeq) && defined(CONFIG_64BIT) - u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) | - le32_to_cpu(req_desc->u.low)); + u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) | + le32_to_cpu(req_desc->u.low)); - writeq(req_data, &instance->reg_set->inbound_low_queue_port); + writeq(req_data, &instance->reg_set->inbound_low_queue_port); #else - unsigned long flags; - spin_lock_irqsave(&instance->hba_lock, flags); - writel(le32_to_cpu(req_desc->u.low), - &instance->reg_set->inbound_low_queue_port); - writel(le32_to_cpu(req_desc->u.high), - &instance->reg_set->inbound_high_queue_port); - mmiowb(); - spin_unlock_irqrestore(&instance->hba_lock, flags); + unsigned long flags; + spin_lock_irqsave(&instance->hba_lock, flags); + writel(le32_to_cpu(req_desc->u.low), + &instance->reg_set->inbound_low_queue_port); + writel(le32_to_cpu(req_desc->u.high), + &instance->reg_set->inbound_high_queue_port); + mmiowb(); + spin_unlock_irqrestore(&instance->hba_lock, flags); #endif - } } /** @@ -982,7 +976,6 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) const char *sys_info; MFI_CAPABILITIES *drv_ops; u32 scratch_pad_2; - unsigned long flags; ktime_t time; bool cur_fw_64bit_dma_capable; @@ -1121,14 +1114,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) break; } - /* For Ventura also IOC INIT required 64 bit Descriptor write. */ - spin_lock_irqsave(&instance->hba_lock, flags); - writel(le32_to_cpu(req_desc.u.low), - &instance->reg_set->inbound_low_queue_port); - writel(le32_to_cpu(req_desc.u.high), - &instance->reg_set->inbound_high_queue_port); - mmiowb(); - spin_unlock_irqrestore(&instance->hba_lock, flags); + megasas_fire_cmd_fusion(instance, &req_desc); wait_and_poll(instance, cmd, MFI_POLL_TIMEOUT_SECS); -- cgit v1.2.3 From 92256269893e96e5f9e8ac6dd882a0bef63fcea7 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 7 Feb 2018 18:40:27 +0100 Subject: drm/nouveau: Make clock gate support conditional The recently introduced clock gate support breaks on Tegra chips because no thermal support is enabled for those devices. Conditionalize the code on the existence of thermal support to fix this. Fixes: b138eca661cc ("drm/nouveau: Add support for basic clockgating on Kepler1") Cc: Martin Peres Cc: Lyude Paul Signed-off-by: Thierry Reding Reviewed-by: Lyude Paul Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index bf62303571b3..3695cde669f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -301,7 +301,7 @@ nvkm_therm_attr_set(struct nvkm_therm *therm, void nvkm_therm_clkgate_enable(struct nvkm_therm *therm) { - if (!therm->func->clkgate_enable || !therm->clkgating_enabled) + if (!therm || !therm->func->clkgate_enable || !therm->clkgating_enabled) return; nvkm_debug(&therm->subdev, @@ -312,7 +312,7 @@ nvkm_therm_clkgate_enable(struct nvkm_therm *therm) void nvkm_therm_clkgate_fini(struct nvkm_therm *therm, bool suspend) { - if (!therm->func->clkgate_fini || !therm->clkgating_enabled) + if (!therm || !therm->func->clkgate_fini || !therm->clkgating_enabled) return; nvkm_debug(&therm->subdev, @@ -395,7 +395,7 @@ void nvkm_therm_clkgate_init(struct nvkm_therm *therm, const struct nvkm_therm_clkgate_pack *p) { - if (!therm->func->clkgate_init || !therm->clkgating_enabled) + if (!therm || !therm->func->clkgate_init || !therm->clkgating_enabled) return; therm->func->clkgate_init(therm, p); -- cgit v1.2.3 From b86b8eb6fecb5a4bac1ed0ca925c4082a61ea6e9 Mon Sep 17 00:00:00 2001 From: Dominik Bozek Date: Thu, 15 Feb 2018 21:27:48 -0800 Subject: usb: cdc_acm: prevent race at write to acm while system resumes ACM driver may accept data to transmit while system is not fully resumed. In this case ACM driver buffers data and prepare URBs on usb anchor list. There is a little chance that two tasks put a char and initiate acm_tty_flush_chars(). In such a case, driver will put one URB twice on usb anchor list. This patch also reset length of data before resue of a buffer. This not only prevent sending rubbish, but also lower risc of race. Without this patch we hit following kernel panic in one of our stabilty/stress tests. [ 46.884442] *list_add double add*: new=ffff9b2ab7289330, prev=ffff9b2ab7289330, next=ffff9b2ab81e28e0. [ 46.884476] Modules linked in: hci_uart btbcm bluetooth rfkill_gpio igb_avb(O) cfg80211 snd_soc_sst_bxt_tdf8532 snd_soc_skl snd_soc_skl_ipc snd_soc_sst_ipc snd_soc_sst_dsp snd_soc_sst_acpi snd_soc_sst_match snd_hda_ext_core snd_hda_core trusty_timer trusty_wall trusty_log trusty_virtio trusty_ipc trusty_mem trusty_irq trusty virtio_ring virtio intel_ipu4_mmu_bxtB0 lib2600_mod_bxtB0 intel_ipu4_isys_mod_bxtB0 lib2600psys_mod_bxtB0 intel_ipu4_psys_mod_bxtB0 intel_ipu4_mod_bxtB0 intel_ipu4_wrapper_bxtB0 intel_ipu4_acpi videobuf2_dma_contig as3638 dw9714 lm3643 crlmodule smiapp smiapp_pll [ 46.884480] CPU: 1 PID: 33 Comm: kworker/u8:1 Tainted: G U W O 4.9.56-quilt-2e5dc0ac-g618ed69ced6e-dirty #4 [ 46.884489] Workqueue: events_unbound flush_to_ldisc [ 46.884494] ffffb98ac012bb08 ffffffffad3e82e5 ffffb98ac012bb58 0000000000000000 [ 46.884497] ffffb98ac012bb48 ffffffffad0a23d1 00000024ad6374dd ffff9b2ab7289330 [ 46.884500] ffff9b2ab81e28e0 ffff9b2ab7289330 0000000000000002 0000000000000000 [ 46.884501] Call Trace: [ 46.884507] [] dump_stack+0x67/0x92 [ 46.884511] [] __warn+0xd1/0xf0 [ 46.884513] [] warn_slowpath_fmt+0x5f/0x80 [ 46.884516] [] __list_add+0xb3/0xc0 [ 46.884521] [] *usb_anchor_urb*+0x4c/0xa0 [ 46.884524] [] *acm_tty_flush_chars*+0x8f/0xb0 [ 46.884527] [] *acm_tty_put_char*+0x41/0x100 [ 46.884530] [] tty_put_char+0x24/0x40 [ 46.884533] [] do_output_char+0xa5/0x200 [ 46.884535] [] __process_echoes+0x148/0x290 [ 46.884538] [] n_tty_receive_buf_common+0x57c/0xb00 [ 46.884541] [] n_tty_receive_buf2+0x14/0x20 [ 46.884543] [] tty_ldisc_receive_buf+0x22/0x50 [ 46.884545] [] flush_to_ldisc+0xc5/0xe0 [ 46.884549] [] process_one_work+0x148/0x440 [ 46.884551] [] worker_thread+0x69/0x4a0 [ 46.884554] [] ? max_active_store+0x80/0x80 [ 46.884556] [] kthread+0x110/0x130 [ 46.884559] [] ? kthread_park+0x60/0x60 [ 46.884563] [] ret_from_fork+0x27/0x40 [ 46.884566] ---[ end trace 3bd599058b8a9eb3 ]--- Signed-off-by: Dominik Bozek Signed-off-by: Kuppuswamy Sathyanarayanan Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 06b3b54a0e68..7b366a6c0b49 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -174,6 +174,7 @@ static int acm_wb_alloc(struct acm *acm) wb = &acm->wb[wbn]; if (!wb->use) { wb->use = 1; + wb->len = 0; return wbn; } wbn = (wbn + 1) % ACM_NW; @@ -805,16 +806,18 @@ static int acm_tty_write(struct tty_struct *tty, static void acm_tty_flush_chars(struct tty_struct *tty) { struct acm *acm = tty->driver_data; - struct acm_wb *cur = acm->putbuffer; + struct acm_wb *cur; int err; unsigned long flags; + spin_lock_irqsave(&acm->write_lock, flags); + + cur = acm->putbuffer; if (!cur) /* nothing to do */ - return; + goto out; acm->putbuffer = NULL; err = usb_autopm_get_interface_async(acm->control); - spin_lock_irqsave(&acm->write_lock, flags); if (err < 0) { cur->use = 0; acm->putbuffer = cur; -- cgit v1.2.3 From f88982679f54f75daa5b8eff3da72508f1e7422f Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 30 Jan 2018 23:11:24 -0800 Subject: binder: check for binder_thread allocation failure in binder_poll() If the kzalloc() in binder_get_thread() fails, binder_poll() dereferences the resulting NULL pointer. Fix it by returning POLLERR if the memory allocation failed. This bug was found by syzkaller using fault injection. Reported-by: syzbot Fixes: 457b9a6f09f0 ("Staging: android: add binder driver") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 15e3d3c2260d..ad5e662e3e14 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4391,6 +4391,8 @@ static __poll_t binder_poll(struct file *filp, bool wait_for_proc_work; thread = binder_get_thread(proc); + if (!thread) + return POLLERR; binder_inner_proc_lock(thread->proc); thread->looper |= BINDER_LOOPER_STATE_POLL; -- cgit v1.2.3 From e46a3b3ba7509cb7fda0e07bc7c63a2cd90f579b Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Wed, 7 Feb 2018 12:38:47 -0800 Subject: ANDROID: binder: remove WARN() for redundant txn error binder_send_failed_reply() is called when a synchronous transaction fails. It reports an error to the thread that is waiting for the completion. Given that the transaction is synchronous, there should never be more than 1 error response to that thread -- this was being asserted with a WARN(). However, when exercising the driver with syzbot tests, cases were observed where multiple "synchronous" requests were sent without waiting for responses, so it is possible that multiple errors would be reported to the thread. This testing was conducted with panic_on_warn set which forced the crash. This is easily reproduced by sending back-to-back "synchronous" transactions without checking for any response (eg, set read_size to 0): bwr.write_buffer = (uintptr_t)&bc1; bwr.write_size = sizeof(bc1); bwr.read_buffer = (uintptr_t)&br; bwr.read_size = 0; ioctl(fd, BINDER_WRITE_READ, &bwr); sleep(1); bwr2.write_buffer = (uintptr_t)&bc2; bwr2.write_size = sizeof(bc2); bwr2.read_buffer = (uintptr_t)&br; bwr2.read_size = 0; ioctl(fd, BINDER_WRITE_READ, &bwr2); sleep(1); The first transaction is sent to the servicemanager and the reply fails because no VMA is set up by this client. After binder_send_failed_reply() is called, the BINDER_WORK_RETURN_ERROR is sitting on the thread's todo list since the read_size was 0 and the client is not waiting for a response. The 2nd transaction is sent and the BINDER_WORK_RETURN_ERROR has not been consumed, so the thread's reply_error.cmd is still set (normally cleared when the BINDER_WORK_RETURN_ERROR is handled). Therefore when the servicemanager attempts to reply to the 2nd failed transaction, the error is already set and it triggers this warning. This is a user error since it is not waiting for the synchronous transaction to complete. If it ever does check, it will see an error. Changed the WARN() to a pr_warn(). Signed-off-by: Todd Kjos Reported-by: syzbot Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/android/binder.c b/drivers/android/binder.c index ad5e662e3e14..31322e9a235d 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1991,8 +1991,14 @@ static void binder_send_failed_reply(struct binder_transaction *t, &target_thread->reply_error.work); wake_up_interruptible(&target_thread->wait); } else { - WARN(1, "Unexpected reply error: %u\n", - target_thread->reply_error.cmd); + /* + * Cannot get here for normal operation, but + * we can if multiple synchronous transactions + * are sent without blocking for responses. + * Just ignore the 2nd error in this case. + */ + pr_warn("Unexpected reply error: %u\n", + target_thread->reply_error.cmd); } binder_inner_proc_unlock(target_thread->proc); binder_thread_dec_tmpref(target_thread); -- cgit v1.2.3 From 8ca86f1639ec5890d400fff9211aca22d0a392eb Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Wed, 7 Feb 2018 13:57:37 -0800 Subject: binder: replace "%p" with "%pK" The format specifier "%p" can leak kernel addresses. Use "%pK" instead. There were 4 remaining cases in binder.c. Signed-off-by: Todd Kjos Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 31322e9a235d..a85f9033b57e 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2199,7 +2199,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, int debug_id = buffer->debug_id; binder_debug(BINDER_DEBUG_TRANSACTION, - "%d buffer release %d, size %zd-%zd, failed at %p\n", + "%d buffer release %d, size %zd-%zd, failed at %pK\n", proc->pid, buffer->debug_id, buffer->data_size, buffer->offsets_size, failed_at); @@ -3711,7 +3711,7 @@ static int binder_thread_write(struct binder_proc *proc, } } binder_debug(BINDER_DEBUG_DEAD_BINDER, - "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n", + "%d:%d BC_DEAD_BINDER_DONE %016llx found %pK\n", proc->pid, thread->pid, (u64)cookie, death); if (death == NULL) { @@ -5042,7 +5042,7 @@ static void print_binder_transaction_ilocked(struct seq_file *m, spin_lock(&t->lock); to_proc = t->to_proc; seq_printf(m, - "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d", + "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d", prefix, t->debug_id, t, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, @@ -5066,7 +5066,7 @@ static void print_binder_transaction_ilocked(struct seq_file *m, } if (buffer->target_node) seq_printf(m, " node %d", buffer->target_node->debug_id); - seq_printf(m, " size %zd:%zd data %p\n", + seq_printf(m, " size %zd:%zd data %pK\n", buffer->data_size, buffer->offsets_size, buffer->data); } -- cgit v1.2.3 From 5eeb2ca02a2f6084fc57ae5c244a38baab07033a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 16 Feb 2018 09:47:15 +0100 Subject: ANDROID: binder: synchronize_rcu() when using POLLFREE. To prevent races with ep_remove_waitqueue() removing the waitqueue at the same time. Reported-by: syzbot+a2a3c4909716e271487e@syzkaller.appspotmail.com Signed-off-by: Martijn Coenen Cc: stable # 4.14+ Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/android/binder.c b/drivers/android/binder.c index a85f9033b57e..764b63a5aade 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4382,6 +4382,15 @@ static int binder_thread_release(struct binder_proc *proc, binder_inner_proc_unlock(thread->proc); + /* + * This is needed to avoid races between wake_up_poll() above and + * and ep_remove_waitqueue() called for other reasons (eg the epoll file + * descriptor being closed); ep_remove_waitqueue() holds an RCU read + * lock, so we can be sure it's done after calling synchronize_rcu(). + */ + if (thread->looper & BINDER_LOOPER_STATE_POLL) + synchronize_rcu(); + if (send_reply) binder_send_failed_reply(send_reply, BR_DEAD_REPLY); binder_release_work(proc, &thread->todo); -- cgit v1.2.3 From 7ae079aca59f560d2a44b65d45dffdefed6bd17a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 14 Feb 2018 14:03:29 +0200 Subject: mei: set device client to the disconnected state upon suspend. This fixes regression introduced by commit 8d52af6795c0 ("mei: speed up the power down flow") In mei_cldev_disable during device power down flow, such as suspend or system power off, it jumps over disconnecting function to speed up the power down process, however, because the client is unlinked from the file_list (mei_cl_unlink) mei_cl_set_disconnected is not called from mei_cl_all_disconnect leaving resource leaking. The most visible is reference counter on underlying HW module is not decreased preventing to remove modules after suspend/resume cycles. Signed-off-by: Tomas Winkler Fixes: 8d52af6795c0 ("mei: speed up the power down flow") Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 6 ------ drivers/misc/mei/client.c | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 3e5eabdae8d9..772d02922529 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -548,12 +548,6 @@ int mei_cldev_disable(struct mei_cl_device *cldev) goto out; } - if (bus->dev_state == MEI_DEV_POWER_DOWN) { - dev_dbg(bus->dev, "Device is powering down, don't bother with disconnection\n"); - err = 0; - goto out; - } - err = mei_cl_disconnect(cl); if (err < 0) dev_err(bus->dev, "Could not disconnect from the ME client\n"); diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index be64969d986a..7e60c1817c31 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -945,6 +945,12 @@ int mei_cl_disconnect(struct mei_cl *cl) return 0; } + if (dev->dev_state == MEI_DEV_POWER_DOWN) { + cl_dbg(dev, cl, "Device is powering down, don't bother with disconnection\n"); + mei_cl_set_disconnected(cl); + return 0; + } + rets = pm_runtime_get(dev->dev); if (rets < 0 && rets != -EINPROGRESS) { pm_runtime_put_noidle(dev->dev); -- cgit v1.2.3 From 5ab2ba931255d8bf03009c06d58dce97de32797c Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 29 Mar 2016 10:56:57 +0300 Subject: iwlwifi: mvm: fix security bug in PN checking A previous patch allowed the same PN for packets originating from the same AMSDU by copying PN only for the last packet in the series. This however is bogus since we cannot assume the last frame will be received on the same queue, and if it is received on a different ueue we will end up not incrementing the PN and possibly let the next packet to have the same PN and pass through. Change the logic instead to driver explicitly indicate for the second sub frame and on to be allowed to have the same PN as the first subframe. Indicate it to mac80211 as well for the fallback queue. Fixes: f1ae02b186d9 ("iwlwifi: mvm: allow same PN for de-aggregated AMSDU") Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 39 ++++++++++++++------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index a3f7c1bf3cc8..580de5851fc7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -71,6 +71,7 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb); struct iwl_mvm_key_pn *ptk_pn; + int res; u8 tid, keyidx; u8 pn[IEEE80211_CCMP_PN_LEN]; u8 *extiv; @@ -127,12 +128,13 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, pn[4] = extiv[1]; pn[5] = extiv[0]; - if (memcmp(pn, ptk_pn->q[queue].pn[tid], - IEEE80211_CCMP_PN_LEN) <= 0) + res = memcmp(pn, ptk_pn->q[queue].pn[tid], IEEE80211_CCMP_PN_LEN); + if (res < 0) + return -1; + if (!res && !(stats->flag & RX_FLAG_ALLOW_SAME_PN)) return -1; - if (!(stats->flag & RX_FLAG_AMSDU_MORE)) - memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN); + memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN); stats->flag |= RX_FLAG_PN_VALIDATED; return 0; @@ -314,28 +316,21 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, } /* - * returns true if a packet outside BA session is a duplicate and - * should be dropped + * returns true if a packet is a duplicate and should be dropped. + * Updates AMSDU PN tracking info */ -static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, - struct ieee80211_rx_status *rx_status, - struct ieee80211_hdr *hdr, - struct iwl_rx_mpdu_desc *desc) +static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, + struct ieee80211_rx_status *rx_status, + struct ieee80211_hdr *hdr, + struct iwl_rx_mpdu_desc *desc) { struct iwl_mvm_sta *mvm_sta; struct iwl_mvm_rxq_dup_data *dup_data; - u8 baid, tid, sub_frame_idx; + u8 tid, sub_frame_idx; if (WARN_ON(IS_ERR_OR_NULL(sta))) return false; - baid = (le32_to_cpu(desc->reorder_data) & - IWL_RX_MPDU_REORDER_BAID_MASK) >> - IWL_RX_MPDU_REORDER_BAID_SHIFT; - - if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) - return false; - mvm_sta = iwl_mvm_sta_from_mac80211(sta); dup_data = &mvm_sta->dup_data[queue]; @@ -365,6 +360,12 @@ static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, dup_data->last_sub_frame[tid] >= sub_frame_idx)) return true; + /* Allow same PN as the first subframe for following sub frames */ + if (dup_data->last_seq[tid] == hdr->seq_ctrl && + sub_frame_idx > dup_data->last_sub_frame[tid] && + desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) + rx_status->flag |= RX_FLAG_ALLOW_SAME_PN; + dup_data->last_seq[tid] = hdr->seq_ctrl; dup_data->last_sub_frame[tid] = sub_frame_idx; @@ -971,7 +972,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, if (ieee80211_is_data(hdr->frame_control)) iwl_mvm_rx_csum(sta, skb, desc); - if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) { + if (iwl_mvm_is_dup(sta, queue, rx_status, hdr, desc)) { kfree_skb(skb); goto out; } -- cgit v1.2.3 From fc07bd8ce19bff9e7479c04077ddb5957d1a27be Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 21 Dec 2017 15:05:28 +0200 Subject: iwlwifi: mvm: fix IBSS for devices that support station type API In IBSS, the mac80211 sets the cab_queue to be invalid. However, the multicast station uses it, so we need to override it. A previous patch did it, but it was nested inside the if's and was applied only for legacy FWs that don't support the new station type API, instead of being applied for all paths. In addition, add a missing NL80211_IFTYPE_ADHOC to the initialization of the queues in iwl_mvm_mac_ctxt_init() Fixes: ee48b72211f8 ("iwlwifi: mvm: support ibss in dqa mode") Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 3 ++- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 24 +++++++++++------------ 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 2f22e14e00fe..8ba16fc24e3a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -438,7 +438,8 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } /* Allocate the CAB queue for softAP and GO interfaces */ - if (vif->type == NL80211_IFTYPE_AP) { + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_ADHOC) { /* * For TVQM this will be overwritten later with the FW assigned * queue value (when queue is enabled). diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 6b2674e02606..dbd2ba2bb714 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2052,6 +2052,17 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) vif->type != NL80211_IFTYPE_ADHOC)) return -ENOTSUPP; + /* + * In IBSS, ieee80211_check_queues() sets the cab_queue to be + * invalid, so make sure we use the queue we want. + * Note that this is done here as we want to avoid making DQA + * changes in mac80211 layer. + */ + if (vif->type == NL80211_IFTYPE_ADHOC) { + vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; + mvmvif->cab_queue = vif->cab_queue; + } + /* * While in previous FWs we had to exclude cab queue from TFD queue * mask, now it is needed as any other queue. @@ -2083,20 +2094,9 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) timeout); mvmvif->cab_queue = queue; } else if (!fw_has_api(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_API_STA_TYPE)) { - /* - * In IBSS, ieee80211_check_queues() sets the cab_queue to be - * invalid, so make sure we use the queue we want. - * Note that this is done here as we want to avoid making DQA - * changes in mac80211 layer. - */ - if (vif->type == NL80211_IFTYPE_ADHOC) { - vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; - mvmvif->cab_queue = vif->cab_queue; - } + IWL_UCODE_TLV_API_STA_TYPE)) iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0, &cfg, timeout); - } return 0; } -- cgit v1.2.3 From 4437ba7ee7de7e71d11deb91c87a370e4ffd2601 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 27 Dec 2017 08:58:02 +0200 Subject: iwlwifi: pcie: don't warn if we use all the transmit pointers Our Transmit Frame Descriptor (TFD) is a DMA descriptor that includes several pointers to be able to transmit a packet which is not physically contiguous. Depending on the hardware being use, we can have 20 or 25 pointers in a single TFD. In both cases, it is more than enough and it is quite hard to hit this limit. It has been reported that when using specific applications (Ktorrent), we can actually use all the pointers and then a long standing bug showed up. When we free the TFD, we check its number of valid pointers and make sure it doesn't exceed the number of pointers the hardware support. This check had an off by one bug: it is perfectly valid to free the 20 pointers if the TFD has 20 pointers. Fix that. https://bugzilla.kernel.org/show_bug.cgi?id=197981 Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 6d0a907d5ba5..fabae0f60683 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -147,7 +147,7 @@ static void iwl_pcie_gen2_tfd_unmap(struct iwl_trans *trans, /* Sanity check on number of chunks */ num_tbs = iwl_pcie_gen2_get_num_tbs(trans, tfd); - if (num_tbs >= trans_pcie->max_tbs) { + if (num_tbs > trans_pcie->max_tbs) { IWL_ERR(trans, "Too many chunks: %i\n", num_tbs); return; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 3f85713c41dc..1a566287993d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -378,7 +378,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, /* Sanity check on number of chunks */ num_tbs = iwl_pcie_tfd_get_num_tbs(trans, tfd); - if (num_tbs >= trans_pcie->max_tbs) { + if (num_tbs > trans_pcie->max_tbs) { IWL_ERR(trans, "Too many chunks: %i\n", num_tbs); /* @todo issue fatal error, it is quite serious situation */ return; -- cgit v1.2.3 From ac66b8347bbad5913df098e5281fa6e2c7fc796e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 14 Feb 2018 18:45:59 +0000 Subject: gpu: ipu-v3: make const arrays int_reg static, shrinks object size Don't populate the const read-only arrays int_reg on the stack but instead make them static. Makes the object code smaller by over 80 bytes: Before: text data bss dec hex filename 28024 8936 192 37152 9120 drivers/gpu/ipu-v3/ipu-common.o After: text data bss dec hex filename 27794 9080 192 37066 90ca drivers/gpu/ipu-v3/ipu-common.o (gcc version 7.2.0 x86_64) Signed-off-by: Colin Ian King Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 658fa2d3e40c..48685cddbad1 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -1089,7 +1089,7 @@ static void ipu_irq_handler(struct irq_desc *desc) { struct ipu_soc *ipu = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); - const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14}; + static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14}; chained_irq_enter(chip, desc); @@ -1102,7 +1102,7 @@ static void ipu_err_irq_handler(struct irq_desc *desc) { struct ipu_soc *ipu = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); - const int int_reg[] = { 4, 5, 8, 9}; + static const int int_reg[] = { 4, 5, 8, 9}; chained_irq_enter(chip, desc); -- cgit v1.2.3 From 285cb4f62319737e6538252cf1a67ce9da5cf3d5 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Mon, 5 Feb 2018 16:45:36 +0000 Subject: irqchip/mips-gic: Avoid spuriously handling masked interrupts Commit 7778c4b27cbe ("irqchip: mips-gic: Use pcpu_masks to avoid reading GIC_SH_MASK*") removed the read of the hardware mask register when handling shared interrupts, instead using the driver's shadow pcpu_masks entry as the effective mask. Unfortunately this did not take account of the write to pcpu_masks during gic_shared_irq_domain_map, which effectively unmasks the interrupt early. If an interrupt is asserted, gic_handle_shared_int decodes and processes the interrupt even though it has not yet been unmasked via gic_unmask_irq, which also sets the appropriate bit in pcpu_masks. On the MIPS Boston board, when a console command line of "console=ttyS0,115200n8r" is passed, the modem status IRQ is enabled in the UART, which is immediately raised to the GIC. The interrupt has been mapped, but no handler has yet been registered, nor is it expected to be unmasked. However, the write to pcpu_masks in gic_shared_irq_domain_map has effectively unmasked it, resulting in endless reports of: [ 5.058454] irq 13, desc: ffffffff80a7ad80, depth: 1, count: 0, unhandled: 0 [ 5.062057] ->handle_irq(): ffffffff801b1838, [ 5.062175] handle_bad_irq+0x0/0x2c0 Where IRQ 13 is the UART interrupt. To fix this, just remove the write to pcpu_masks in gic_shared_irq_domain_map. The existing write in gic_unmask_irq is the correct place for what is now the effective unmasking. Cc: stable@vger.kernel.org Fixes: 7778c4b27cbe ("irqchip: mips-gic: Use pcpu_masks to avoid reading GIC_SH_MASK*") Signed-off-by: Matt Redfearn Reviewed-by: Paul Burton Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-mips-gic.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index ef92a4d2038e..d32268cc1174 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -424,8 +424,6 @@ static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq, spin_lock_irqsave(&gic_lock, flags); write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin); write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu))); - gic_clear_pcpu_masks(intr); - set_bit(intr, per_cpu_ptr(pcpu_masks, cpu)); irq_data_update_effective_affinity(data, cpumask_of(cpu)); spin_unlock_irqrestore(&gic_lock, flags); -- cgit v1.2.3 From b6dd4d83dc2f78cebc9a7e6e7e4bc2be4d29b94d Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Fri, 2 Feb 2018 09:20:29 -0500 Subject: irqchip/gic-v3: Change pr_debug message to pr_devel The pr_debug() in gic-v3 gic_send_sgi() can trigger a circular locking warning: GICv3: CPU10: ICC_SGI1R_EL1 5000400 ====================================================== WARNING: possible circular locking dependency detected 4.15.0+ #1 Tainted: G W ------------------------------------------------------ dynamic_debug01/1873 is trying to acquire lock: ((console_sem).lock){-...}, at: [<0000000099c891ec>] down_trylock+0x20/0x4c but task is already holding lock: (&rq->lock){-.-.}, at: [<00000000842e1587>] __task_rq_lock+0x54/0xdc which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 (&rq->lock){-.-.}: __lock_acquire+0x3b4/0x6e0 lock_acquire+0xf4/0x2a8 _raw_spin_lock+0x4c/0x60 task_fork_fair+0x3c/0x148 sched_fork+0x10c/0x214 copy_process.isra.32.part.33+0x4e8/0x14f0 _do_fork+0xe8/0x78c kernel_thread+0x48/0x54 rest_init+0x34/0x2a4 start_kernel+0x45c/0x488 -> #1 (&p->pi_lock){-.-.}: __lock_acquire+0x3b4/0x6e0 lock_acquire+0xf4/0x2a8 _raw_spin_lock_irqsave+0x58/0x70 try_to_wake_up+0x48/0x600 wake_up_process+0x28/0x34 __up.isra.0+0x60/0x6c up+0x60/0x68 __up_console_sem+0x4c/0x7c console_unlock+0x328/0x634 vprintk_emit+0x25c/0x390 dev_vprintk_emit+0xc4/0x1fc dev_printk_emit+0x88/0xa8 __dev_printk+0x58/0x9c _dev_info+0x84/0xa8 usb_new_device+0x100/0x474 hub_port_connect+0x280/0x92c hub_event+0x740/0xa84 process_one_work+0x240/0x70c worker_thread+0x60/0x400 kthread+0x110/0x13c ret_from_fork+0x10/0x18 -> #0 ((console_sem).lock){-...}: validate_chain.isra.34+0x6e4/0xa20 __lock_acquire+0x3b4/0x6e0 lock_acquire+0xf4/0x2a8 _raw_spin_lock_irqsave+0x58/0x70 down_trylock+0x20/0x4c __down_trylock_console_sem+0x3c/0x9c console_trylock+0x20/0xb0 vprintk_emit+0x254/0x390 vprintk_default+0x58/0x90 vprintk_func+0xbc/0x164 printk+0x80/0xa0 __dynamic_pr_debug+0x84/0xac gic_raise_softirq+0x184/0x18c smp_cross_call+0xac/0x218 smp_send_reschedule+0x3c/0x48 resched_curr+0x60/0x9c check_preempt_curr+0x70/0xdc wake_up_new_task+0x310/0x470 _do_fork+0x188/0x78c SyS_clone+0x44/0x50 __sys_trace_return+0x0/0x4 other info that might help us debug this: Chain exists of: (console_sem).lock --> &p->pi_lock --> &rq->lock Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&rq->lock); lock(&p->pi_lock); lock(&rq->lock); lock((console_sem).lock); *** DEADLOCK *** 2 locks held by dynamic_debug01/1873: #0: (&p->pi_lock){-.-.}, at: [<000000001366df53>] wake_up_new_task+0x40/0x470 #1: (&rq->lock){-.-.}, at: [<00000000842e1587>] __task_rq_lock+0x54/0xdc stack backtrace: CPU: 10 PID: 1873 Comm: dynamic_debug01 Tainted: G W 4.15.0+ #1 Hardware name: GIGABYTE R120-T34-00/MT30-GS2-00, BIOS T48 10/02/2017 Call trace: dump_backtrace+0x0/0x188 show_stack+0x24/0x2c dump_stack+0xa4/0xe0 print_circular_bug.isra.31+0x29c/0x2b8 check_prev_add.constprop.39+0x6c8/0x6dc validate_chain.isra.34+0x6e4/0xa20 __lock_acquire+0x3b4/0x6e0 lock_acquire+0xf4/0x2a8 _raw_spin_lock_irqsave+0x58/0x70 down_trylock+0x20/0x4c __down_trylock_console_sem+0x3c/0x9c console_trylock+0x20/0xb0 vprintk_emit+0x254/0x390 vprintk_default+0x58/0x90 vprintk_func+0xbc/0x164 printk+0x80/0xa0 __dynamic_pr_debug+0x84/0xac gic_raise_softirq+0x184/0x18c smp_cross_call+0xac/0x218 smp_send_reschedule+0x3c/0x48 resched_curr+0x60/0x9c check_preempt_curr+0x70/0xdc wake_up_new_task+0x310/0x470 _do_fork+0x188/0x78c SyS_clone+0x44/0x50 __sys_trace_return+0x0/0x4 GICv3: CPU0: ICC_SGI1R_EL1 12000 This could be fixed with printk_deferred() but that might lessen its usefulness for debugging. So change it to pr_devel to keep it out of production kernels. Developers working on gic-v3 can enable it as needed in their kernels. Signed-off-by: Mark Salter Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index a57c0fbbd34a..d71be9a1f9d2 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -673,7 +673,7 @@ static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq) MPIDR_TO_SGI_RS(cluster_id) | tlist << ICC_SGI1R_TARGET_LIST_SHIFT); - pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val); + pr_devel("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val); gic_write_sgi1r(val); } -- cgit v1.2.3 From 21ec30c0ef5234fb1039cc7c7737d885bf875a9e Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Wed, 31 Jan 2018 18:03:42 -0600 Subject: irqchip/gic-v3: Use wmb() instead of smb_wmb() in gic_raise_softirq() A DMB instruction can be used to ensure the relative order of only memory accesses before and after the barrier. Since writes to system registers are not memory operations, barrier DMB is not sufficient for observability of memory accesses that occur before ICC_SGI1R_EL1 writes. A DSB instruction ensures that no instructions that appear in program order after the DSB instruction, can execute until the DSB instruction has completed. Cc: stable@vger.kernel.org Acked-by: Will Deacon , Signed-off-by: Shanker Donthineni Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index d71be9a1f9d2..d99cc07903ec 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -688,7 +688,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) * Ensure that stores to Normal memory are visible to the * other CPUs before issuing the IPI. */ - smp_wmb(); + wmb(); for_each_cpu(cpu, mask) { u64 cluster_id = MPIDR_TO_SGI_CLUSTER_ID(cpu_logical_map(cpu)); -- cgit v1.2.3 From 95a2562590c2f64a0398183f978d5cf3db6d0284 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 1 Feb 2018 09:03:29 -0800 Subject: irqchip/gic-v3: Ignore disabled ITS nodes On some platforms there's an ITS available but it's not enabled because reading or writing the registers is denied by the firmware. In fact, reading or writing them will cause the system to reset. We could remove the node from DT in such a case, but it's better to skip nodes that are marked as "disabled" in DT so that we can describe the hardware that exists and use the status property to indicate how the firmware has configured things. Cc: Stuart Yoder Cc: Laurentiu Tudor Cc: Greg Kroah-Hartman Cc: Marc Zyngier Cc: Rajendra Nayak Signed-off-by: Stephen Boyd Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its-pci-msi.c | 2 ++ drivers/irqchip/irq-gic-v3-its-platform-msi.c | 2 ++ drivers/irqchip/irq-gic-v3-its.c | 2 ++ drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c | 2 ++ 4 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c index 14a8c0a7e095..25a98de5cfb2 100644 --- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c @@ -132,6 +132,8 @@ static int __init its_pci_of_msi_init(void) for (np = of_find_matching_node(NULL, its_device_id); np; np = of_find_matching_node(np, its_device_id)) { + if (!of_device_is_available(np)) + continue; if (!of_property_read_bool(np, "msi-controller")) continue; diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c index 833a90fe33ae..8881a053c173 100644 --- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c @@ -154,6 +154,8 @@ static void __init its_pmsi_of_init(void) for (np = of_find_matching_node(NULL, its_device_id); np; np = of_find_matching_node(np, its_device_id)) { + if (!of_device_is_available(np)) + continue; if (!of_property_read_bool(np, "msi-controller")) continue; diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 06f025fd5726..1d3056f53747 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -3314,6 +3314,8 @@ static int __init its_of_probe(struct device_node *node) for (np = of_find_matching_node(node, its_device_id); np; np = of_find_matching_node(np, its_device_id)) { + if (!of_device_is_available(np)) + continue; if (!of_property_read_bool(np, "msi-controller")) { pr_warn("%pOF: no msi-controller property, ITS ignored\n", np); diff --git a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c index 5064d5ddf581..fc2013aade51 100644 --- a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c +++ b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c @@ -73,6 +73,8 @@ static int __init its_fsl_mc_msi_init(void) for (np = of_find_matching_node(NULL, its_device_id); np; np = of_find_matching_node(np, its_device_id)) { + if (!of_device_is_available(np)) + continue; if (!of_property_read_bool(np, "msi-controller")) continue; -- cgit v1.2.3 From de337ee301422756dff43d6c60fbb0400c1235e9 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 6 Feb 2018 18:55:33 +0000 Subject: irqchip/gic-v2m: Add PCI Multi-MSI support We'd never implemented Multi-MSI support with GICv2m, because it is weird and clunky, and you'd think people would rather use MSI-X. Turns out there is still plenty of devices out there that rely on Multi-MSI. Oh well, let's teach that trick to the v2m widget, it is not a big deal anyway. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v2m.c | 46 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 993a8426a453..1ff38aff9f29 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -94,7 +94,7 @@ static struct irq_chip gicv2m_msi_irq_chip = { static struct msi_domain_info gicv2m_msi_domain_info = { .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_PCI_MSIX), + MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI), .chip = &gicv2m_msi_irq_chip, }; @@ -155,18 +155,12 @@ static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain, return 0; } -static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq) +static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq, + int nr_irqs) { - int pos; - - pos = hwirq - v2m->spi_start; - if (pos < 0 || pos >= v2m->nr_spis) { - pr_err("Failed to teardown msi. Invalid hwirq %d\n", hwirq); - return; - } - spin_lock(&v2m_lock); - __clear_bit(pos, v2m->bm); + bitmap_release_region(v2m->bm, hwirq - v2m->spi_start, + get_count_order(nr_irqs)); spin_unlock(&v2m_lock); } @@ -174,13 +168,13 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *args) { struct v2m_data *v2m = NULL, *tmp; - int hwirq, offset, err = 0; + int hwirq, offset, i, err = 0; spin_lock(&v2m_lock); list_for_each_entry(tmp, &v2m_nodes, entry) { - offset = find_first_zero_bit(tmp->bm, tmp->nr_spis); - if (offset < tmp->nr_spis) { - __set_bit(offset, tmp->bm); + offset = bitmap_find_free_region(tmp->bm, tmp->nr_spis, + get_count_order(nr_irqs)); + if (offset >= 0) { v2m = tmp; break; } @@ -192,16 +186,21 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, hwirq = v2m->spi_start + offset; - err = gicv2m_irq_gic_domain_alloc(domain, virq, hwirq); - if (err) { - gicv2m_unalloc_msi(v2m, hwirq); - return err; - } + for (i = 0; i < nr_irqs; i++) { + err = gicv2m_irq_gic_domain_alloc(domain, virq + i, hwirq + i); + if (err) + goto fail; - irq_domain_set_hwirq_and_chip(domain, virq, hwirq, - &gicv2m_irq_chip, v2m); + irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, + &gicv2m_irq_chip, v2m); + } return 0; + +fail: + irq_domain_free_irqs_parent(domain, virq, nr_irqs); + gicv2m_unalloc_msi(v2m, hwirq, get_count_order(nr_irqs)); + return err; } static void gicv2m_irq_domain_free(struct irq_domain *domain, @@ -210,8 +209,7 @@ static void gicv2m_irq_domain_free(struct irq_domain *domain, struct irq_data *d = irq_domain_get_irq_data(domain, virq); struct v2m_data *v2m = irq_data_get_irq_chip_data(d); - BUG_ON(nr_irqs != 1); - gicv2m_unalloc_msi(v2m, d->hwirq); + gicv2m_unalloc_msi(v2m, d->hwirq, nr_irqs); irq_domain_free_irqs_parent(domain, virq, nr_irqs); } -- cgit v1.2.3 From 6d36b7fec60e6f74a15ce4781d30b2aecce85dfc Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 22 Jan 2018 16:06:16 +0100 Subject: gpu: ipu-cpmem: add 8-bit grayscale support to ipu_cpmem_set_image Add the missing offset calculation for grayscale images. Since the IPU only supports capturing greyscale in raw passthrough mode, it is the same as 8-bit bayer formats. Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-cpmem.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c index bb9c087e6c0d..ef32377b91c0 100644 --- a/drivers/gpu/ipu-v3/ipu-cpmem.c +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c @@ -788,6 +788,7 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_GREY: offset = image->rect.left + image->rect.top * pix->bytesperline; break; case V4L2_PIX_FMT_SBGGR16: -- cgit v1.2.3 From 2d02424e89eca71b3fa5e832e6fbe467a413e3d5 Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Mon, 12 Feb 2018 11:18:12 +0900 Subject: irqchip/bcm: Remove hashed address printing Since commit ad67b74d2469 ("printk: hash addresses printed with %p") pointers are being hashed when printed. Displaying the virtual memory at bootup time is not helpful. so delete the prints. Acked-by: Florian Fainelli Signed-off-by: Jaedon Shin Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-bcm7038-l1.c | 3 --- drivers/irqchip/irq-bcm7120-l2.c | 3 --- drivers/irqchip/irq-brcmstb-l2.c | 3 --- 3 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index 55cfb986225b..faf734ff4cf3 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -339,9 +339,6 @@ int __init bcm7038_l1_of_init(struct device_node *dn, goto out_unmap; } - pr_info("registered BCM7038 L1 intc (mem: 0x%p, IRQs: %d)\n", - intc->cpus[0]->map_base, IRQS_PER_WORD * intc->n_words); - return 0; out_unmap: diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index 983640eba418..8968e5e93fcb 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -318,9 +318,6 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn, } } - pr_info("registered %s intc (mem: 0x%p, parent IRQ(s): %d)\n", - intc_name, data->map_base[0], data->num_parent_irqs); - return 0; out_free_domain: diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index 691d20eb0bec..0e65f609352e 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -262,9 +262,6 @@ static int __init brcmstb_l2_intc_of_init(struct device_node *np, ct->chip.irq_set_wake = irq_gc_set_wake; } - pr_info("registered L2 intc (mem: 0x%p, parent irq: %d)\n", - base, parent_irq); - return 0; out_free_domain: -- cgit v1.2.3 From 4b7f7ee2a5f523cf002328c6c02cb3e28a0fb30b Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 28 Dec 2017 13:28:30 +0200 Subject: iwlwifi: align timestamp cancel with timestamp start Canceling the periodic timestamp work should be done in the opposite flow to where it was started. This also prevents from sending the MARKER command during the mac_stop flow - causing a false queue hang (FW is no longer there to send a response). Fixes: 93b167c13a3a ("iwlwifi: runtime: sync FW and host clocks for logs") Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/init.c | 6 ------ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 -- 3 files changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/init.c b/drivers/net/wireless/intel/iwlwifi/fw/init.c index c39fe84bb4c4..45f21acbd842 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/init.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/init.c @@ -76,9 +76,3 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, iwl_fwrt_dbgfs_register(fwrt, dbgfs_dir); } IWL_EXPORT_SYMBOL(iwl_fw_runtime_init); - -void iwl_fw_runtime_exit(struct iwl_fw_runtime *fwrt) -{ - iwl_fw_cancel_timestamp(fwrt); -} -IWL_EXPORT_SYMBOL(iwl_fw_runtime_exit); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 2d28e0804218..89ff02d7c876 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -90,6 +90,7 @@ #include "fw/runtime.h" #include "fw/dbg.h" #include "fw/acpi.h" +#include "fw/debugfs.h" #define IWL_MVM_MAX_ADDRESSES 5 /* RSSI offset for WkP */ @@ -1783,6 +1784,7 @@ static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm) static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm) { + iwl_fw_cancel_timestamp(&mvm->fwrt); iwl_free_fw_paging(&mvm->fwrt); clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); iwl_fw_dump_conf_clear(&mvm->fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 5d525a0023dc..6bb347bf0d6e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -802,7 +802,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_mvm_leds_exit(mvm); iwl_mvm_thermal_exit(mvm); out_free: - iwl_fw_runtime_exit(&mvm->fwrt); iwl_fw_flush_dump(&mvm->fwrt); if (iwlmvm_mod_params.init_dbg) @@ -843,7 +842,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS) kfree(mvm->d3_resume_sram); #endif - iwl_fw_runtime_exit(&mvm->fwrt); iwl_trans_op_mode_leave(mvm->trans); iwl_phy_db_free(mvm->phy_db); -- cgit v1.2.3 From 6b7a5aea71b342ec0593d23b08383e1f33da4c9a Mon Sep 17 00:00:00 2001 From: Naftali Goldstein Date: Thu, 28 Dec 2017 15:53:04 +0200 Subject: iwlwifi: mvm: always init rs with 20mhz bandwidth rates In AP mode, when a new station associates, rs is initialized immediately upon association completion, before the phy context is updated with the association parameters, so the sta bandwidth might be wider than the phy context allows. To avoid this issue, always initialize rs with 20mhz bandwidth rate, and after authorization, when the phy context is already up-to-date, re-init rs with the correct bw. Signed-off-by: Naftali Goldstein Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 ++++ drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 28 ++++++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 8aed40a8bc38..08de822c3ef0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2682,6 +2682,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, /* enable beacon filtering */ WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); + + iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, + false); + ret = 0; } else if (old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 60abb0084ee5..47f4c7a1d80d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -2684,7 +2684,8 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, enum nl80211_band band, - struct rs_rate *rate) + struct rs_rate *rate, + bool init) { int i, nentries; unsigned long active_rate; @@ -2738,14 +2739,25 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, */ if (sta->vht_cap.vht_supported && best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { - switch (sta->bandwidth) { - case IEEE80211_STA_RX_BW_160: - case IEEE80211_STA_RX_BW_80: - case IEEE80211_STA_RX_BW_40: + /* + * In AP mode, when a new station associates, rs is initialized + * immediately upon association completion, before the phy + * context is updated with the association parameters, so the + * sta bandwidth might be wider than the phy context allows. + * To avoid this issue, always initialize rs with 20mhz + * bandwidth rate, and after authorization, when the phy context + * is already up-to-date, re-init rs with the correct bw. + */ + u32 bw = init ? RATE_MCS_CHAN_WIDTH_20 : rs_bw_from_sta_bw(sta); + + switch (bw) { + case RATE_MCS_CHAN_WIDTH_40: + case RATE_MCS_CHAN_WIDTH_80: + case RATE_MCS_CHAN_WIDTH_160: initial_rates = rs_optimal_rates_vht; nentries = ARRAY_SIZE(rs_optimal_rates_vht); break; - case IEEE80211_STA_RX_BW_20: + case RATE_MCS_CHAN_WIDTH_20: initial_rates = rs_optimal_rates_vht_20mhz; nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz); break; @@ -2756,7 +2768,7 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, active_rate = lq_sta->active_siso_rate; rate->type = LQ_VHT_SISO; - rate->bw = rs_bw_from_sta_bw(sta); + rate->bw = bw; } else if (sta->ht_cap.ht_supported && best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { initial_rates = rs_optimal_rates_ht; @@ -2839,7 +2851,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, tbl = &(lq_sta->lq_info[active_tbl]); rate = &tbl->rate; - rs_get_initial_rate(mvm, sta, lq_sta, band, rate); + rs_get_initial_rate(mvm, sta, lq_sta, band, rate, init); rs_init_optimal_rate(mvm, sta, lq_sta); WARN_ONCE(rate->ant != ANT_A && rate->ant != ANT_B, -- cgit v1.2.3 From 8dd601fa8317243be887458c49f6c29c2f3d719f Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 15 Feb 2018 20:00:15 +1100 Subject: dm: correctly handle chained bios in dec_pending() dec_pending() is given an error status (possibly 0) to be recorded against a bio. It can be called several times on the one 'struct dm_io', and it is careful to only assign a non-zero error to io->status. However when it then assigned io->status to bio->bi_status, it is not careful and could overwrite a genuine error status with 0. This can happen when chained bios are in use. If a bio is chained beneath the bio that this dm_io is handling, the child bio might complete and set bio->bi_status before the dm_io completes. This has been possible since chained bios were introduced in 3.14, and has become a lot easier to trigger with commit 18a25da84354 ("dm: ensure bio submission follows a depth-first tree walk") as that commit caused dm to start using chained bios itself. A particular failure mode is that if a bio spans an 'error' target and a working target, the 'error' fragment will complete instantly and set the ->bi_status, and the other fragment will normally complete a little later, and will clear ->bi_status. The fix is simply to only assign io_error to bio->bi_status when io_error is not zero. Reported-and-tested-by: Milan Broz Cc: stable@vger.kernel.org (v3.14+) Signed-off-by: NeilBrown Signed-off-by: Mike Snitzer --- drivers/md/dm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/dm.c b/drivers/md/dm.c index d6de00f367ef..68136806d365 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -903,7 +903,8 @@ static void dec_pending(struct dm_io *io, blk_status_t error) queue_io(md, bio); } else { /* done with normal IO or empty flush */ - bio->bi_status = io_error; + if (io_error) + bio->bi_status = io_error; bio_endio(bio); } } -- cgit v1.2.3 From 2188558621ed475cef55fa94ce535499452f0091 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 14 Feb 2018 14:38:43 +0200 Subject: RDMA/verbs: Check existence of function prior to accessing it Update all the flows to ensure that function pointer exists prior to accessing it. This is much safer than checking the uverbs_ex_mask variable, especially since we know that test isn't working properly and will be removed in -next. This prevents a user triggereable oops. Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/core_priv.h | 3 +++ drivers/infiniband/core/uverbs_cmd.c | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index c4560d84dfae..c91f9a80b831 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -309,6 +309,9 @@ static inline struct ib_qp *_ib_create_qp(struct ib_device *dev, { struct ib_qp *qp; + if (!dev->create_qp) + return ERR_PTR(-EOPNOTSUPP); + qp = dev->create_qp(pd, attr, udata); if (IS_ERR(qp)) return qp; diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index cd9fbd7c82b0..dbcfb313cee9 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -978,6 +978,9 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file, struct ib_uverbs_ex_create_cq_resp resp; struct ib_cq_init_attr attr = {}; + if (!ib_dev->create_cq) + return ERR_PTR(-EOPNOTSUPP); + if (cmd->comp_vector >= file->device->num_comp_vectors) return ERR_PTR(-EINVAL); @@ -2947,6 +2950,11 @@ int ib_uverbs_ex_create_wq(struct ib_uverbs_file *file, wq_init_attr.create_flags = cmd.create_flags; obj->uevent.events_reported = 0; INIT_LIST_HEAD(&obj->uevent.event_list); + + if (!pd->device->create_wq) { + err = -EOPNOTSUPP; + goto err_put_cq; + } wq = pd->device->create_wq(pd, &wq_init_attr, uhw); if (IS_ERR(wq)) { err = PTR_ERR(wq); @@ -3090,7 +3098,12 @@ int ib_uverbs_ex_modify_wq(struct ib_uverbs_file *file, wq_attr.flags = cmd.flags; wq_attr.flags_mask = cmd.flags_mask; } + if (!wq->device->modify_wq) { + ret = -EOPNOTSUPP; + goto out; + } ret = wq->device->modify_wq(wq, &wq_attr, cmd.attr_mask, uhw); +out: uobj_put_obj_read(wq); return ret; } @@ -3187,6 +3200,11 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file, init_attr.log_ind_tbl_size = cmd.log_ind_tbl_size; init_attr.ind_tbl = wqs; + + if (!ib_dev->create_rwq_ind_table) { + err = -EOPNOTSUPP; + goto err_uobj; + } rwq_ind_tbl = ib_dev->create_rwq_ind_table(ib_dev, &init_attr, uhw); if (IS_ERR(rwq_ind_tbl)) { @@ -3776,6 +3794,9 @@ int ib_uverbs_ex_query_device(struct ib_uverbs_file *file, struct ib_device_attr attr = {0}; int err; + if (!ib_dev->query_device) + return -EOPNOTSUPP; + if (ucore->inlen < sizeof(cmd)) return -EINVAL; -- cgit v1.2.3 From 02b7b2844c2ffd3b614ec2b9293e8c7f041d60da Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Feb 2018 16:36:04 +0100 Subject: staging: fsl-mc: fix build testing on x86 Selecting GENERIC_MSI_IRQ_DOMAIN on x86 causes a compile-time error in some configurations: drivers/base/platform-msi.c:37:19: error: field 'arg' has incomplete type On the other architectures, we are fine, but here we should have an additional dependency on X86_LOCAL_APIC so we can get the PCI_MSI_IRQ_DOMAIN symbol. Cc: stable@vger.kernel.org Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fsl-mc/bus/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/fsl-mc/bus/Kconfig b/drivers/staging/fsl-mc/bus/Kconfig index 1f9100049176..b35ef7ee6901 100644 --- a/drivers/staging/fsl-mc/bus/Kconfig +++ b/drivers/staging/fsl-mc/bus/Kconfig @@ -7,7 +7,7 @@ config FSL_MC_BUS bool "QorIQ DPAA2 fsl-mc bus driver" - depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86 || PPC))) + depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86_LOCAL_APIC || PPC))) select GENERIC_MSI_IRQ_DOMAIN help Driver to enable the bus infrastructure for the QorIQ DPAA2 -- cgit v1.2.3 From ce8a3a9e76d0193e2e8d74a06d275b3c324ca652 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 4 Feb 2018 02:06:27 +0000 Subject: staging: android: ashmem: Fix a race condition in pin ioctls ashmem_pin_unpin() reads asma->file and asma->size before taking the ashmem_mutex, so it can race with other operations that modify them. Build-tested only. Cc: stable@vger.kernel.org Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ashmem.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index bbdc53b686dd..6dbba5aff191 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -702,30 +702,32 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd, size_t pgstart, pgend; int ret = -EINVAL; + mutex_lock(&ashmem_mutex); + if (unlikely(!asma->file)) - return -EINVAL; + goto out_unlock; - if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) - return -EFAULT; + if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) { + ret = -EFAULT; + goto out_unlock; + } /* per custom, you can pass zero for len to mean "everything onward" */ if (!pin.len) pin.len = PAGE_ALIGN(asma->size) - pin.offset; if (unlikely((pin.offset | pin.len) & ~PAGE_MASK)) - return -EINVAL; + goto out_unlock; if (unlikely(((__u32)-1) - pin.offset < pin.len)) - return -EINVAL; + goto out_unlock; if (unlikely(PAGE_ALIGN(asma->size) < pin.offset + pin.len)) - return -EINVAL; + goto out_unlock; pgstart = pin.offset / PAGE_SIZE; pgend = pgstart + (pin.len / PAGE_SIZE) - 1; - mutex_lock(&ashmem_mutex); - switch (cmd) { case ASHMEM_PIN: ret = ashmem_pin(asma, pgstart, pgend); @@ -738,6 +740,7 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd, break; } +out_unlock: mutex_unlock(&ashmem_mutex); return ret; -- cgit v1.2.3 From 6d79bd5bb6c79a9dba4842040c9adf39e7806330 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Fri, 26 Jan 2018 09:48:18 -0800 Subject: staging: android: ion: Zero CMA allocated memory Since commit 204f672255c2 ("staging: android: ion: Use CMA APIs directly") the CMA API is now used directly and therefore the allocated memory is no longer automatically zeroed. Explicitly zero CMA allocated memory to ensure that no data is exposed to userspace. Fixes: 204f672255c2 ("staging: android: ion: Use CMA APIs directly") Signed-off-by: Liam Mark Acked-by: Laura Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion_cma_heap.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index 94e06925c712..49718c96bf9e 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "ion.h" @@ -42,6 +43,22 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, if (!pages) return -ENOMEM; + if (PageHighMem(pages)) { + unsigned long nr_clear_pages = nr_pages; + struct page *page = pages; + + while (nr_clear_pages > 0) { + void *vaddr = kmap_atomic(page); + + memset(vaddr, 0, PAGE_SIZE); + kunmap_atomic(vaddr); + page++; + nr_clear_pages--; + } + } else { + memset(page_address(pages), 0, size); + } + table = kmalloc(sizeof(*table), GFP_KERNEL); if (!table) goto err; -- cgit v1.2.3 From 50c330973c0c9f1e300b07bbab78d306dcc6e612 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Fri, 16 Feb 2018 16:57:56 +0000 Subject: irqchip/gic-v3-its: Fix misplaced __iomem annotations Save 26 lines worth of Sparse complaints by fixing up this minor mishap. The pointee lies in the __iomem space; the pointer does not. Signed-off-by: Robin Murphy Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 1d3056f53747..94b7d74d519f 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -2495,7 +2495,7 @@ static int its_vpe_set_affinity(struct irq_data *d, static void its_vpe_schedule(struct its_vpe *vpe) { - void * __iomem vlpi_base = gic_data_rdist_vlpi_base(); + void __iomem *vlpi_base = gic_data_rdist_vlpi_base(); u64 val; /* Schedule the VPE */ @@ -2527,7 +2527,7 @@ static void its_vpe_schedule(struct its_vpe *vpe) static void its_vpe_deschedule(struct its_vpe *vpe) { - void * __iomem vlpi_base = gic_data_rdist_vlpi_base(); + void __iomem *vlpi_base = gic_data_rdist_vlpi_base(); u32 count = 1000000; /* 1s! */ bool clean; u64 val; -- cgit v1.2.3 From 2f08ee363fe097bc6dc01aac53e1798b16c00986 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 14 Feb 2018 18:43:36 -0800 Subject: RDMA/restrack: don't use uaccess_kernel() uaccess_kernel() isn't sufficient to determine if an rdma resource is user-mode or not. For example, resources allocated in the add_one() function of an ib_client get falsely labeled as user mode, when they are kernel mode allocations. EG: mad qps. The result is that these qps are skipped over during a nldev query because of an erroneous namespace mismatch. So now we determine if the resource is user-mode by looking at the object struct's uobject or similar pointer to know if it was allocated for user mode applications. Fixes: 02d8883f520e ("RDMA/restrack: Add general infrastructure to track RDMA resources") Signed-off-by: Steve Wise Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/core_priv.h | 4 +++- drivers/infiniband/core/restrack.c | 18 ++++++++++++++++-- drivers/infiniband/core/uverbs_cmd.c | 4 ++-- drivers/infiniband/core/verbs.c | 3 +-- 4 files changed, 22 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index c91f9a80b831..25bb178f6074 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -305,7 +305,8 @@ void nldev_exit(void); static inline struct ib_qp *_ib_create_qp(struct ib_device *dev, struct ib_pd *pd, struct ib_qp_init_attr *attr, - struct ib_udata *udata) + struct ib_udata *udata, + struct ib_uobject *uobj) { struct ib_qp *qp; @@ -318,6 +319,7 @@ static inline struct ib_qp *_ib_create_qp(struct ib_device *dev, qp->device = dev; qp->pd = pd; + qp->uobject = uobj; /* * We don't track XRC QPs for now, because they don't have PD * and more importantly they are created internaly by driver, diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c index d8dc709a3715..3dbc4e4cca41 100644 --- a/drivers/infiniband/core/restrack.c +++ b/drivers/infiniband/core/restrack.c @@ -7,7 +7,6 @@ #include #include #include -#include #include void rdma_restrack_init(struct rdma_restrack_root *res) @@ -88,6 +87,21 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res) return dev; } +static bool res_is_user(struct rdma_restrack_entry *res) +{ + switch (res->type) { + case RDMA_RESTRACK_PD: + return container_of(res, struct ib_pd, res)->uobject; + case RDMA_RESTRACK_CQ: + return container_of(res, struct ib_cq, res)->uobject; + case RDMA_RESTRACK_QP: + return container_of(res, struct ib_qp, res)->uobject; + default: + WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type); + return false; + } +} + void rdma_restrack_add(struct rdma_restrack_entry *res) { struct ib_device *dev = res_to_dev(res); @@ -95,7 +109,7 @@ void rdma_restrack_add(struct rdma_restrack_entry *res) if (!dev) return; - if (!uaccess_kernel()) { + if (res_is_user(res)) { get_task_struct(current); res->task = current; res->kern_name = NULL; diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index dbcfb313cee9..25a0e0e083b3 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1520,7 +1520,8 @@ static int create_qp(struct ib_uverbs_file *file, if (cmd->qp_type == IB_QPT_XRC_TGT) qp = ib_create_qp(pd, &attr); else - qp = _ib_create_qp(device, pd, &attr, uhw); + qp = _ib_create_qp(device, pd, &attr, uhw, + &obj->uevent.uobject); if (IS_ERR(qp)) { ret = PTR_ERR(qp); @@ -1553,7 +1554,6 @@ static int create_qp(struct ib_uverbs_file *file, if (ind_tbl) atomic_inc(&ind_tbl->usecnt); } - qp->uobject = &obj->uevent.uobject; obj->uevent.uobject.object = qp; diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 16ebc6372c31..93025d2009b8 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -887,7 +887,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, if (qp_init_attr->cap.max_rdma_ctxs) rdma_rw_init_qp(device, qp_init_attr); - qp = _ib_create_qp(device, pd, qp_init_attr, NULL); + qp = _ib_create_qp(device, pd, qp_init_attr, NULL, NULL); if (IS_ERR(qp)) return qp; @@ -898,7 +898,6 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, } qp->real_qp = qp; - qp->uobject = NULL; qp->qp_type = qp_init_attr->qp_type; qp->rwq_ind_tbl = qp_init_attr->rwq_ind_tbl; -- cgit v1.2.3 From c4e43e14cd4617d57babc7a9f251bf3e9ad360a0 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Thu, 15 Feb 2018 18:16:57 +0530 Subject: cxgb4: free up resources of pf 0-3 free pf 0-3 resources, commit baf5086840ab ("cxgb4: restructure VF mgmt code") erroneously removed the code which frees the pf 0-3 resources, causing the probe of pf 0-3 to fail in case of driver reload. Fixes: baf5086840ab ("cxgb4: restructure VF mgmt code") Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 56bc626ef006..7b452e85de2a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4982,9 +4982,10 @@ static int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs) pcie_fw = readl(adap->regs + PCIE_FW_A); /* Check if cxgb4 is the MASTER and fw is initialized */ - if (!(pcie_fw & PCIE_FW_INIT_F) || + if (num_vfs && + (!(pcie_fw & PCIE_FW_INIT_F) || !(pcie_fw & PCIE_FW_MASTER_VLD_F) || - PCIE_FW_MASTER_G(pcie_fw) != CXGB4_UNIFIED_PF) { + PCIE_FW_MASTER_G(pcie_fw) != CXGB4_UNIFIED_PF)) { dev_warn(&pdev->dev, "cxgb4 driver needs to be MASTER to support SRIOV\n"); return -EOPNOTSUPP; @@ -5599,24 +5600,24 @@ static void remove_one(struct pci_dev *pdev) #if IS_ENABLED(CONFIG_IPV6) t4_cleanup_clip_tbl(adapter); #endif - iounmap(adapter->regs); if (!is_t4(adapter->params.chip)) iounmap(adapter->bar2); - pci_disable_pcie_error_reporting(pdev); - if ((adapter->flags & DEV_ENABLED)) { - pci_disable_device(pdev); - adapter->flags &= ~DEV_ENABLED; - } - pci_release_regions(pdev); - kfree(adapter->mbox_log); - synchronize_rcu(); - kfree(adapter); } #ifdef CONFIG_PCI_IOV else { cxgb4_iov_configure(adapter->pdev, 0); } #endif + iounmap(adapter->regs); + pci_disable_pcie_error_reporting(pdev); + if ((adapter->flags & DEV_ENABLED)) { + pci_disable_device(pdev); + adapter->flags &= ~DEV_ENABLED; + } + pci_release_regions(pdev); + kfree(adapter->mbox_log); + synchronize_rcu(); + kfree(adapter); } /* "Shutdown" quiesces the device, stopping Ingress Packet and Interrupt -- cgit v1.2.3 From e6f02a4d57cc438099bc8abfba43ba1400d77b38 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Thu, 15 Feb 2018 18:20:01 +0530 Subject: cxgb4: fix trailing zero in CIM LA dump Set correct size of the CIM LA dump for T6. Fixes: 27887bc7cb7f ("cxgb4: collect hardware LA dumps") Signed-off-by: Rahul Lakkireddy Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c index 557fd8bfd54e..00a1d2d13169 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c @@ -472,7 +472,7 @@ int cudbg_collect_cim_la(struct cudbg_init *pdbg_init, if (is_t6(padap->params.chip)) { size = padap->params.cim_la_size / 10 + 1; - size *= 11 * sizeof(u32); + size *= 10 * sizeof(u32); } else { size = padap->params.cim_la_size / 8; size *= 8 * sizeof(u32); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c index 30485f9a598f..143686c60234 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c @@ -102,7 +102,7 @@ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity) case CUDBG_CIM_LA: if (is_t6(adap->params.chip)) { len = adap->params.cim_la_size / 10 + 1; - len *= 11 * sizeof(u32); + len *= 10 * sizeof(u32); } else { len = adap->params.cim_la_size / 8; len *= 8 * sizeof(u32); -- cgit v1.2.3 From 7dcf688d4c78a18ba9538b2bf1b11dc7a43fe9be Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Thu, 15 Feb 2018 20:03:18 +0530 Subject: PCI/cxgb4: Extend T3 PCI quirk to T4+ devices We've run into a problem where our device is attached to a Virtual Machine and the use of the new pci_set_vpd_size() API doesn't help. The VM kernel has been informed that the accesses are okay, but all of the actual VPD Capability Accesses are trapped down into the KVM Hypervisor where it goes ahead and imposes the silent denials. The right idea is to follow the kernel.org commit 1c7de2b4ff88 ("PCI: Enable access to non-standard VPD for Chelsio devices (cxgb3)") which Alexey Kardashevskiy authored to establish a PCI Quirk for our T3-based adapters. This commit extends that PCI Quirk to cover Chelsio T4 devices and later. The advantage of this approach is that the VPD Size gets set early in the Base OS/Hypervisor Boot and doesn't require that the cxgb4 driver even be available in the Base OS/Hypervisor. Thus PF4 can be exported to a Virtual Machine and everything should work. Fixes: 67e658794ca1 ("cxgb4: Set VPD size so we can read both VPD structures") Cc: # v4.9+ Signed-off-by: Casey Leedom Signed-off-by: Arjun Vynipadath Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 10 -------- drivers/pci/quirks.c | 39 ++++++++++++++++++------------ 2 files changed, 23 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 047609ef0515..920bccd6bc40 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -2637,7 +2637,6 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) } #define EEPROM_STAT_ADDR 0x7bfc -#define VPD_SIZE 0x800 #define VPD_BASE 0x400 #define VPD_BASE_OLD 0 #define VPD_LEN 1024 @@ -2704,15 +2703,6 @@ int t4_get_raw_vpd_params(struct adapter *adapter, struct vpd_params *p) if (!vpd) return -ENOMEM; - /* We have two VPD data structures stored in the adapter VPD area. - * By default, Linux calculates the size of the VPD area by traversing - * the first VPD area at offset 0x0, so we need to tell the OS what - * our real VPD size is. - */ - ret = pci_set_vpd_size(adapter->pdev, VPD_SIZE); - if (ret < 0) - goto out; - /* Card information normally starts at VPD_BASE but early cards had * it at 0. */ diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index fc734014206f..8b14bd326d4a 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3419,22 +3419,29 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PORT_RIDGE, static void quirk_chelsio_extend_vpd(struct pci_dev *dev) { - pci_set_vpd_size(dev, 8192); -} - -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x20, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x21, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x22, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x23, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x24, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x25, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x26, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x30, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x31, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x32, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x35, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x36, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x37, quirk_chelsio_extend_vpd); + int chip = (dev->device & 0xf000) >> 12; + int func = (dev->device & 0x0f00) >> 8; + int prod = (dev->device & 0x00ff) >> 0; + + /* + * If this is a T3-based adapter, there's a 1KB VPD area at offset + * 0xc00 which contains the preferred VPD values. If this is a T4 or + * later based adapter, the special VPD is at offset 0x400 for the + * Physical Functions (the SR-IOV Virtual Functions have no VPD + * Capabilities). The PCI VPD Access core routines will normally + * compute the size of the VPD by parsing the VPD Data Structure at + * offset 0x000. This will result in silent failures when attempting + * to accesses these other VPD areas which are beyond those computed + * limits. + */ + if (chip == 0x0 && prod >= 0x20) + pci_set_vpd_size(dev, 8192); + else if (chip >= 0x4 && func < 0x8) + pci_set_vpd_size(dev, 2048); +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID, + quirk_chelsio_extend_vpd); #ifdef CONFIG_ACPI /* -- cgit v1.2.3 From 43a08e0f58b3f236165029710a4e3b303815253b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 15 Feb 2018 14:47:15 -0800 Subject: tun: fix tun_napi_alloc_frags() frag allocator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While fuzzing arm64 v4.16-rc1 with Syzkaller, I've been hitting a misaligned atomic in __skb_clone:         atomic_inc(&(skb_shinfo(skb)->dataref)); where dataref doesn't have the required natural alignment, and the atomic operation faults. e.g. i often see it aligned to a single byte boundary rather than a four byte boundary. AFAICT, the skb_shared_info is misaligned at the instant it's allocated in __napi_alloc_skb() __napi_alloc_skb() Problem is caused by tun_napi_alloc_frags() using napi_alloc_frag() with user provided seg sizes, leading to other users of this API getting unaligned page fragments. Since we would like to not necessarily add paddings or alignments to the frags that tun_napi_alloc_frags() attaches to the skb, switch to another page frag allocator. As a bonus skb_page_frag_refill() can use GFP_KERNEL allocations, meaning that we can not deplete memory reserves as easily. Fixes: 90e33d459407 ("tun: enable napi_gro_frags() for TUN/TAP driver") Signed-off-by: Eric Dumazet Reported-by: Mark Rutland Tested-by: Mark Rutland Signed-off-by: David S. Miller --- drivers/net/tun.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 81e6cc951e7f..b52258c327d2 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1489,27 +1489,23 @@ static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile, skb->truesize += skb->data_len; for (i = 1; i < it->nr_segs; i++) { + struct page_frag *pfrag = ¤t->task_frag; size_t fragsz = it->iov[i].iov_len; - unsigned long offset; - struct page *page; - void *data; if (fragsz == 0 || fragsz > PAGE_SIZE) { err = -EINVAL; goto free; } - local_bh_disable(); - data = napi_alloc_frag(fragsz); - local_bh_enable(); - if (!data) { + if (!skb_page_frag_refill(fragsz, pfrag, GFP_KERNEL)) { err = -ENOMEM; goto free; } - page = virt_to_head_page(data); - offset = data - page_address(page); - skb_fill_page_desc(skb, i - 1, page, offset, fragsz); + skb_fill_page_desc(skb, i - 1, pfrag->page, + pfrag->offset, fragsz); + page_ref_inc(pfrag->page); + pfrag->offset += fragsz; } return skb; -- cgit v1.2.3 From 25c058ccaf2ebbc3e250ec1e199e161f91fe27d4 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 14 Feb 2018 06:41:25 +0100 Subject: drm: Allow determining if current task is output poll worker Introduce a helper to determine if the current task is an output poll worker. This allows us to fix a long-standing deadlock in several DRM drivers wherein the ->runtime_suspend callback waits for the output poll worker to finish and the worker in turn calls a ->detect callback which waits for runtime suspend to finish. The ->detect callback is invoked from multiple call sites and waiting for runtime suspend to finish is the correct thing to do except if it's executing in the context of the worker. v2: Expand kerneldoc to specifically mention deadlock between output poll worker and autosuspend worker as use case. (Lyude) Cc: Dave Airlie Cc: Ben Skeggs Cc: Alex Deucher Reviewed-by: Lyude Paul Signed-off-by: Lukas Wunner Link: https://patchwork.freedesktop.org/patch/msgid/3549ce32e7f1467102e70d3e9cbf70c46bfe108e.1518593424.git.lukas@wunner.de --- drivers/gpu/drm/drm_probe_helper.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 6dc2dde5b672..7a6b2dc08913 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -654,6 +654,26 @@ out: schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); } +/** + * drm_kms_helper_is_poll_worker - is %current task an output poll worker? + * + * Determine if %current task is an output poll worker. This can be used + * to select distinct code paths for output polling versus other contexts. + * + * One use case is to avoid a deadlock between the output poll worker and + * the autosuspend worker wherein the latter waits for polling to finish + * upon calling drm_kms_helper_poll_disable(), while the former waits for + * runtime suspend to finish upon calling pm_runtime_get_sync() in a + * connector ->detect hook. + */ +bool drm_kms_helper_is_poll_worker(void) +{ + struct work_struct *work = current_work(); + + return work && work->func == output_poll_execute; +} +EXPORT_SYMBOL(drm_kms_helper_is_poll_worker); + /** * drm_kms_helper_poll_disable - disable output polling * @dev: drm_device -- cgit v1.2.3 From d61a5c1063515e855bedb1b81e20e50b0ac3541e Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 11 Feb 2018 10:38:28 +0100 Subject: drm/nouveau: Fix deadlock on runtime suspend nouveau's ->runtime_suspend hook calls drm_kms_helper_poll_disable(), which waits for the output poll worker to finish if it's running. The output poll worker meanwhile calls pm_runtime_get_sync() in nouveau_connector_detect() which waits for the ongoing suspend to finish, causing a deadlock. Fix by not acquiring a runtime PM ref if nouveau_connector_detect() is called in the output poll worker's context. This is safe because the poll worker is only enabled while runtime active and we know that ->runtime_suspend waits for it to finish. Other contexts calling nouveau_connector_detect() do require a runtime PM ref, these comprise: status_store() drm sysfs interface ->fill_modes drm callback drm_fb_helper_probe_connector_modes() drm_mode_getconnector() nouveau_connector_hotplug() nouveau_display_hpd_work() nv17_tv_set_property() Stack trace for posterity: INFO: task kworker/0:1:58 blocked for more than 120 seconds. Workqueue: events output_poll_execute [drm_kms_helper] Call Trace: schedule+0x28/0x80 rpm_resume+0x107/0x6e0 __pm_runtime_resume+0x47/0x70 nouveau_connector_detect+0x7e/0x4a0 [nouveau] nouveau_connector_detect_lvds+0x132/0x180 [nouveau] drm_helper_probe_detect_ctx+0x85/0xd0 [drm_kms_helper] output_poll_execute+0x11e/0x1c0 [drm_kms_helper] process_one_work+0x184/0x380 worker_thread+0x2e/0x390 INFO: task kworker/0:2:252 blocked for more than 120 seconds. Workqueue: pm pm_runtime_work Call Trace: schedule+0x28/0x80 schedule_timeout+0x1e3/0x370 wait_for_completion+0x123/0x190 flush_work+0x142/0x1c0 nouveau_pmops_runtime_suspend+0x7e/0xd0 [nouveau] pci_pm_runtime_suspend+0x5c/0x180 vga_switcheroo_runtime_suspend+0x1e/0xa0 __rpm_callback+0xc1/0x200 rpm_callback+0x1f/0x70 rpm_suspend+0x13c/0x640 pm_runtime_work+0x6e/0x90 process_one_work+0x184/0x380 worker_thread+0x2e/0x390 Bugzilla: https://bugs.archlinux.org/task/53497 Bugzilla: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=870523 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=70388#c33 Fixes: 5addcf0a5f0f ("nouveau: add runtime PM support (v0.9)") Cc: stable@vger.kernel.org # v3.12+: 27d4ee03078a: workqueue: Allow retrieval of current task's work struct Cc: stable@vger.kernel.org # v3.12+: 25c058ccaf2e: drm: Allow determining if current task is output poll worker Cc: Ben Skeggs Cc: Dave Airlie Reviewed-by: Lyude Paul Signed-off-by: Lukas Wunner Link: https://patchwork.freedesktop.org/patch/msgid/b7d2cbb609a80f59ccabfdf479b9d5907c603ea1.1518338789.git.lukas@wunner.de --- drivers/gpu/drm/nouveau/nouveau_connector.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 69d6e61a01ec..6ed9cb053dfa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -570,9 +570,15 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) nv_connector->edid = NULL; } - ret = pm_runtime_get_sync(connector->dev->dev); - if (ret < 0 && ret != -EACCES) - return conn_status; + /* Outputs are only polled while runtime active, so acquiring a + * runtime PM ref here is unnecessary (and would deadlock upon + * runtime suspend because it waits for polling to finish). + */ + if (!drm_kms_helper_is_poll_worker()) { + ret = pm_runtime_get_sync(connector->dev->dev); + if (ret < 0 && ret != -EACCES) + return conn_status; + } nv_encoder = nouveau_connector_ddc_detect(connector); if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) { @@ -647,8 +653,10 @@ detect_analog: out: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return conn_status; } -- cgit v1.2.3 From 15734feff2bdac24aa3266c437cffa42851990e3 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 11 Feb 2018 10:38:28 +0100 Subject: drm/radeon: Fix deadlock on runtime suspend radeon's ->runtime_suspend hook calls drm_kms_helper_poll_disable(), which waits for the output poll worker to finish if it's running. The output poll worker meanwhile calls pm_runtime_get_sync() in radeon's ->detect hooks, which waits for the ongoing suspend to finish, causing a deadlock. Fix by not acquiring a runtime PM ref if the ->detect hooks are called in the output poll worker's context. This is safe because the poll worker is only enabled while runtime active and we know that ->runtime_suspend waits for it to finish. Stack trace for posterity: INFO: task kworker/0:3:31847 blocked for more than 120 seconds Workqueue: events output_poll_execute [drm_kms_helper] Call Trace: schedule+0x3c/0x90 rpm_resume+0x1e2/0x690 __pm_runtime_resume+0x3f/0x60 radeon_lvds_detect+0x39/0xf0 [radeon] output_poll_execute+0xda/0x1e0 [drm_kms_helper] process_one_work+0x14b/0x440 worker_thread+0x48/0x4a0 INFO: task kworker/2:0:10493 blocked for more than 120 seconds. Workqueue: pm pm_runtime_work Call Trace: schedule+0x3c/0x90 schedule_timeout+0x1b3/0x240 wait_for_common+0xc2/0x180 wait_for_completion+0x1d/0x20 flush_work+0xfc/0x1a0 __cancel_work_timer+0xa5/0x1d0 cancel_delayed_work_sync+0x13/0x20 drm_kms_helper_poll_disable+0x1f/0x30 [drm_kms_helper] radeon_pmops_runtime_suspend+0x3d/0xa0 [radeon] pci_pm_runtime_suspend+0x61/0x1a0 vga_switcheroo_runtime_suspend+0x21/0x70 __rpm_callback+0x32/0x70 rpm_callback+0x24/0x80 rpm_suspend+0x12b/0x640 pm_runtime_work+0x6f/0xb0 process_one_work+0x14b/0x440 worker_thread+0x48/0x4a0 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94147 Fixes: 10ebc0bc0934 ("drm/radeon: add runtime PM support (v2)") Cc: stable@vger.kernel.org # v3.13+: 27d4ee03078a: workqueue: Allow retrieval of current task's work struct Cc: stable@vger.kernel.org # v3.13+: 25c058ccaf2e: drm: Allow determining if current task is output poll worker Cc: Ismo Toijala Cc: Alex Deucher Cc: Dave Airlie Reviewed-by: Lyude Paul Signed-off-by: Lukas Wunner Link: https://patchwork.freedesktop.org/patch/msgid/64ea02c44f91dda19bc563902b97bbc699040392.1518338789.git.lukas@wunner.de --- drivers/gpu/drm/radeon/radeon_connectors.c | 74 ++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 59dcefb2df3b..30e129684c7c 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -900,9 +900,11 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; int r; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } if (encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -925,8 +927,12 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) /* check acpi lid status ??? */ radeon_connector_update_scratch_regs(connector, ret); - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } + return ret; } @@ -1040,9 +1046,11 @@ radeon_vga_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; int r; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } encoder = radeon_best_single_encoder(connector); if (!encoder) @@ -1109,8 +1117,10 @@ radeon_vga_detect(struct drm_connector *connector, bool force) radeon_connector_update_scratch_regs(connector, ret); out: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return ret; } @@ -1174,9 +1184,11 @@ radeon_tv_detect(struct drm_connector *connector, bool force) if (!radeon_connector->dac_load_detect) return ret; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } encoder = radeon_best_single_encoder(connector); if (!encoder) @@ -1188,8 +1200,12 @@ radeon_tv_detect(struct drm_connector *connector, bool force) if (ret == connector_status_connected) ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false); radeon_connector_update_scratch_regs(connector, ret); - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } + return ret; } @@ -1252,9 +1268,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; bool dret = false, broken_edid = false; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } if (radeon_connector->detected_hpd_without_ddc) { force = true; @@ -1437,8 +1455,10 @@ out: } exit: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return ret; } @@ -1689,9 +1709,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (radeon_dig_connector->is_mst) return connector_status_disconnected; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } if (!force && radeon_check_hpd_status_unchanged(connector)) { ret = connector->status; @@ -1778,8 +1800,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force) } out: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return ret; } -- cgit v1.2.3 From aa0aad57909eb321746325951d66af88a83bc956 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 11 Feb 2018 10:38:28 +0100 Subject: drm/amdgpu: Fix deadlock on runtime suspend amdgpu's ->runtime_suspend hook calls drm_kms_helper_poll_disable(), which waits for the output poll worker to finish if it's running. The output poll worker meanwhile calls pm_runtime_get_sync() in amdgpu's ->detect hooks, which waits for the ongoing suspend to finish, causing a deadlock. Fix by not acquiring a runtime PM ref if the ->detect hooks are called in the output poll worker's context. This is safe because the poll worker is only enabled while runtime active and we know that ->runtime_suspend waits for it to finish. Fixes: d38ceaf99ed0 ("drm/amdgpu: add core driver (v4)") Cc: stable@vger.kernel.org # v4.2+: 27d4ee03078a: workqueue: Allow retrieval of current task's work struct Cc: stable@vger.kernel.org # v4.2+: 25c058ccaf2e: drm: Allow determining if current task is output poll worker Cc: Alex Deucher Tested-by: Mike Lothian Reviewed-by: Lyude Paul Signed-off-by: Lukas Wunner Link: https://patchwork.freedesktop.org/patch/msgid/4c9bf72aacae1eef062bd134cd112e0770a7f121.1518338789.git.lukas@wunner.de --- drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 58 +++++++++++++++++--------- 1 file changed, 38 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index df9cbc78e168..21e7ae159dff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -737,9 +737,11 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; int r; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } if (encoder) { struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); @@ -758,8 +760,12 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force) /* check acpi lid status ??? */ amdgpu_connector_update_scratch_regs(connector, ret); - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } + return ret; } @@ -869,9 +875,11 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; int r; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } encoder = amdgpu_connector_best_single_encoder(connector); if (!encoder) @@ -925,8 +933,10 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) amdgpu_connector_update_scratch_regs(connector, ret); out: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return ret; } @@ -989,9 +999,11 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; bool dret = false, broken_edid = false; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { ret = connector->status; @@ -1116,8 +1128,10 @@ out: amdgpu_connector_update_scratch_regs(connector, ret); exit: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return ret; } @@ -1360,9 +1374,11 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); int r; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { ret = connector->status; @@ -1430,8 +1446,10 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) amdgpu_connector_update_scratch_regs(connector, ret); out: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return ret; } -- cgit v1.2.3 From 29fee6eed2811ff1089b30fc579a2d19d78016ab Mon Sep 17 00:00:00 2001 From: Joao Martins Date: Fri, 2 Feb 2018 17:42:33 +0000 Subject: xenbus: track caller request id Commit fd8aa9095a95 ("xen: optimize xenbus driver for multiple concurrent xenstore accesses") optimized xenbus concurrent accesses but in doing so broke UABI of /dev/xen/xenbus. Through /dev/xen/xenbus applications are in charge of xenbus message exchange with the correct header and body. Now, after the mentioned commit the replies received by application will no longer have the header req_id echoed back as it was on request (see specification below for reference), because that particular field is being overwritten by kernel. struct xsd_sockmsg { uint32_t type; /* XS_??? */ uint32_t req_id;/* Request identifier, echoed in daemon's response. */ uint32_t tx_id; /* Transaction id (0 if not related to a transaction). */ uint32_t len; /* Length of data following this. */ /* Generally followed by nul-terminated string(s). */ }; Before there was only one request at a time so req_id could simply be forwarded back and forth. To allow simultaneous requests we need a different req_id for each message thus kernel keeps a monotonic increasing counter for this field and is written on every request irrespective of userspace value. Forwarding again the req_id on userspace requests is not a solution because we would open the possibility of userspace-generated req_id colliding with kernel ones. So this patch instead takes another route which is to artificially keep user req_id while keeping the xenbus logic as is. We do that by saving the original req_id before xs_send(), use the private kernel counter as req_id and then once reply comes and was validated, we restore back the original req_id. Cc: # 4.11 Fixes: fd8aa9095a ("xen: optimize xenbus driver for multiple concurrent xenstore accesses") Reported-by: Bhavesh Davda Signed-off-by: Joao Martins Reviewed-by: Juergen Gross Signed-off-by: Juergen Gross --- drivers/xen/xenbus/xenbus.h | 1 + drivers/xen/xenbus/xenbus_comms.c | 1 + drivers/xen/xenbus/xenbus_xs.c | 3 +++ 3 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus.h b/drivers/xen/xenbus/xenbus.h index 149c5e7efc89..092981171df1 100644 --- a/drivers/xen/xenbus/xenbus.h +++ b/drivers/xen/xenbus/xenbus.h @@ -76,6 +76,7 @@ struct xb_req_data { struct list_head list; wait_queue_head_t wq; struct xsd_sockmsg msg; + uint32_t caller_req_id; enum xsd_sockmsg_type type; char *body; const struct kvec *vec; diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c index 5b081a01779d..d239fc3c5e3d 100644 --- a/drivers/xen/xenbus/xenbus_comms.c +++ b/drivers/xen/xenbus/xenbus_comms.c @@ -309,6 +309,7 @@ static int process_msg(void) goto out; if (req->state == xb_req_state_wait_reply) { + req->msg.req_id = req->caller_req_id; req->msg.type = state.msg.type; req->msg.len = state.msg.len; req->body = state.body; diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index 3e59590c7254..3f3b29398ab8 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -227,6 +227,8 @@ static void xs_send(struct xb_req_data *req, struct xsd_sockmsg *msg) req->state = xb_req_state_queued; init_waitqueue_head(&req->wq); + /* Save the caller req_id and restore it later in the reply */ + req->caller_req_id = req->msg.req_id; req->msg.req_id = xs_request_enter(req); mutex_lock(&xb_write_mutex); @@ -310,6 +312,7 @@ static void *xs_talkv(struct xenbus_transaction t, req->num_vecs = num_vecs; req->cb = xs_wake_up; + msg.req_id = 0; msg.tx_id = t.id; msg.type = type; msg.len = 0; -- cgit v1.2.3 From 64d6871827b1e2ac8c9daf49f2c883378c7d50cd Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Wed, 14 Feb 2018 10:28:23 -0800 Subject: pvcalls-front: introduce a per sock_mapping refcount Introduce a per sock_mapping refcount, in addition to the existing global refcount. Thanks to the sock_mapping refcount, we can safely wait for it to be 1 in pvcalls_front_release before freeing an active socket, instead of waiting for the global refcount to be 1. Signed-off-by: Stefano Stabellini Acked-by: Juergen Gross Signed-off-by: Juergen Gross --- drivers/xen/pvcalls-front.c | 191 ++++++++++++++++++-------------------------- 1 file changed, 79 insertions(+), 112 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index 753d9cb437d0..11ce470b41a5 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -60,6 +60,7 @@ struct sock_mapping { bool active_socket; struct list_head list; struct socket *sock; + atomic_t refcount; union { struct { int irq; @@ -93,6 +94,32 @@ struct sock_mapping { }; }; +static inline struct sock_mapping *pvcalls_enter_sock(struct socket *sock) +{ + struct sock_mapping *map; + + if (!pvcalls_front_dev || + dev_get_drvdata(&pvcalls_front_dev->dev) == NULL) + return ERR_PTR(-ENOTCONN); + + map = (struct sock_mapping *)sock->sk->sk_send_head; + if (map == NULL) + return ERR_PTR(-ENOTSOCK); + + pvcalls_enter(); + atomic_inc(&map->refcount); + return map; +} + +static inline void pvcalls_exit_sock(struct socket *sock) +{ + struct sock_mapping *map; + + map = (struct sock_mapping *)sock->sk->sk_send_head; + atomic_dec(&map->refcount); + pvcalls_exit(); +} + static inline int get_request(struct pvcalls_bedata *bedata, int *req_id) { *req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1); @@ -369,31 +396,23 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr, if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM) return -EOPNOTSUPP; - pvcalls_enter(); - if (!pvcalls_front_dev) { - pvcalls_exit(); - return -ENOTCONN; - } + map = pvcalls_enter_sock(sock); + if (IS_ERR(map)) + return PTR_ERR(map); bedata = dev_get_drvdata(&pvcalls_front_dev->dev); - map = (struct sock_mapping *)sock->sk->sk_send_head; - if (!map) { - pvcalls_exit(); - return -ENOTSOCK; - } - spin_lock(&bedata->socket_lock); ret = get_request(bedata, &req_id); if (ret < 0) { spin_unlock(&bedata->socket_lock); - pvcalls_exit(); + pvcalls_exit_sock(sock); return ret; } ret = create_active(map, &evtchn); if (ret < 0) { spin_unlock(&bedata->socket_lock); - pvcalls_exit(); + pvcalls_exit_sock(sock); return ret; } @@ -423,7 +442,7 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr, smp_rmb(); ret = bedata->rsp[req_id].ret; bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; - pvcalls_exit(); + pvcalls_exit_sock(sock); return ret; } @@ -488,23 +507,15 @@ int pvcalls_front_sendmsg(struct socket *sock, struct msghdr *msg, if (flags & (MSG_CONFIRM|MSG_DONTROUTE|MSG_EOR|MSG_OOB)) return -EOPNOTSUPP; - pvcalls_enter(); - if (!pvcalls_front_dev) { - pvcalls_exit(); - return -ENOTCONN; - } + map = pvcalls_enter_sock(sock); + if (IS_ERR(map)) + return PTR_ERR(map); bedata = dev_get_drvdata(&pvcalls_front_dev->dev); - map = (struct sock_mapping *) sock->sk->sk_send_head; - if (!map) { - pvcalls_exit(); - return -ENOTSOCK; - } - mutex_lock(&map->active.out_mutex); if ((flags & MSG_DONTWAIT) && !pvcalls_front_write_todo(map)) { mutex_unlock(&map->active.out_mutex); - pvcalls_exit(); + pvcalls_exit_sock(sock); return -EAGAIN; } if (len > INT_MAX) @@ -526,7 +537,7 @@ again: tot_sent = sent; mutex_unlock(&map->active.out_mutex); - pvcalls_exit(); + pvcalls_exit_sock(sock); return tot_sent; } @@ -591,19 +602,11 @@ int pvcalls_front_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, if (flags & (MSG_CMSG_CLOEXEC|MSG_ERRQUEUE|MSG_OOB|MSG_TRUNC)) return -EOPNOTSUPP; - pvcalls_enter(); - if (!pvcalls_front_dev) { - pvcalls_exit(); - return -ENOTCONN; - } + map = pvcalls_enter_sock(sock); + if (IS_ERR(map)) + return PTR_ERR(map); bedata = dev_get_drvdata(&pvcalls_front_dev->dev); - map = (struct sock_mapping *) sock->sk->sk_send_head; - if (!map) { - pvcalls_exit(); - return -ENOTSOCK; - } - mutex_lock(&map->active.in_mutex); if (len > XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER)) len = XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER); @@ -623,7 +626,7 @@ int pvcalls_front_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, ret = 0; mutex_unlock(&map->active.in_mutex); - pvcalls_exit(); + pvcalls_exit_sock(sock); return ret; } @@ -637,24 +640,16 @@ int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len) if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM) return -EOPNOTSUPP; - pvcalls_enter(); - if (!pvcalls_front_dev) { - pvcalls_exit(); - return -ENOTCONN; - } + map = pvcalls_enter_sock(sock); + if (IS_ERR(map)) + return PTR_ERR(map); bedata = dev_get_drvdata(&pvcalls_front_dev->dev); - map = (struct sock_mapping *) sock->sk->sk_send_head; - if (map == NULL) { - pvcalls_exit(); - return -ENOTSOCK; - } - spin_lock(&bedata->socket_lock); ret = get_request(bedata, &req_id); if (ret < 0) { spin_unlock(&bedata->socket_lock); - pvcalls_exit(); + pvcalls_exit_sock(sock); return ret; } req = RING_GET_REQUEST(&bedata->ring, req_id); @@ -684,7 +679,7 @@ int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len) bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; map->passive.status = PVCALLS_STATUS_BIND; - pvcalls_exit(); + pvcalls_exit_sock(sock); return 0; } @@ -695,21 +690,13 @@ int pvcalls_front_listen(struct socket *sock, int backlog) struct xen_pvcalls_request *req; int notify, req_id, ret; - pvcalls_enter(); - if (!pvcalls_front_dev) { - pvcalls_exit(); - return -ENOTCONN; - } + map = pvcalls_enter_sock(sock); + if (IS_ERR(map)) + return PTR_ERR(map); bedata = dev_get_drvdata(&pvcalls_front_dev->dev); - map = (struct sock_mapping *) sock->sk->sk_send_head; - if (!map) { - pvcalls_exit(); - return -ENOTSOCK; - } - if (map->passive.status != PVCALLS_STATUS_BIND) { - pvcalls_exit(); + pvcalls_exit_sock(sock); return -EOPNOTSUPP; } @@ -717,7 +704,7 @@ int pvcalls_front_listen(struct socket *sock, int backlog) ret = get_request(bedata, &req_id); if (ret < 0) { spin_unlock(&bedata->socket_lock); - pvcalls_exit(); + pvcalls_exit_sock(sock); return ret; } req = RING_GET_REQUEST(&bedata->ring, req_id); @@ -741,7 +728,7 @@ int pvcalls_front_listen(struct socket *sock, int backlog) bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; map->passive.status = PVCALLS_STATUS_LISTEN; - pvcalls_exit(); + pvcalls_exit_sock(sock); return ret; } @@ -753,21 +740,13 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) struct xen_pvcalls_request *req; int notify, req_id, ret, evtchn, nonblock; - pvcalls_enter(); - if (!pvcalls_front_dev) { - pvcalls_exit(); - return -ENOTCONN; - } + map = pvcalls_enter_sock(sock); + if (IS_ERR(map)) + return PTR_ERR(map); bedata = dev_get_drvdata(&pvcalls_front_dev->dev); - map = (struct sock_mapping *) sock->sk->sk_send_head; - if (!map) { - pvcalls_exit(); - return -ENOTSOCK; - } - if (map->passive.status != PVCALLS_STATUS_LISTEN) { - pvcalls_exit(); + pvcalls_exit_sock(sock); return -EINVAL; } @@ -785,13 +764,13 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) goto received; } if (nonblock) { - pvcalls_exit(); + pvcalls_exit_sock(sock); return -EAGAIN; } if (wait_event_interruptible(map->passive.inflight_accept_req, !test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags))) { - pvcalls_exit(); + pvcalls_exit_sock(sock); return -EINTR; } } @@ -802,7 +781,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags); spin_unlock(&bedata->socket_lock); - pvcalls_exit(); + pvcalls_exit_sock(sock); return ret; } map2 = kzalloc(sizeof(*map2), GFP_ATOMIC); @@ -810,7 +789,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags); spin_unlock(&bedata->socket_lock); - pvcalls_exit(); + pvcalls_exit_sock(sock); return -ENOMEM; } ret = create_active(map2, &evtchn); @@ -819,7 +798,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags); spin_unlock(&bedata->socket_lock); - pvcalls_exit(); + pvcalls_exit_sock(sock); return ret; } list_add_tail(&map2->list, &bedata->socket_mappings); @@ -841,13 +820,13 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) /* We could check if we have received a response before returning. */ if (nonblock) { WRITE_ONCE(map->passive.inflight_req_id, req_id); - pvcalls_exit(); + pvcalls_exit_sock(sock); return -EAGAIN; } if (wait_event_interruptible(bedata->inflight_req, READ_ONCE(bedata->rsp[req_id].req_id) == req_id)) { - pvcalls_exit(); + pvcalls_exit_sock(sock); return -EINTR; } /* read req_id, then the content */ @@ -862,7 +841,7 @@ received: clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags); pvcalls_front_free_map(bedata, map2); - pvcalls_exit(); + pvcalls_exit_sock(sock); return -ENOMEM; } newsock->sk->sk_send_head = (void *)map2; @@ -874,7 +853,7 @@ received: clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags); wake_up(&map->passive.inflight_accept_req); - pvcalls_exit(); + pvcalls_exit_sock(sock); return ret; } @@ -965,23 +944,16 @@ __poll_t pvcalls_front_poll(struct file *file, struct socket *sock, struct sock_mapping *map; __poll_t ret; - pvcalls_enter(); - if (!pvcalls_front_dev) { - pvcalls_exit(); + map = pvcalls_enter_sock(sock); + if (IS_ERR(map)) return EPOLLNVAL; - } bedata = dev_get_drvdata(&pvcalls_front_dev->dev); - map = (struct sock_mapping *) sock->sk->sk_send_head; - if (!map) { - pvcalls_exit(); - return EPOLLNVAL; - } if (map->active_socket) ret = pvcalls_front_poll_active(file, bedata, map, wait); else ret = pvcalls_front_poll_passive(file, bedata, map, wait); - pvcalls_exit(); + pvcalls_exit_sock(sock); return ret; } @@ -995,25 +967,20 @@ int pvcalls_front_release(struct socket *sock) if (sock->sk == NULL) return 0; - pvcalls_enter(); - if (!pvcalls_front_dev) { - pvcalls_exit(); - return -EIO; + map = pvcalls_enter_sock(sock); + if (IS_ERR(map)) { + if (PTR_ERR(map) == -ENOTCONN) + return -EIO; + else + return 0; } - bedata = dev_get_drvdata(&pvcalls_front_dev->dev); - map = (struct sock_mapping *) sock->sk->sk_send_head; - if (map == NULL) { - pvcalls_exit(); - return 0; - } - spin_lock(&bedata->socket_lock); ret = get_request(bedata, &req_id); if (ret < 0) { spin_unlock(&bedata->socket_lock); - pvcalls_exit(); + pvcalls_exit_sock(sock); return ret; } sock->sk->sk_send_head = NULL; @@ -1043,10 +1010,10 @@ int pvcalls_front_release(struct socket *sock) /* * We need to make sure that sendmsg/recvmsg on this socket have * not started before we've cleared sk_send_head here. The - * easiest (though not optimal) way to guarantee this is to see - * that no pvcall (other than us) is in progress. + * easiest way to guarantee this is to see that no pvcalls + * (other than us) is in progress on this socket. */ - while (atomic_read(&pvcalls_refcount) > 1) + while (atomic_read(&map->refcount) > 1) cpu_relax(); pvcalls_front_free_map(bedata, map); -- cgit v1.2.3 From d1a75e0896f5e9f5cb6a979caaea39f1f4b9feb1 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Wed, 14 Feb 2018 10:28:24 -0800 Subject: pvcalls-front: wait for other operations to return when release passive sockets Passive sockets can have ongoing operations on them, specifically, we have two wait_event_interruptable calls in pvcalls_front_accept. Add two wake_up calls in pvcalls_front_release, then wait for the potential waiters to return and release the sock_mapping refcount. Signed-off-by: Stefano Stabellini Acked-by: Juergen Gross Signed-off-by: Juergen Gross --- drivers/xen/pvcalls-front.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index 11ce470b41a5..aedbee3b2838 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -1018,6 +1018,12 @@ int pvcalls_front_release(struct socket *sock) pvcalls_front_free_map(bedata, map); } else { + wake_up(&bedata->inflight_req); + wake_up(&map->passive.inflight_accept_req); + + while (atomic_read(&map->refcount) > 1) + cpu_relax(); + spin_lock(&bedata->socket_lock); list_del(&map->list); spin_unlock(&bedata->socket_lock); -- cgit v1.2.3 From f027e0b3a774e10302207e91d304bbf99e3a8b36 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 14 Feb 2018 15:43:00 +0100 Subject: iio: adis_lib: Initialize trigger before requesting interrupt The adis_probe_trigger() creates a new IIO trigger and requests an interrupt associated with the trigger. The interrupt uses the generic iio_trigger_generic_data_rdy_poll() function as its interrupt handler. Currently the driver initializes some fields of the trigger structure after the interrupt has been requested. But an interrupt can fire as soon as it has been requested. This opens up a race condition. iio_trigger_generic_data_rdy_poll() will access the trigger data structure and dereference the ops field. If the ops field is not yet initialized this will result in a NULL pointer deref. It is not expected that the device generates an interrupt at this point, so typically this issue did not surface unless e.g. due to a hardware misconfiguration (wrong interrupt number, wrong polarity, etc.). But some newer devices from the ADIS family start to generate periodic interrupts in their power-on reset configuration and unfortunately the interrupt can not be masked in the device. This makes the race condition much more visible and the following crash has been observed occasionally when booting a system using the ADIS16460. Unable to handle kernel NULL pointer dereference at virtual address 00000008 pgd = c0004000 [00000008] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.9.0-04126-gf9739f0-dirty #257 Hardware name: Xilinx Zynq Platform task: ef04f640 task.stack: ef050000 PC is at iio_trigger_notify_done+0x30/0x68 LR is at iio_trigger_generic_data_rdy_poll+0x18/0x20 pc : [] lr : [] psr: 60000193 sp : ef051bb8 ip : 00000000 fp : ef106400 r10: c081d80a r9 : ef3bfa00 r8 : 00000087 r7 : ef051bec r6 : 00000000 r5 : ef3bfa00 r4 : ee92ab00 r3 : 00000000 r2 : 00000000 r1 : 00000000 r0 : ee97e400 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment none Control: 18c5387d Table: 0000404a DAC: 00000051 Process swapper/0 (pid: 1, stack limit = 0xef050210) [] (iio_trigger_notify_done) from [] (__handle_irq_event_percpu+0x88/0x118) [] (__handle_irq_event_percpu) from [] (handle_irq_event_percpu+0x1c/0x58) [] (handle_irq_event_percpu) from [] (handle_irq_event+0x38/0x5c) [] (handle_irq_event) from [] (handle_level_irq+0xa4/0x130) [] (handle_level_irq) from [] (generic_handle_irq+0x24/0x34) [] (generic_handle_irq) from [] (zynq_gpio_irqhandler+0xb8/0x13c) [] (zynq_gpio_irqhandler) from [] (generic_handle_irq+0x24/0x34) [] (generic_handle_irq) from [] (__handle_domain_irq+0x5c/0xb4) [] (__handle_domain_irq) from [] (gic_handle_irq+0x48/0x8c) [] (gic_handle_irq) from [] (__irq_svc+0x6c/0xa8) To fix this make sure that the trigger is fully initialized before requesting the interrupt. Fixes: ccd2b52f4ac6 ("staging:iio: Add common ADIS library") Reported-by: Robin Getz Signed-off-by: Lars-Peter Clausen Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis_trigger.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index 0dd5a381be64..457372f36791 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -46,6 +46,10 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) if (adis->trig == NULL) return -ENOMEM; + adis->trig->dev.parent = &adis->spi->dev; + adis->trig->ops = &adis_trigger_ops; + iio_trigger_set_drvdata(adis->trig, adis); + ret = request_irq(adis->spi->irq, &iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_RISING, @@ -54,9 +58,6 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) if (ret) goto error_free_trig; - adis->trig->dev.parent = &adis->spi->dev; - adis->trig->ops = &adis_trigger_ops; - iio_trigger_set_drvdata(adis->trig, adis); ret = iio_trigger_register(adis->trig); indio_dev->trig = iio_trigger_get(adis->trig); -- cgit v1.2.3 From 4cd140bda6494543f1c1b0ccceceaa44b676eef6 Mon Sep 17 00:00:00 2001 From: Stefan Windfeldt-Prytz Date: Thu, 15 Feb 2018 15:02:53 +0100 Subject: iio: buffer: check if a buffer has been set up when poll is called If no iio buffer has been set up and poll is called return 0. Without this check there will be a null pointer dereference when calling poll on a iio driver without an iio buffer. Cc: stable@vger.kernel.org Signed-off-by: Stefan Windfeldt-Prytz Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index eda2a0f1658f..c7499c8bd69f 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -175,7 +175,7 @@ unsigned int iio_buffer_poll(struct file *filp, struct iio_dev *indio_dev = filp->private_data; struct iio_buffer *rb = indio_dev->buffer; - if (!indio_dev->info) + if (!indio_dev->info || rb == NULL) return 0; poll_wait(filp, &rb->pollq, wait); -- cgit v1.2.3 From 565e0450129647df5112bff3df3ffd02b0c08e32 Mon Sep 17 00:00:00 2001 From: Aliaksei Karaliou Date: Sat, 23 Dec 2017 21:20:31 +0300 Subject: md/raid5: simplify uninitialization of shrinker Don't use shrinker.nr_deferred to check whether shrinker was initialized or not. Now this check was integrated into unregister_shrinker(), so it is safe to call it against unregistered shrinker. Signed-off-by: Aliaksei Karaliou Signed-off-by: Shaohua Li --- drivers/md/raid5.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 50d01144b805..36e050678f5a 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6764,9 +6764,7 @@ static void free_conf(struct r5conf *conf) log_exit(conf); - if (conf->shrinker.nr_deferred) - unregister_shrinker(&conf->shrinker); - + unregister_shrinker(&conf->shrinker); free_thread_groups(conf); shrink_stripes(conf); raid5_free_percpu(conf); -- cgit v1.2.3 From 56a64c177abd85a01c5881e195c363b7bda448f2 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Wed, 17 Jan 2018 13:38:02 +0000 Subject: md/raid1: Fix trailing semicolon The trailing semicolon is an empty statement that does no operation. Removing it since it doesn't do anything. Signed-off-by: Luis de Bethencourt Signed-off-by: Shaohua Li --- drivers/md/raid1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index b2eae332e1a2..f978eddc7a21 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1108,7 +1108,7 @@ static void alloc_behind_master_bio(struct r1bio *r1_bio, bio_copy_data(behind_bio, bio); skip_copy: - r1_bio->behind_master_bio = behind_bio;; + r1_bio->behind_master_bio = behind_bio; set_bit(R1BIO_BehindIO, &r1_bio->state); return; -- cgit v1.2.3 From 3acdb7b514198d81ef7efcb2e86f498776ac10a7 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 13 Jan 2018 09:49:03 +0100 Subject: md-multipath: Use seq_putc() in multipath_status() A single character (closing square bracket) should be put into a sequence. Thus use the corresponding function "seq_putc". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Shaohua Li --- drivers/md/md-multipath.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/md-multipath.c b/drivers/md/md-multipath.c index e40065bdbfc8..0a7e99d62c69 100644 --- a/drivers/md/md-multipath.c +++ b/drivers/md/md-multipath.c @@ -157,7 +157,7 @@ static void multipath_status(struct seq_file *seq, struct mddev *mddev) seq_printf (seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_"); } rcu_read_unlock(); - seq_printf (seq, "]"); + seq_putc(seq, ']'); } static int multipath_congested(struct mddev *mddev, int bits) -- cgit v1.2.3 From 4b242e97d74192bbc5decd808c058cbc347af016 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Fri, 19 Jan 2018 11:37:56 +0800 Subject: raid10: change the size of resync window for clustered raid To align with raid1's resync window, we need to set the resync window of raid10 to 32M as well. Fixes: 8db87912c9a8 ("md-cluster: Use a small window for raid10 resync") Reported-by: Zhilong Liu Signed-off-by: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/raid10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 99c9207899a7..8d7ddc947d9d 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -141,7 +141,7 @@ static void r10bio_pool_free(void *r10_bio, void *data) #define RESYNC_WINDOW (1024*1024) /* maximum number of concurrent requests, memory permitting */ #define RESYNC_DEPTH (32*1024*1024/RESYNC_BLOCK_SIZE) -#define CLUSTER_RESYNC_WINDOW (16 * RESYNC_WINDOW) +#define CLUSTER_RESYNC_WINDOW (32 * RESYNC_WINDOW) #define CLUSTER_RESYNC_WINDOW_SECTORS (CLUSTER_RESYNC_WINDOW >> 9) /* -- cgit v1.2.3 From b126194cbb799f9980b92a77e58db6ad794c8082 Mon Sep 17 00:00:00 2001 From: Xiao Ni Date: Wed, 24 Jan 2018 12:17:38 +0800 Subject: MD: Free bioset when md_run fails Signed-off-by: Xiao Ni Acked-by: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/md.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index bc67ab6844f0..bcf4ab9ab3df 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5497,8 +5497,10 @@ int md_run(struct mddev *mddev) } if (mddev->sync_set == NULL) { mddev->sync_set = bioset_create(BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); - if (!mddev->sync_set) - return -ENOMEM; + if (!mddev->sync_set) { + err = -ENOMEM; + goto abort; + } } spin_lock(&pers_lock); @@ -5511,7 +5513,8 @@ int md_run(struct mddev *mddev) else pr_warn("md: personality for level %s is not loaded!\n", mddev->clevel); - return -EINVAL; + err = -EINVAL; + goto abort; } spin_unlock(&pers_lock); if (mddev->level != pers->level) { @@ -5524,7 +5527,8 @@ int md_run(struct mddev *mddev) pers->start_reshape == NULL) { /* This personality cannot handle reshaping... */ module_put(pers->owner); - return -EINVAL; + err = -EINVAL; + goto abort; } if (pers->sync_request) { @@ -5593,7 +5597,7 @@ int md_run(struct mddev *mddev) mddev->private = NULL; module_put(pers->owner); bitmap_destroy(mddev); - return err; + goto abort; } if (mddev->queue) { bool nonrot = true; @@ -5655,6 +5659,18 @@ int md_run(struct mddev *mddev) sysfs_notify_dirent_safe(mddev->sysfs_action); sysfs_notify(&mddev->kobj, NULL, "degraded"); return 0; + +abort: + if (mddev->bio_set) { + bioset_free(mddev->bio_set); + mddev->bio_set = NULL; + } + if (mddev->sync_set) { + bioset_free(mddev->sync_set); + mddev->sync_set = NULL; + } + + return err; } EXPORT_SYMBOL_GPL(md_run); -- cgit v1.2.3 From 9c7be59fc519af9081c46c48f06f2b8fadf55ad8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 16 Feb 2018 10:48:20 +0100 Subject: libata: Apply NOLPM quirk to Crucial MX100 512GB SSDs Various people have reported the Crucial MX100 512GB model not working with LPM set to min_power. I've now received a report that it also does not work with the new med_power_with_dipm level. It does work with medium_power, but that has no measurable power-savings and given the amount of people being bitten by the other levels not working, this commit just disables LPM altogether. Note all reporters of this have either the 512GB model (max capacity), or are not specifying their SSD's size. So for now this quirk assumes this is a problem with the 512GB model only. Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=89261 Buglink: https://github.com/linrunner/TLP/issues/84 Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 61b09968d032..28cad49fc846 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4530,6 +4530,11 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "PIONEER DVD-RW DVR-212D", NULL, ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, + /* The 512GB version of the MX100 has both queued TRIM and LPM issues */ + { "Crucial_CT512MX100*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM | + ATA_HORKAGE_NOLPM, }, + /* devices that don't properly handle queued TRIM commands */ { "Micron_M500_*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, -- cgit v1.2.3 From 4b6c1060eaa6495aa5b0032e8f2d51dd936b1257 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Fri, 2 Feb 2018 23:13:19 +0100 Subject: md: fix md_write_start() deadlock w/o metadata devices If no metadata devices are configured on raid1/4/5/6/10 (e.g. via dm-raid), md_write_start() unconditionally waits for superblocks to be written thus deadlocking. Fix introduces mddev->has_superblocks bool, defines it in md_run() and checks for it in md_write_start() to conditionally avoid waiting. Once on it, check for non-existing superblocks in md_super_write(). Link: https://bugzilla.kernel.org/show_bug.cgi?id=198647 Fixes: cc27b0c78c796 ("md: fix deadlock between mddev_suspend() and md_write_start()") Signed-off-by: Heinz Mauelshagen Signed-off-by: Shaohua Li --- drivers/md/md.c | 10 ++++++++++ drivers/md/md.h | 2 ++ 2 files changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index bcf4ab9ab3df..9b73cf139b80 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -801,6 +801,9 @@ void md_super_write(struct mddev *mddev, struct md_rdev *rdev, struct bio *bio; int ff = 0; + if (!page) + return; + if (test_bit(Faulty, &rdev->flags)) return; @@ -5452,6 +5455,7 @@ int md_run(struct mddev *mddev) * the only valid external interface is through the md * device. */ + mddev->has_superblocks = false; rdev_for_each(rdev, mddev) { if (test_bit(Faulty, &rdev->flags)) continue; @@ -5465,6 +5469,9 @@ int md_run(struct mddev *mddev) set_disk_ro(mddev->gendisk, 1); } + if (rdev->sb_page) + mddev->has_superblocks = true; + /* perform some consistency tests on the device. * We don't want the data to overlap the metadata, * Internal Bitmap issues have been handled elsewhere. @@ -8065,6 +8072,7 @@ EXPORT_SYMBOL(md_done_sync); bool md_write_start(struct mddev *mddev, struct bio *bi) { int did_change = 0; + if (bio_data_dir(bi) != WRITE) return true; @@ -8097,6 +8105,8 @@ bool md_write_start(struct mddev *mddev, struct bio *bi) rcu_read_unlock(); if (did_change) sysfs_notify_dirent_safe(mddev->sysfs_state); + if (!mddev->has_superblocks) + return true; wait_event(mddev->sb_wait, !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) || mddev->suspended); diff --git a/drivers/md/md.h b/drivers/md/md.h index 58cd20a5e85e..fbc925cce810 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -468,6 +468,8 @@ struct mddev { void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev); struct md_cluster_info *cluster_info; unsigned int good_device_nr; /* good device num within cluster raid */ + + bool has_superblocks:1; }; enum recovery_flags { -- cgit v1.2.3 From f2785b527cda46314805123ddcbc871655b7c4c4 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 3 Feb 2018 09:19:30 +1100 Subject: md: document lifetime of internal rdev pointer. The rdev pointer kept in the local 'config' for each for raid1, raid10, raid4/5/6 has non-obvious lifetime rules. Sometimes RCU is needed, sometimes a lock, something nothing. Add documentation to explain this. Signed-off-by: NeilBrown Signed-off-by: Shaohua Li --- drivers/md/raid1.h | 12 ++++++++++++ drivers/md/raid10.h | 13 +++++++++++++ drivers/md/raid5.h | 12 ++++++++++++ 3 files changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h index c7294e7557e0..eb84bc68e2fd 100644 --- a/drivers/md/raid1.h +++ b/drivers/md/raid1.h @@ -26,6 +26,18 @@ #define BARRIER_BUCKETS_NR_BITS (PAGE_SHIFT - ilog2(sizeof(atomic_t))) #define BARRIER_BUCKETS_NR (1<reconfig_mutex + * 2/ when resync/recovery is known to be happening - i.e. in code that is + * called as part of performing resync/recovery. + * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer + * and if it is non-NULL, increment rdev->nr_pending before dropping the + * RCU lock. + * When .rdev is set to NULL, the nr_pending count checked again and if it has + * been incremented, the pointer is put back in .rdev. + */ + struct raid1_info { struct md_rdev *rdev; sector_t head_position; diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h index db2ac22ac1b4..e2e8840de9bf 100644 --- a/drivers/md/raid10.h +++ b/drivers/md/raid10.h @@ -2,6 +2,19 @@ #ifndef _RAID10_H #define _RAID10_H +/* Note: raid10_info.rdev can be set to NULL asynchronously by + * raid10_remove_disk. + * There are three safe ways to access raid10_info.rdev. + * 1/ when holding mddev->reconfig_mutex + * 2/ when resync/recovery/reshape is known to be happening - i.e. in code + * that is called as part of performing resync/recovery/reshape. + * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer + * and if it is non-NULL, increment rdev->nr_pending before dropping the + * RCU lock. + * When .rdev is set to NULL, the nr_pending count checked again and if it has + * been incremented, the pointer is put back in .rdev. + */ + struct raid10_info { struct md_rdev *rdev, *replacement; sector_t head_position; diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 2e6123825095..3f8da26032ac 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -450,6 +450,18 @@ enum { * HANDLE gets cleared if stripe_handle leaves nothing locked. */ +/* Note: disk_info.rdev can be set to NULL asynchronously by raid5_remove_disk. + * There are three safe ways to access disk_info.rdev. + * 1/ when holding mddev->reconfig_mutex + * 2/ when resync/recovery/reshape is known to be happening - i.e. in code that + * is called as part of performing resync/recovery/reshape. + * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer + * and if it is non-NULL, increment rdev->nr_pending before dropping the RCU + * lock. + * When .rdev is set to NULL, the nr_pending count checked again and if + * it has been incremented, the pointer is put back in .rdev. + */ + struct disk_info { struct md_rdev *rdev, *replacement; struct page *extra_page; /* extra page to use in prexor */ -- cgit v1.2.3 From 9487cfd3430d07366801886bdf185799a2b6f066 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Wed, 7 Feb 2018 17:39:14 +0100 Subject: s390/dasd: fix handling of internal requests Internal DASD device driver I/O such as query host access count or path verification is started using the _sleep_on() function. To mark a request as started or ended the callback_data is set to either DASD_SLEEPON_START_TAG or DASD_SLEEPON_END_TAG. In cases where the request has to be stopped unconditionally the status is set to DASD_SLEEPON_END_TAG as well which leads to immediate clearing of the request. But the request might still be on a device request queue for normal operation which might lead to a panic because of a BUG() statement in __dasd_device_process_final_queue() or a list corruption of the device request queue. Fix by removing the setting of DASD_SLEEPON_END_TAG in the dasd_cancel_req() and dasd_generic_requeue_all_requests() functions and ensure that the request is not deleted in the requeue function. Trigger the device tasklet in the requeue function and let the normal processing cleanup the request. Signed-off-by: Stefan Haberland Reviewed-by: Jan Hoeppner Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index a7c15f0085e2..ecef8e73d40b 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2581,8 +2581,6 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr) case DASD_CQR_QUEUED: /* request was not started - just set to cleared */ cqr->status = DASD_CQR_CLEARED; - if (cqr->callback_data == DASD_SLEEPON_START_TAG) - cqr->callback_data = DASD_SLEEPON_END_TAG; break; case DASD_CQR_IN_IO: /* request in IO - terminate IO and release again */ @@ -3902,9 +3900,12 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) wait_event(dasd_flush_wq, (cqr->status != DASD_CQR_CLEAR_PENDING)); - /* mark sleepon requests as ended */ - if (cqr->callback_data == DASD_SLEEPON_START_TAG) - cqr->callback_data = DASD_SLEEPON_END_TAG; + /* + * requeue requests to blocklayer will only work + * for block device requests + */ + if (_dasd_requeue_request(cqr)) + continue; /* remove requests from device and block queue */ list_del_init(&cqr->devlist); @@ -3917,13 +3918,6 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) cqr = refers; } - /* - * requeue requests to blocklayer will only work - * for block device requests - */ - if (_dasd_requeue_request(cqr)) - continue; - if (cqr->block) list_del_init(&cqr->blocklist); cqr->block->base->discipline->free_cp( @@ -3940,8 +3934,7 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) list_splice_tail(&requeue_queue, &device->ccw_queue); spin_unlock_irq(get_ccwdev_lock(device->cdev)); } - /* wake up generic waitqueue for eventually ended sleepon requests */ - wake_up(&generic_waitq); + dasd_schedule_device_bh(device); return rc; } -- cgit v1.2.3 From 5682e268350f9eccdbb04006605c1b7068a7b323 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 17 Feb 2018 21:05:04 +0800 Subject: clk: sunxi-ng: a31: Fix CLK_OUT_* clock ops When support for the A31/A31s CCU was first added, the clock ops for the CLK_OUT_* clocks was set to the wrong type. The clocks are MP-type, but the ops was set for div (M) clocks. This went unnoticed until now. This was because while they are different clocks, their data structures aligned in a way that ccu_div_ops would access the second ccu_div_internal and ccu_mux_internal structures, which were valid, if not incorrect. Furthermore, the use of these CLK_OUT_* was for feeding a precise 32.768 kHz clock signal to the WiFi chip. This was achievable by using the parent with the same clock rate and no divider. So the incorrect divider setting did not affect this usage. Commit 946797aa3f08 ("clk: sunxi-ng: Support fixed post-dividers on MP style clocks") added a new field to the ccu_mp structure, which broke the aforementioned alignment. Now the system crashes as div_ops tries to look up a nonexistent table. Reported-by: Philipp Rossak Tested-by: Philipp Rossak Fixes: c6e6c96d8fa6 ("clk: sunxi-ng: Add A31/A31s clocks") Cc: Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun6i-a31.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index 72b16ed1012b..3b97f60540ad 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -762,7 +762,7 @@ static struct ccu_mp out_a_clk = { .features = CCU_FEATURE_FIXED_PREDIV, .hw.init = CLK_HW_INIT_PARENTS("out-a", clk_out_parents, - &ccu_div_ops, + &ccu_mp_ops, 0), }, }; @@ -783,7 +783,7 @@ static struct ccu_mp out_b_clk = { .features = CCU_FEATURE_FIXED_PREDIV, .hw.init = CLK_HW_INIT_PARENTS("out-b", clk_out_parents, - &ccu_div_ops, + &ccu_mp_ops, 0), }, }; @@ -804,7 +804,7 @@ static struct ccu_mp out_c_clk = { .features = CCU_FEATURE_FIXED_PREDIV, .hw.init = CLK_HW_INIT_PARENTS("out-c", clk_out_parents, - &ccu_div_ops, + &ccu_mp_ops, 0), }, }; -- cgit v1.2.3 From ce162bfbc0b601841886965baba14877127c7c7c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 24 Jan 2018 08:40:51 +0100 Subject: mac80211_hwsim: don't use WQ_MEM_RECLAIM We're obviously not part of a memory reclaim path, so don't set the flag. This also causes a warning in check_flush_dependency() since we end up in a code path that flushes a non-reclaim workqueue, and we shouldn't do that if we were really part of reclaim. Reported-by: syzbot+41cdaf4232c50e658934@syzkaller.appspotmail.com Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index f6d4a50f1bdb..829ac22b72fc 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3455,7 +3455,7 @@ static int __init init_mac80211_hwsim(void) spin_lock_init(&hwsim_radio_lock); - hwsim_wq = alloc_workqueue("hwsim_wq",WQ_MEM_RECLAIM,0); + hwsim_wq = alloc_workqueue("hwsim_wq", 0, 0); if (!hwsim_wq) return -ENOMEM; -- cgit v1.2.3 From c795f3052b60b01e80485fad98c53e5e67d093c9 Mon Sep 17 00:00:00 2001 From: Tobias Jordan Date: Thu, 15 Feb 2018 15:34:55 +0100 Subject: gpu: ipu-v3: pre: fix device node leak in ipu_pre_lookup_by_phandle Before returning, call of_node_put() for the device node returned by of_parse_phandle(). Fixes: d2a34232580a ("gpu: ipu-v3: add driver for Prefetch Resolve Engine") Signed-off-by: Tobias Jordan Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-pre.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/ipu-v3/ipu-pre.c b/drivers/gpu/ipu-v3/ipu-pre.c index f1cec3d70498..0f70e8847540 100644 --- a/drivers/gpu/ipu-v3/ipu-pre.c +++ b/drivers/gpu/ipu-v3/ipu-pre.c @@ -129,11 +129,14 @@ ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index) if (pre_node == pre->dev->of_node) { mutex_unlock(&ipu_pre_list_mutex); device_link_add(dev, pre->dev, DL_FLAG_AUTOREMOVE); + of_node_put(pre_node); return pre; } } mutex_unlock(&ipu_pre_list_mutex); + of_node_put(pre_node); + return NULL; } -- cgit v1.2.3 From 3addaba8141bc6a4f649a48f46e552af32922147 Mon Sep 17 00:00:00 2001 From: Tobias Jordan Date: Thu, 15 Feb 2018 15:35:30 +0100 Subject: gpu: ipu-v3: prg: fix device node leak in ipu_prg_lookup_by_phandle Before returning, call of_node_put() for the device node returned by of_parse_phandle(). Fixes: ea9c260514c1 ("gpu: ipu-v3: add driver for Prefetch Resolve Gasket") Signed-off-by: Tobias Jordan Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-prg.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/ipu-v3/ipu-prg.c b/drivers/gpu/ipu-v3/ipu-prg.c index 067365c733c6..97b99500153d 100644 --- a/drivers/gpu/ipu-v3/ipu-prg.c +++ b/drivers/gpu/ipu-v3/ipu-prg.c @@ -102,11 +102,14 @@ ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id) mutex_unlock(&ipu_prg_list_mutex); device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE); prg->id = ipu_id; + of_node_put(prg_node); return prg; } } mutex_unlock(&ipu_prg_list_mutex); + of_node_put(prg_node); + return NULL; } -- cgit v1.2.3 From 58a22fc44539ad7fd4c07c9fcc156cad1e3340ea Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 25 Jan 2018 10:37:52 +0100 Subject: gpu: ipu-cpmem: add 16-bit grayscale support to ipu_cpmem_set_image Add the missing offset calculation for 16-bit grayscale images. Since the IPU only supports capturing greyscale in raw passthrough mode, it is the same as 16-bit bayer formats. Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-cpmem.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c index ef32377b91c0..9f2d9ec42add 100644 --- a/drivers/gpu/ipu-v3/ipu-cpmem.c +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c @@ -795,6 +795,7 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) case V4L2_PIX_FMT_SGBRG16: case V4L2_PIX_FMT_SGRBG16: case V4L2_PIX_FMT_SRGGB16: + case V4L2_PIX_FMT_Y16: offset = image->rect.left * 2 + image->rect.top * pix->bytesperline; break; -- cgit v1.2.3 From 50b0f0aee839b5a9995fe7964a678634f75a0518 Mon Sep 17 00:00:00 2001 From: Jan Luebbe Date: Tue, 13 Feb 2018 18:35:36 +0100 Subject: gpu: ipu-csi: add 10/12-bit grayscale support to mbus_code_to_bus_cfg The 10/12-bit config used for bayer formats is used for grayscale as well. Signed-off-by: Jan Luebbe Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-csi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c index 24e12b87a0cb..caa05b0702e1 100644 --- a/drivers/gpu/ipu-v3/ipu-csi.c +++ b/drivers/gpu/ipu-v3/ipu-csi.c @@ -288,6 +288,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_Y10_1X10: cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; cfg->mipi_dt = MIPI_DT_RAW10; cfg->data_width = IPU_CSI_DATA_WIDTH_10; @@ -296,6 +297,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) case MEDIA_BUS_FMT_SGBRG12_1X12: case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_Y12_1X12: cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; cfg->mipi_dt = MIPI_DT_RAW12; cfg->data_width = IPU_CSI_DATA_WIDTH_12; -- cgit v1.2.3 From 06998a756a3865817b87a129a7e5d5bb66dc1ec3 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Sun, 18 Feb 2018 16:53:59 +0800 Subject: drm/edid: Add 6 bpc quirk for CPT panel in Asus UX303LA Similar to commit e10aec652f31 ("drm/edid: Add 6 bpc quirk for display AEO model 0."), the EDID reports "DFP 1.x compliant TMDS" but it support 6bpc instead of 8 bpc. Hence, use 6 bpc quirk for this panel. Fixes: 196f954e2509 ("drm/i915/dp: Revert "drm/i915/dp: fall back to 18 bpp when sink capability is unknown"") BugLink: https://bugs.launchpad.net/bugs/1749420 Signed-off-by: Kai-Heng Feng Reviewed-by: Mario Kleiner Cc: # v4.8+ Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180218085359.7817-1-kai.heng.feng@canonical.com --- drivers/gpu/drm/drm_edid.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index cb487148359a..16fb76ba6509 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -113,6 +113,9 @@ static const struct edid_quirk { /* AEO model 0 reports 8 bpc, but is a 6 bpc panel */ { "AEO", 0, EDID_QUIRK_FORCE_6BPC }, + /* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */ + { "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC }, + /* Belinea 10 15 55 */ { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, -- cgit v1.2.3 From b37f78f234bf4fd98979d6c3ccc0f85e508f978f Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Fri, 16 Feb 2018 15:56:37 -0700 Subject: net: qualcomm: rmnet: Fix crash on real dev unregistration With CONFIG_DEBUG_PREEMPT enabled, a crash with the following call stack was observed when removing a real dev which had rmnet devices attached to it. To fix this, remove the netdev_upper link APIs and instead use the existing information in rmnet_port and rmnet_priv to get the association between real and rmnet devs. BUG: sleeping function called from invalid context in_atomic(): 0, irqs_disabled(): 0, pid: 5762, name: ip Preemption disabled at: [] debug_object_active_state+0xa4/0x16c Internal error: Oops - BUG: 0 [#1] PREEMPT SMP Modules linked in: PC is at ___might_sleep+0x13c/0x180 LR is at ___might_sleep+0x17c/0x180 [] ___might_sleep+0x13c/0x180 [] __might_sleep+0x58/0x8c [] mutex_lock+0x2c/0x48 [] kernfs_remove_by_name_ns+0x48/0xa8 [] sysfs_remove_link+0x30/0x58 [] __netdev_adjacent_dev_remove+0x14c/0x1e0 [] __netdev_adjacent_dev_unlink_lists+0x40/0x68 [] netdev_upper_dev_unlink+0xb4/0x1fc [] rmnet_dev_walk_unreg+0x6c/0xc8 [] netdev_walk_all_lower_dev_rcu+0x58/0xb4 [] rmnet_config_notify_cb+0xf4/0x134 [] raw_notifier_call_chain+0x58/0x78 [] call_netdevice_notifiers_info+0x48/0x78 [] rollback_registered_many+0x230/0x3c8 [] unregister_netdevice_many+0x38/0x94 [] rtnl_delete_link+0x58/0x88 [] rtnl_dellink+0xbc/0x1cc [] rtnetlink_rcv_msg+0xb0/0x244 [] netlink_rcv_skb+0xb4/0xdc [] rtnetlink_rcv+0x34/0x44 [] netlink_unicast+0x1ec/0x294 [] netlink_sendmsg+0x320/0x390 [] sock_sendmsg+0x54/0x60 [] ___sys_sendmsg+0x298/0x2b0 [] SyS_sendmsg+0xb4/0xf0 [] el0_svc_naked+0x24/0x28 Fixes: ceed73a2cf4a ("drivers: net: ethernet: qualcomm: rmnet: Initial implementation") Fixes: 60d58f971c10 ("net: qualcomm: rmnet: Implement bridge mode") Signed-off-by: Subash Abhinov Kasiviswanathan Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 68 +++++----------------- 1 file changed, 14 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c index 7e7704daf5f1..c4949183eef3 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -43,12 +43,6 @@ /* Local Definitions and Declarations */ -struct rmnet_walk_data { - struct net_device *real_dev; - struct list_head *head; - struct rmnet_port *port; -}; - static int rmnet_is_real_dev_registered(const struct net_device *real_dev) { return rcu_access_pointer(real_dev->rx_handler) == rmnet_rx_handler; @@ -112,17 +106,14 @@ static int rmnet_register_real_device(struct net_device *real_dev) static void rmnet_unregister_bridge(struct net_device *dev, struct rmnet_port *port) { - struct net_device *rmnet_dev, *bridge_dev; struct rmnet_port *bridge_port; + struct net_device *bridge_dev; if (port->rmnet_mode != RMNET_EPMODE_BRIDGE) return; /* bridge slave handling */ if (!port->nr_rmnet_devs) { - rmnet_dev = netdev_master_upper_dev_get_rcu(dev); - netdev_upper_dev_unlink(dev, rmnet_dev); - bridge_dev = port->bridge_ep; bridge_port = rmnet_get_port_rtnl(bridge_dev); @@ -132,9 +123,6 @@ static void rmnet_unregister_bridge(struct net_device *dev, bridge_dev = port->bridge_ep; bridge_port = rmnet_get_port_rtnl(bridge_dev); - rmnet_dev = netdev_master_upper_dev_get_rcu(bridge_dev); - netdev_upper_dev_unlink(bridge_dev, rmnet_dev); - rmnet_unregister_real_device(bridge_dev, bridge_port); } } @@ -173,10 +161,6 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev, if (err) goto err1; - err = netdev_master_upper_dev_link(dev, real_dev, NULL, NULL, extack); - if (err) - goto err2; - port->rmnet_mode = mode; hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]); @@ -193,8 +177,6 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev, return 0; -err2: - rmnet_vnd_dellink(mux_id, port, ep); err1: rmnet_unregister_real_device(real_dev, port); err0: @@ -204,14 +186,13 @@ err0: static void rmnet_dellink(struct net_device *dev, struct list_head *head) { + struct rmnet_priv *priv = netdev_priv(dev); struct net_device *real_dev; struct rmnet_endpoint *ep; struct rmnet_port *port; u8 mux_id; - rcu_read_lock(); - real_dev = netdev_master_upper_dev_get_rcu(dev); - rcu_read_unlock(); + real_dev = priv->real_dev; if (!real_dev || !rmnet_is_real_dev_registered(real_dev)) return; @@ -219,7 +200,6 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head) port = rmnet_get_port_rtnl(real_dev); mux_id = rmnet_vnd_get_mux(dev); - netdev_upper_dev_unlink(dev, real_dev); ep = rmnet_get_endpoint(port, mux_id); if (ep) { @@ -233,30 +213,13 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head) unregister_netdevice_queue(dev, head); } -static int rmnet_dev_walk_unreg(struct net_device *rmnet_dev, void *data) -{ - struct rmnet_walk_data *d = data; - struct rmnet_endpoint *ep; - u8 mux_id; - - mux_id = rmnet_vnd_get_mux(rmnet_dev); - ep = rmnet_get_endpoint(d->port, mux_id); - if (ep) { - hlist_del_init_rcu(&ep->hlnode); - rmnet_vnd_dellink(mux_id, d->port, ep); - kfree(ep); - } - netdev_upper_dev_unlink(rmnet_dev, d->real_dev); - unregister_netdevice_queue(rmnet_dev, d->head); - - return 0; -} - static void rmnet_force_unassociate_device(struct net_device *dev) { struct net_device *real_dev = dev; - struct rmnet_walk_data d; + struct hlist_node *tmp_ep; + struct rmnet_endpoint *ep; struct rmnet_port *port; + unsigned long bkt_ep; LIST_HEAD(list); if (!rmnet_is_real_dev_registered(real_dev)) @@ -264,16 +227,19 @@ static void rmnet_force_unassociate_device(struct net_device *dev) ASSERT_RTNL(); - d.real_dev = real_dev; - d.head = &list; - port = rmnet_get_port_rtnl(dev); - d.port = port; rcu_read_lock(); rmnet_unregister_bridge(dev, port); - netdev_walk_all_lower_dev_rcu(real_dev, rmnet_dev_walk_unreg, &d); + hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) { + unregister_netdevice_queue(ep->egress_dev, &list); + rmnet_vnd_dellink(ep->mux_id, port, ep); + + hlist_del_init_rcu(&ep->hlnode); + kfree(ep); + } + rcu_read_unlock(); unregister_netdevice_many(&list); @@ -422,11 +388,6 @@ int rmnet_add_bridge(struct net_device *rmnet_dev, if (err) return -EBUSY; - err = netdev_master_upper_dev_link(slave_dev, rmnet_dev, NULL, NULL, - extack); - if (err) - return -EINVAL; - slave_port = rmnet_get_port(slave_dev); slave_port->rmnet_mode = RMNET_EPMODE_BRIDGE; slave_port->bridge_ep = real_dev; @@ -449,7 +410,6 @@ int rmnet_del_bridge(struct net_device *rmnet_dev, port->rmnet_mode = RMNET_EPMODE_VND; port->bridge_ep = NULL; - netdev_upper_dev_unlink(slave_dev, rmnet_dev); slave_port = rmnet_get_port(slave_dev); rmnet_unregister_real_device(slave_dev, slave_port); -- cgit v1.2.3 From 4dba8bbce94541c560940ac65ca9cd563fd43348 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Fri, 16 Feb 2018 15:56:38 -0700 Subject: net: qualcomm: rmnet: Fix warning seen with 64 bit stats With CONFIG_DEBUG_PREEMPT enabled, a warning was seen on device creation. This occurs due to the incorrect cpu API usage in ndo_get_stats64 handler. BUG: using smp_processor_id() in preemptible [00000000] code: rmnetcli/5743 caller is debug_smp_processor_id+0x1c/0x24 Call trace: [] dump_backtrace+0x0/0x2a8 [] show_stack+0x20/0x28 [] dump_stack+0xa8/0xe0 [] check_preemption_disabled+0x104/0x108 [] debug_smp_processor_id+0x1c/0x24 [] rmnet_get_stats64+0x64/0x13c [] dev_get_stats+0x68/0xd8 [] rtnl_fill_stats+0x54/0x140 [] rtnl_fill_ifinfo+0x428/0x9cc [] rtmsg_ifinfo_build_skb+0x80/0xf4 [] rtnetlink_event+0x88/0xb4 [] raw_notifier_call_chain+0x58/0x78 [] call_netdevice_notifiers_info+0x48/0x78 [] __netdev_upper_dev_link+0x290/0x5e8 [] netdev_master_upper_dev_link+0x3c/0x48 [] rmnet_newlink+0xf0/0x1c8 [] rtnl_newlink+0x57c/0x6c8 [] rtnetlink_rcv_msg+0xb0/0x244 [] netlink_rcv_skb+0xb4/0xdc [] rtnetlink_rcv+0x34/0x44 [] netlink_unicast+0x1ec/0x294 [] netlink_sendmsg+0x320/0x390 [] sock_sendmsg+0x54/0x60 [] SyS_sendto+0x1a0/0x1e4 [] el0_svc_naked+0x24/0x28 Fixes: 192c4b5d48f2 ("net: qualcomm: rmnet: Add support for 64 bit stats") Signed-off-by: Subash Abhinov Kasiviswanathan Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index 570a227acdd8..346d310914df 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -121,7 +121,7 @@ static void rmnet_get_stats64(struct net_device *dev, memset(&total_stats, 0, sizeof(struct rmnet_vnd_stats)); for_each_possible_cpu(cpu) { - pcpu_ptr = this_cpu_ptr(priv->pcpu_stats); + pcpu_ptr = per_cpu_ptr(priv->pcpu_stats, cpu); do { start = u64_stats_fetch_begin_irq(&pcpu_ptr->syncp); -- cgit v1.2.3 From f57bbaae7271a47dc6486d489c503faeb248b6d5 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Fri, 16 Feb 2018 15:56:39 -0700 Subject: net: qualcomm: rmnet: Fix possible null dereference in command processing If a command packet with invalid mux id is received, the packet would not have a valid endpoint. This invalid endpoint maybe dereferenced leading to a crash. Identified by manual code inspection. Fixes: 3352e6c45760 ("net: qualcomm: rmnet: Convert the muxed endpoint to hlist") Signed-off-by: Subash Abhinov Kasiviswanathan Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c index 6bc328fb88e1..b0dbca070c00 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c @@ -38,6 +38,11 @@ static u8 rmnet_map_do_flow_control(struct sk_buff *skb, } ep = rmnet_get_endpoint(port, mux_id); + if (!ep) { + kfree_skb(skb); + return RX_HANDLER_CONSUMED; + } + vnd = ep->egress_dev; ip_family = cmd->flow_control.ip_family; -- cgit v1.2.3 From d1c95af366961101819f07e3c64d44f3be7f0367 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sat, 17 Feb 2018 00:30:44 +0100 Subject: mlxsw: spectrum_router: Do not unconditionally clear route offload indication When mlxsw replaces (or deletes) a route it removes the offload indication from the replaced route. This is problematic for IPv4 routes, as the offload indication is stored in the fib_info which is usually shared between multiple routes. Instead of unconditionally clearing the offload indication, only clear it if no other route is using the fib_info. Fixes: 3984d1a89fe7 ("mlxsw: spectrum_router: Provide offload indication using nexthop flags") Signed-off-by: Ido Schimmel Reported-by: Alexander Petrovskiy Tested-by: Alexander Petrovskiy Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index dcc6305f7c22..f7948e983637 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3794,6 +3794,9 @@ mlxsw_sp_fib4_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry) struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group; int i; + if (!list_is_singular(&nh_grp->fib_list)) + return; + for (i = 0; i < nh_grp->count; i++) { struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i]; -- cgit v1.2.3 From 20e6bb17facdc2a078baa12136910bab2c315519 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 15 Jan 2018 17:10:33 +0100 Subject: watchdog: rave-sp: add NVMEM dependency We can build this driver with or without NVMEM, but not built-in when NVMEM is a loadable module: drivers/watchdog/rave-sp-wdt.o: In function `rave_sp_wdt_probe': rave-sp-wdt.c:(.text+0x27c): undefined reference to `nvmem_cell_get' rave-sp-wdt.c:(.text+0x290): undefined reference to `nvmem_cell_read' rave-sp-wdt.c:(.text+0x2c4): undefined reference to `nvmem_cell_put' This adds a Kconfig dependency to enforce that. Fixes: c3bb33345721 ("watchdog: Add RAVE SP watchdog driver") Signed-off-by: Arnd Bergmann Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index aff773bcebdb..a16bad78679b 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -226,6 +226,7 @@ config ZIIRAVE_WATCHDOG config RAVE_SP_WATCHDOG tristate "RAVE SP Watchdog timer" depends on RAVE_SP_CORE + depends on NVMEM || !NVMEM select WATCHDOG_CORE help Support for the watchdog on RAVE SP device. -- cgit v1.2.3 From 7e2e5158e700f2196dff3b68ac07405575e09c22 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Mon, 19 Feb 2018 02:01:05 +0100 Subject: watchdog: i6300esb: fix build failure i6300esb uses fuctions defined in watchdog_core.c, and when CONFIG_WATCHDOG_CORE is not set we have this build error: drivers/watchdog/i6300esb.o: In function `esb_remove': i6300esb.c:(.text+0xcc): undefined reference to `watchdog_unregister_device' drivers/watchdog/i6300esb.o: In function `esb_probe': i6300esb.c:(.text+0x2a1): undefined reference to `watchdog_init_timeout' i6300esb.c:(.text+0x388): undefined reference to `watchdog_register_device' make: *** [Makefile:1029: vmlinux] Error 1 Fix this by selecting CONFIG_WATCHDOG_CORE when I6300ESB_WDT is set. Fixes: 7af4ac8772a8f ("watchdog: i6300esb: use the watchdog subsystem") Signed-off-by: Matteo Croce Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index a16bad78679b..56f9e203049e 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1009,6 +1009,7 @@ config WAFER_WDT config I6300ESB_WDT tristate "Intel 6300ESB Timer/Watchdog" depends on PCI + select WATCHDOG_CORE ---help--- Hardware driver for the watchdog timer built into the Intel 6300ESB controller hub. -- cgit v1.2.3 From 4cd6764495f2b6c2d3dc4fdd339f78764f7995d5 Mon Sep 17 00:00:00 2001 From: Radu Rendec Date: Mon, 19 Feb 2018 14:38:51 +0000 Subject: watchdog: xen_wdt: fix potential build failure xen_wdt uses watchdog core functions (from watchdog_core.c) and, when compiled without CONFIG_WATCHDOG_CORE being set, it produces the following build error: ERROR: "devm_watchdog_register_device" [drivers/watchdog/xen_wdt.ko] undefined! ERROR: "watchdog_init_timeout" [drivers/watchdog/xen_wdt.ko] undefined! Fix this by selecting CONFIG_WATCHDOG_CORE when CONFIG_XEN_WDT is set. Fixes: 18cffd68e0c4 ("watchdog: xen_wdt: use the watchdog subsystem") Signed-off-by: Radu Rendec Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 56f9e203049e..3d984cdea0ca 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1839,6 +1839,7 @@ config WATCHDOG_SUN4V config XEN_WDT tristate "Xen Watchdog support" depends on XEN + select WATCHDOG_CORE help Say Y here to support the hypervisor watchdog capability provided by Xen 4.0 and newer. The watchdog timeout period is normally one -- cgit v1.2.3 From a17f4f032b61abd998a1f81b206a4517e2e3db2f Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Mon, 19 Feb 2018 17:04:33 +0100 Subject: watchdog: sp5100_tco.c: fix potential build failure isp5100_tco.c uses watchdog core functions (from watchdog_core.c) and, when compiled without CONFIG_WATCHDOG_CORE being set, it produces the following build error: ERROR: "devm_watchdog_register_device" [drivers/watchdog/sp5100_tco.ko] undefined! ERROR: "watchdog_init_timeout" [drivers/watchdog/sp5100_tco.ko] undefined! Fix this by selecting CONFIG_WATCHDOG_CORE. Fixes: 7cd9d5fff792 ("watchdog: sp5100_tco: Convert to use watchdog subsystem") Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 3d984cdea0ca..37460cd6cabb 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -904,6 +904,7 @@ config F71808E_WDT config SP5100_TCO tristate "AMD/ATI SP5100 TCO Timer/Watchdog" depends on X86 && PCI + select WATCHDOG_CORE ---help--- Hardware watchdog driver for the AMD/ATI SP5100 chipset. The TCO (Total Cost of Ownership) timer is a watchdog timer that will reboot -- cgit v1.2.3 From 39772f0a7be3b3dc26c74ea13fe7847fd1522c8b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 3 Feb 2018 09:19:30 +1100 Subject: md: only allow remove_and_add_spares when no sync_thread running. The locking protocols in md assume that a device will never be removed from an array during resync/recovery/reshape. When that isn't happening, rcu or reconfig_mutex is needed to protect an rdev pointer while taking a refcount. When it is happening, that protection isn't needed. Unfortunately there are cases were remove_and_add_spares() is called when recovery might be happening: is state_store(), slot_store() and hot_remove_disk(). In each case, this is just an optimization, to try to expedite removal from the personality so the device can be removed from the array. If resync etc is happening, we just have to wait for md_check_recover to find a suitable time to call remove_and_add_spares(). This optimization and not essential so it doesn't matter if it fails. So change remove_and_add_spares() to abort early if resync/recovery/reshape is happening, unless it is called from md_check_recovery() as part of a newly started recovery. The parameter "this" is only NULL when called from md_check_recovery() so when it is NULL, there is no need to abort. As this can result in a NULL dereference, the fix is suitable for -stable. cc: yuyufen Cc: Tomasz Majchrzak Fixes: 8430e7e0af9a ("md: disconnect device from personality before trying to remove it.") Cc: stable@ver.kernel.org (v4.8+) Signed-off-by: NeilBrown Signed-off-by: Shaohua Li --- drivers/md/md.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index 9b73cf139b80..ba152dddaaa3 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8595,6 +8595,10 @@ static int remove_and_add_spares(struct mddev *mddev, int removed = 0; bool remove_some = false; + if (this && test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) + /* Mustn't remove devices when resync thread is running */ + return 0; + rdev_for_each(rdev, mddev) { if ((this == NULL || rdev == this) && rdev->raid_disk >= 0 && -- cgit v1.2.3 From 01a69cab01c184d3786af09e9339311123d63d22 Mon Sep 17 00:00:00 2001 From: Yufen Yu Date: Tue, 6 Feb 2018 17:39:15 +0800 Subject: md raid10: fix NULL deference in handle_write_completed() In the case of 'recover', an r10bio with R10BIO_WriteError & R10BIO_IsRecover will be progressed by handle_write_completed(). This function traverses all r10bio->devs[copies]. If devs[m].repl_bio != NULL, it thinks conf->mirrors[dev].replacement is also not NULL. However, this is not always true. When there is an rdev of raid10 has replacement, then each r10bio ->devs[m].repl_bio != NULL in conf->r10buf_pool. However, in 'recover', even if corresponded replacement is NULL, it doesn't clear r10bio ->devs[m].repl_bio, resulting in replacement NULL deference. This bug was introduced when replacement support for raid10 was added in Linux 3.3. As NeilBrown suggested: Elsewhere the determination of "is this device part of the resync/recovery" is made by resting bio->bi_end_io. If this is end_sync_write, then we tried to write here. If it is NULL, then we didn't try to write. Fixes: 9ad1aefc8ae8 ("md/raid10: Handle replacement devices during resync.") Cc: stable (V3.3+) Suggested-by: NeilBrown Signed-off-by: Yufen Yu Signed-off-by: Shaohua Li --- drivers/md/raid10.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 8d7ddc947d9d..9e9441fde8b3 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -2655,7 +2655,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) for (m = 0; m < conf->copies; m++) { int dev = r10_bio->devs[m].devnum; rdev = conf->mirrors[dev].rdev; - if (r10_bio->devs[m].bio == NULL) + if (r10_bio->devs[m].bio == NULL || + r10_bio->devs[m].bio->bi_end_io == NULL) continue; if (!r10_bio->devs[m].bio->bi_status) { rdev_clear_badblocks( @@ -2670,7 +2671,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) md_error(conf->mddev, rdev); } rdev = conf->mirrors[dev].replacement; - if (r10_bio->devs[m].repl_bio == NULL) + if (r10_bio->devs[m].repl_bio == NULL || + r10_bio->devs[m].repl_bio->bi_end_io == NULL) continue; if (!r10_bio->devs[m].repl_bio->bi_status) { -- cgit v1.2.3 From 506b0a395f26e52b3f18827e0de1be051acb77ab Mon Sep 17 00:00:00 2001 From: Prashant Sreedharan Date: Mon, 19 Feb 2018 12:27:04 +0530 Subject: tg3: APE heartbeat changes In ungraceful host shutdown or driver crash case BMC connectivity is lost. APE firmware is missing the driver state in this case to keep the BMC connectivity alive. This patch has below change to address this issue. Heartbeat mechanism with APE firmware. This heartbeat mechanism is needed to notify the APE firmware about driver state. This patch also has the change in wait time for APE event from 1ms to 20ms as there can be some delay in getting response. v2: Drop inline keyword as per David suggestion. Signed-off-by: Prashant Sreedharan Signed-off-by: Satish Baddipadige Signed-off-by: Siva Reddy Kallam Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 35 ++++++++++++++++++++++++----------- drivers/net/ethernet/broadcom/tg3.h | 5 +++++ 2 files changed, 29 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index a77ee2f8fb8d..c1841db1b500 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -820,7 +820,7 @@ static int tg3_ape_event_lock(struct tg3 *tp, u32 timeout_us) tg3_ape_unlock(tp, TG3_APE_LOCK_MEM); - udelay(10); + usleep_range(10, 20); timeout_us -= (timeout_us > 10) ? 10 : timeout_us; } @@ -922,8 +922,8 @@ static int tg3_ape_send_event(struct tg3 *tp, u32 event) if (!(apedata & APE_FW_STATUS_READY)) return -EAGAIN; - /* Wait for up to 1 millisecond for APE to service previous event. */ - err = tg3_ape_event_lock(tp, 1000); + /* Wait for up to 20 millisecond for APE to service previous event. */ + err = tg3_ape_event_lock(tp, 20000); if (err) return err; @@ -946,6 +946,7 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) switch (kind) { case RESET_KIND_INIT: + tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_COUNT, tp->ape_hb++); tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, APE_HOST_SEG_SIG_MAGIC); tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN, @@ -962,13 +963,6 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) event = APE_EVENT_STATUS_STATE_START; break; case RESET_KIND_SHUTDOWN: - /* With the interface we are currently using, - * APE does not track driver state. Wiping - * out the HOST SEGMENT SIGNATURE forces - * the APE to assume OS absent status. - */ - tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0); - if (device_may_wakeup(&tp->pdev->dev) && tg3_flag(tp, WOL_ENABLE)) { tg3_ape_write32(tp, TG3_APE_HOST_WOL_SPEED, @@ -990,6 +984,18 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) tg3_ape_send_event(tp, event); } +static void tg3_send_ape_heartbeat(struct tg3 *tp, + unsigned long interval) +{ + /* Check if hb interval has exceeded */ + if (!tg3_flag(tp, ENABLE_APE) || + time_before(jiffies, tp->ape_hb_jiffies + interval)) + return; + + tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_COUNT, tp->ape_hb++); + tp->ape_hb_jiffies = jiffies; +} + static void tg3_disable_ints(struct tg3 *tp) { int i; @@ -7262,6 +7268,7 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget) } } + tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL << 1); return work_done; tx_recovery: @@ -7344,6 +7351,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) } } + tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL << 1); return work_done; tx_recovery: @@ -10732,7 +10740,7 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy) if (tg3_flag(tp, ENABLE_APE)) /* Write our heartbeat update interval to APE. */ tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS, - APE_HOST_HEARTBEAT_INT_DISABLE); + APE_HOST_HEARTBEAT_INT_5SEC); tg3_write_sig_post_reset(tp, RESET_KIND_INIT); @@ -11077,6 +11085,9 @@ static void tg3_timer(struct timer_list *t) tp->asf_counter = tp->asf_multiplier; } + /* Update the APE heartbeat every 5 seconds.*/ + tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL); + spin_unlock(&tp->lock); restart_timer: @@ -16653,6 +16664,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) pci_state_reg); tg3_ape_lock_init(tp); + tp->ape_hb_interval = + msecs_to_jiffies(APE_HOST_HEARTBEAT_INT_5SEC); } /* Set up tp->grc_local_ctrl before calling diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index 47f51cc0566d..1d61aa3efda1 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -2508,6 +2508,7 @@ #define TG3_APE_LOCK_PHY3 5 #define TG3_APE_LOCK_GPIO 7 +#define TG3_APE_HB_INTERVAL (tp->ape_hb_interval) #define TG3_EEPROM_SB_F1R2_MBA_OFF 0x10 @@ -3423,6 +3424,10 @@ struct tg3 { struct device *hwmon_dev; bool link_up; bool pcierr_recovery; + + u32 ape_hb; + unsigned long ape_hb_interval; + unsigned long ape_hb_jiffies; }; /* Accessor macros for chip and asic attributes -- cgit v1.2.3 From a588a8bb7b25a3fb4f7fed00feb7aec541fc2632 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 Jan 2018 18:01:21 +0100 Subject: drm/exynos: g2d: use monotonic timestamps The exynos DRM driver uses real-time 'struct timeval' values for exporting its timestamps to user space. This has multiple problems: 1. signed seconds overflow in y2038 2. the 'struct timeval' definition is deprecated in the kernel 3. time may jump or go backwards after a 'settimeofday()' syscall 4. other DRM timestamps are in CLOCK_MONOTONIC domain, so they can't be compared 5. exporting microseconds requires a division by 1000, which may be slow on some architectures. The code existed in two places before, but the IPP portion was removed in 8ded59413ccc ("drm/exynos: ipp: Remove Exynos DRM IPP subsystem"), so we no longer need to worry about it. Ideally timestamps should just use 64-bit nanoseconds instead, but of course we can't change that now. Instead, this tries to address the first four points above by using monotonic 'timespec' values. According to Tobias Jakobi, user space doesn't care about the timestamp at the moment, so we can change the format. Even if there is something looking at them, it will work just fine with monotonic times as long as the application only looks at the relative values between two events. Link: https://patchwork.kernel.org/patch/10038593/ Cc: Tobias Jakobi Signed-off-by: Arnd Bergmann Reviewed-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 2b8bf2dd6387..9effe40f5fa5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -926,7 +926,7 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) struct drm_device *drm_dev = g2d->subdrv.drm_dev; struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node; struct drm_exynos_pending_g2d_event *e; - struct timeval now; + struct timespec64 now; if (list_empty(&runqueue_node->event_list)) return; @@ -934,9 +934,9 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) e = list_first_entry(&runqueue_node->event_list, struct drm_exynos_pending_g2d_event, base.link); - do_gettimeofday(&now); + ktime_get_ts64(&now); e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; + e->event.tv_usec = now.tv_nsec / NSEC_PER_USEC; e->event.cmdlist_no = cmdlist_no; drm_send_event(drm_dev, &e->base); -- cgit v1.2.3 From 1293b6191010672c0c9dacae8f71c6f3e4d70cbe Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 5 Feb 2018 21:09:59 +0100 Subject: drm/exynos: fix comparison to bitshift when dealing with a mask Due to a typo, the mask was destroyed by a comparison instead of a bit shift. Signed-off-by: Wolfram Sang Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/regs-fimc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/exynos/regs-fimc.h b/drivers/gpu/drm/exynos/regs-fimc.h index 30496134a3d0..d7cbe53c4c01 100644 --- a/drivers/gpu/drm/exynos/regs-fimc.h +++ b/drivers/gpu/drm/exynos/regs-fimc.h @@ -569,7 +569,7 @@ #define EXYNOS_CIIMGEFF_FIN_EMBOSSING (4 << 26) #define EXYNOS_CIIMGEFF_FIN_SILHOUETTE (5 << 26) #define EXYNOS_CIIMGEFF_FIN_MASK (7 << 26) -#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff < 13) | (0xff < 0)) +#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff << 13) | (0xff << 0)) /* Real input DMA size register */ #define EXYNOS_CIREAL_ISIZE_AUTOLOAD_ENABLE (1 << 31) -- cgit v1.2.3 From 6f0a60298bbbea43ab5e3955913ab19c153076f3 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 8 Feb 2018 18:42:51 +0100 Subject: drm/exynos: g2d: Delete an error message for a failed memory allocation in two functions Omit an extra message for a memory allocation failure in these functions. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 9effe40f5fa5..f68ef1b3a28c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -286,7 +286,6 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) node = kcalloc(G2D_CMDLIST_NUM, sizeof(*node), GFP_KERNEL); if (!node) { - dev_err(dev, "failed to allocate memory\n"); ret = -ENOMEM; goto err; } @@ -1358,10 +1357,9 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, return -EFAULT; runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL); - if (!runqueue_node) { - dev_err(dev, "failed to allocate memory\n"); + if (!runqueue_node) return -ENOMEM; - } + run_cmdlist = &runqueue_node->run_cmdlist; event_list = &runqueue_node->event_list; INIT_LIST_HEAD(run_cmdlist); -- cgit v1.2.3 From b701a1436a5b177dc2240ba7e8f2ff7106bc8d84 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 15 Feb 2018 08:23:15 +0000 Subject: drm/exynos: remove exynos_drm_rotator.h Since its inclusion in 2012 via commit bea8a429d91a ("drm/exynos: add rotator ipp driver") this header is not used by any source files and is empty. Lets just remove it. Signed-off-by: Corentin Labbe Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_rotator.h | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_rotator.h (limited to 'drivers') diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.h b/drivers/gpu/drm/exynos/exynos_drm_rotator.h deleted file mode 100644 index 71a0b4c0c1e8..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * - * Authors: - * YoungJun Cho - * Eunchul Kim - * - * 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. - */ - -#ifndef _EXYNOS_DRM_ROTATOR_H_ -#define _EXYNOS_DRM_ROTATOR_H_ - -/* TODO */ - -#endif -- cgit v1.2.3 From c84b66f8aa3f879dbf41353f677d87875f5fc6c9 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Feb 2018 18:23:56 +0100 Subject: drm: exynos: Use proper macro definition for HDMI_I2S_PIN_SEL_1 Bit field [2:0] of HDMI_I2S_PIN_SEL_1 corresponds to SDATA_0, not SDATA_2. This patch removes redefinition of HDMI_I2S_SEL_DATA2 constant and adds missing HDMI_I2S_SEL_DATA0. The value of bit field selecting SDATA_1 (pin_sel_3) is also changed, so it is 3 as suggested in the Exynos TRMs. Signed-off-by: Sylwester Nawrocki Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 7 +++++-- drivers/gpu/drm/exynos/regs-hdmi.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index a4b75a46f946..abd84cbcf1c2 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1068,10 +1068,13 @@ static void hdmi_audio_config(struct hdmi_context *hdata) /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */ hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5) | HDMI_I2S_SEL_LRCK(6)); - hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1) - | HDMI_I2S_SEL_SDATA2(4)); + + hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(3) + | HDMI_I2S_SEL_SDATA0(4)); + hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1) | HDMI_I2S_SEL_SDATA2(2)); + hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0)); /* I2S_CON_1 & 2 */ diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h index 04be0f7e8193..4420c203ac85 100644 --- a/drivers/gpu/drm/exynos/regs-hdmi.h +++ b/drivers/gpu/drm/exynos/regs-hdmi.h @@ -464,7 +464,7 @@ /* I2S_PIN_SEL_1 */ #define HDMI_I2S_SEL_SDATA1(x) (((x) & 0x7) << 4) -#define HDMI_I2S_SEL_SDATA2(x) ((x) & 0x7) +#define HDMI_I2S_SEL_SDATA0(x) ((x) & 0x7) /* I2S_PIN_SEL_2 */ #define HDMI_I2S_SEL_SDATA3(x) (((x) & 0x7) << 4) -- cgit v1.2.3 From f8f4aa68a8ae98ed79c8fee3488c38a2f5d2de8c Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 18 Feb 2018 11:05:15 +0200 Subject: mei: me: add cannon point device ids Add CNP LP and CNP H device ids for cannon lake and coffee lake platforms. Cc: 4.14+ Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 3 +++ drivers/misc/mei/pci-me.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 0ccccbaf530d..bda3bd8f3141 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -132,6 +132,9 @@ #define MEI_DEV_ID_KBP 0xA2BA /* Kaby Point */ #define MEI_DEV_ID_KBP_2 0xA2BB /* Kaby Point 2 */ +#define MEI_DEV_ID_CNP_LP 0x9DE0 /* Cannon Point LP */ +#define MEI_DEV_ID_CNP_H 0xA360 /* Cannon Point H */ + /* * MEI HW Section */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 4a0ccda4d04b..f915000e5bf9 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -98,6 +98,9 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_KBP, MEI_ME_PCH8_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_KBP_2, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_LP, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_H, MEI_ME_PCH8_CFG)}, + /* required last entry */ {0, } }; -- cgit v1.2.3 From 2a4ac172c2f257d28c47b90c9e381bec31edcc44 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 18 Feb 2018 11:05:16 +0200 Subject: mei: me: add cannon point device ids for 4th device Add cannon point device ids for 4th (itouch) device. Cc: 4.14+ Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 2 ++ drivers/misc/mei/pci-me.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index bda3bd8f3141..e4b10b2d1a08 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -133,7 +133,9 @@ #define MEI_DEV_ID_KBP_2 0xA2BB /* Kaby Point 2 */ #define MEI_DEV_ID_CNP_LP 0x9DE0 /* Cannon Point LP */ +#define MEI_DEV_ID_CNP_LP_4 0x9DE4 /* Cannon Point LP 4 (iTouch) */ #define MEI_DEV_ID_CNP_H 0xA360 /* Cannon Point H */ +#define MEI_DEV_ID_CNP_H_4 0xA364 /* Cannon Point H 4 (iTouch) */ /* * MEI HW Section diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index f915000e5bf9..ea4e152270a3 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -99,7 +99,9 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_KBP_2, MEI_ME_PCH8_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_LP, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_LP_4, MEI_ME_PCH8_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_H, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_H_4, MEI_ME_PCH8_CFG)}, /* required last entry */ {0, } -- cgit v1.2.3 From b8ff1802815913aad52695898cccbc9f77b7e726 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 19 Feb 2018 11:35:43 +0000 Subject: drm: Handle unexpected holes in color-eviction During eviction, the driver may free more than one hole in the drm_mm due to the side-effects in evicting the scanned nodes. However, drm_mm_scan_color_evict() expects that the scan result is the first available hole (in the mru freed hole_stack list): kernel BUG at drivers/gpu/drm/drm_mm.c:844! invalid opcode: 0000 [#1] PREEMPT SMP KASAN PTI Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: i915 snd_hda_codec_analog snd_hda_codec_generic coretemp snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core lpc_ich snd_pcm e1000e mei_me prime_numbers mei CPU: 1 PID: 1490 Comm: gem_userptr_bli Tainted: G U 4.16.0-rc1-g740f57c54ecf-kasan_6+ #1 Hardware name: Dell Inc. OptiPlex 755 /0PU052, BIOS A08 02/19/2008 RIP: 0010:drm_mm_scan_color_evict+0x2b8/0x3d0 RSP: 0018:ffff880057a573f8 EFLAGS: 00010287 RAX: ffff8800611f5980 RBX: ffff880057a575d0 RCX: dffffc0000000000 RDX: 00000000029d5000 RSI: 1ffff1000af4aec1 RDI: ffff8800611f5a10 RBP: ffff88005ab884d0 R08: ffff880057a57600 R09: 000000000afff000 R10: 1ffff1000b5710b5 R11: 0000000000001000 R12: 1ffff1000af4ae82 R13: ffff8800611f59b0 R14: ffff8800611f5980 R15: ffff880057a57608 FS: 00007f2de0c2e8c0(0000) GS:ffff88006ac40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f2ddde1e000 CR3: 00000000609b2000 CR4: 00000000000006e0 Call Trace: ? drm_mm_scan_remove_block+0x330/0x330 ? drm_mm_scan_remove_block+0x151/0x330 i915_gem_evict_something+0x711/0xbd0 [i915] ? igt_evict_contexts+0x50/0x50 [i915] ? nop_clear_range+0x10/0x10 [i915] ? igt_evict_something+0x90/0x90 [i915] ? i915_gem_gtt_reserve+0x1a1/0x320 [i915] i915_gem_gtt_insert+0x237/0x400 [i915] __i915_vma_do_pin+0xc25/0x1a20 [i915] eb_lookup_vmas+0x1c63/0x3790 [i915] ? i915_gem_check_execbuffer+0x250/0x250 [i915] ? trace_hardirqs_on_caller+0x33f/0x590 ? _raw_spin_unlock_irqrestore+0x39/0x60 ? __pm_runtime_resume+0x7d/0xf0 i915_gem_do_execbuffer+0x86a/0x2ff0 [i915] ? __kmalloc+0x132/0x340 ? i915_gem_execbuffer2_ioctl+0x10f/0x760 [i915] ? drm_ioctl_kernel+0x12e/0x1c0 ? drm_ioctl+0x662/0x980 ? eb_relocate_slow+0xa90/0xa90 [i915] ? i915_gem_execbuffer2_ioctl+0x10f/0x760 [i915] ? __might_fault+0xea/0x1a0 i915_gem_execbuffer2_ioctl+0x3cc/0x760 [i915] ? i915_gem_execbuffer_ioctl+0xba0/0xba0 [i915] ? lock_acquire+0x3c0/0x3c0 ? i915_gem_execbuffer_ioctl+0xba0/0xba0 [i915] drm_ioctl_kernel+0x12e/0x1c0 drm_ioctl+0x662/0x980 ? i915_gem_execbuffer_ioctl+0xba0/0xba0 [i915] ? drm_getstats+0x20/0x20 ? debug_check_no_obj_freed+0x2a6/0x8c0 do_vfs_ioctl+0x170/0xe70 ? ioctl_preallocate+0x170/0x170 ? task_work_run+0xbe/0x160 ? lock_acquire+0x3c0/0x3c0 ? trace_hardirqs_on_caller+0x33f/0x590 ? _raw_spin_unlock_irq+0x2f/0x50 SyS_ioctl+0x36/0x70 ? do_vfs_ioctl+0xe70/0xe70 do_syscall_64+0x18c/0x5d0 entry_SYSCALL_64_after_hwframe+0x26/0x9b RIP: 0033:0x7f2ddf13b587 RSP: 002b:00007fff15c4f9d8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007f2ddf13b587 RDX: 00007fff15c4fa20 RSI: 0000000040406469 RDI: 0000000000000003 RBP: 00007fff15c4fa20 R08: 0000000000000000 R09: 00007f2ddf3fe120 R10: 0000000000000073 R11: 0000000000000246 R12: 0000000040406469 R13: 0000000000000003 R14: 00007fff15c4fa20 R15: 00000000000000c7 Code: 00 00 00 4a c7 44 22 08 00 00 00 00 42 c7 44 22 10 00 00 00 00 48 81 c4 b8 00 00 00 5b 5d 41 5c 41 5d 41 5e 41 5f c3 0f 0b 0f 0b <0f> 0b 31 c0 eb c0 4c 89 ef e8 9a 09 41 ff e9 1e fe ff ff 4c 89 RIP: drm_mm_scan_color_evict+0x2b8/0x3d0 RSP: ffff880057a573f8 We can trivially relax this assumption by searching the hole_stack for the scan result and warn instead if the driver called us without any result. Fixes: 3fa489dabea9 ("drm: Apply tight eviction scanning to color_adjust") Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: # v4.11+ Reviewed-by: Joonas Lahtinen Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180219113543.8010-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index c3c79ee6119e..edab571dbc90 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -836,9 +836,24 @@ struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan) if (!mm->color_adjust) return NULL; - hole = list_first_entry(&mm->hole_stack, typeof(*hole), hole_stack); - hole_start = __drm_mm_hole_node_start(hole); - hole_end = hole_start + hole->hole_size; + /* + * The hole found during scanning should ideally be the first element + * in the hole_stack list, but due to side-effects in the driver it + * may not be. + */ + list_for_each_entry(hole, &mm->hole_stack, hole_stack) { + hole_start = __drm_mm_hole_node_start(hole); + hole_end = hole_start + hole->hole_size; + + if (hole_start <= scan->hit_start && + hole_end >= scan->hit_end) + break; + } + + /* We should only be called after we found the hole previously */ + DRM_MM_BUG_ON(&hole->hole_stack == &mm->hole_stack); + if (unlikely(&hole->hole_stack == &mm->hole_stack)) + return NULL; DRM_MM_BUG_ON(hole_start > scan->hit_start); DRM_MM_BUG_ON(hole_end < scan->hit_end); -- cgit v1.2.3 From e88230a3744a71a0b5ecfb45e08ddfe1c884e50d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 15 Feb 2018 11:19:36 +0100 Subject: drm/meson: fix vsync buffer update The plane buffer address/stride/height was incorrectly updated in the plane_atomic_update operation instead of the vsync irq. This patch delays this operation in the vsync irq along with the other plane delayed setup. This issue was masked using legacy framebuffer and X11 modesetting, but is clearly visible using gbm rendering when buffer is submitted late after vblank, like using software decoding and OpenGL rendering in Kodi. With this patch, tearing and other artifacts disappears completely. Cc: Michal Lazo Fixes: bbbe775ec5b5 ("drm: Add support for Amlogic Meson Graphic Controller") Signed-off-by: Neil Armstrong Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/1518689976-23292-1-git-send-email-narmstrong@baylibre.com --- drivers/gpu/drm/meson/meson_crtc.c | 6 ++++++ drivers/gpu/drm/meson/meson_drv.h | 3 +++ drivers/gpu/drm/meson/meson_plane.c | 7 +++---- 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 5155f0179b61..05520202c967 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c @@ -36,6 +36,7 @@ #include "meson_venc.h" #include "meson_vpp.h" #include "meson_viu.h" +#include "meson_canvas.h" #include "meson_registers.h" /* CRTC definition */ @@ -192,6 +193,11 @@ void meson_crtc_irq(struct meson_drm *priv) } else meson_vpp_disable_interlace_vscaler_osd1(priv); + meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, + priv->viu.osd1_addr, priv->viu.osd1_stride, + priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR); + /* Enable OSD1 */ writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, priv->io_base + _REG(VPP_MISC)); diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index 5e8b392b9d1f..8450d6ac8c9b 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -43,6 +43,9 @@ struct meson_drm { bool osd1_commit; uint32_t osd1_ctrl_stat; uint32_t osd1_blk0_cfg[5]; + uint32_t osd1_addr; + uint32_t osd1_stride; + uint32_t osd1_height; } viu; struct { diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 17e96fa47868..0b6011b8d632 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -164,10 +164,9 @@ static void meson_plane_atomic_update(struct drm_plane *plane, /* Update Canvas with buffer address */ gem = drm_fb_cma_get_gem_obj(fb, 0); - meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, - gem->paddr, fb->pitches[0], - fb->height, MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR); + priv->viu.osd1_addr = gem->paddr; + priv->viu.osd1_stride = fb->pitches[0]; + priv->viu.osd1_height = fb->height; spin_unlock_irqrestore(&priv->drm->event_lock, flags); } -- cgit v1.2.3 From c0248c96631f38f02d58762fc018e316843acac8 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 5 Feb 2018 16:41:56 +0000 Subject: arm_pmu: kill arm_pmu_platdata Now that we have no platforms passing platform data to the arm_pmu code, we can get rid of the platdata and associated hooks, paving the way for rework of our IRQ handling. Signed-off-by: Mark Rutland Cc: Will Deacon Signed-off-by: Will Deacon --- drivers/perf/arm_pmu.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 7bc5eee96b31..82b09d1cb42c 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -320,17 +319,9 @@ validate_group(struct perf_event *event) return 0; } -static struct arm_pmu_platdata *armpmu_get_platdata(struct arm_pmu *armpmu) -{ - struct platform_device *pdev = armpmu->plat_device; - - return pdev ? dev_get_platdata(&pdev->dev) : NULL; -} - static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) { struct arm_pmu *armpmu; - struct arm_pmu_platdata *plat; int ret; u64 start_clock, finish_clock; @@ -342,13 +333,8 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) */ armpmu = *(void **)dev; - plat = armpmu_get_platdata(armpmu); - start_clock = sched_clock(); - if (plat && plat->handle_irq) - ret = plat->handle_irq(irq, armpmu, armpmu->handle_irq); - else - ret = armpmu->handle_irq(irq, armpmu); + ret = armpmu->handle_irq(irq, armpmu); finish_clock = sched_clock(); perf_sample_event_took(finish_clock - start_clock); @@ -578,7 +564,6 @@ int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) goto err_out; } } else { - struct arm_pmu_platdata *platdata = armpmu_get_platdata(armpmu); unsigned long irq_flags; err = irq_force_affinity(irq, cpumask_of(cpu)); @@ -589,13 +574,9 @@ int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) goto err_out; } - if (platdata && platdata->irq_flags) { - irq_flags = platdata->irq_flags; - } else { - irq_flags = IRQF_PERCPU | - IRQF_NOBALANCING | - IRQF_NO_THREAD; - } + irq_flags = IRQF_PERCPU | + IRQF_NOBALANCING | + IRQF_NO_THREAD; err = request_irq(irq, handler, irq_flags, "arm-pmu", per_cpu_ptr(&hw_events->percpu_pmu, cpu)); -- cgit v1.2.3 From d3d5aac206b4e9e569a22fe1811c909dde17587c Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 5 Feb 2018 16:41:57 +0000 Subject: arm_pmu: fold platform helpers into platform code The armpmu_{request,free}_irqs() helpers are only used by arm_pmu_platform.c, so let's fold them in and make them static. Signed-off-by: Mark Rutland Cc: Will Deacon Signed-off-by: Will Deacon --- drivers/perf/arm_pmu.c | 21 --------------------- drivers/perf/arm_pmu_platform.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 82b09d1cb42c..373dfd7d8a1d 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -534,14 +534,6 @@ void armpmu_free_irq(struct arm_pmu *armpmu, int cpu) free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu)); } -void armpmu_free_irqs(struct arm_pmu *armpmu) -{ - int cpu; - - for_each_cpu(cpu, &armpmu->supported_cpus) - armpmu_free_irq(armpmu, cpu); -} - int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) { int err = 0; @@ -593,19 +585,6 @@ err_out: return err; } -int armpmu_request_irqs(struct arm_pmu *armpmu) -{ - int cpu, err; - - for_each_cpu(cpu, &armpmu->supported_cpus) { - err = armpmu_request_irq(armpmu, cpu); - if (err) - break; - } - - return err; -} - static int armpmu_get_cpu_irq(struct arm_pmu *pmu, int cpu) { struct pmu_hw_events __percpu *hw_events = pmu->hw_events; diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c index 46501cc79fd7..244558cfdbce 100644 --- a/drivers/perf/arm_pmu_platform.c +++ b/drivers/perf/arm_pmu_platform.c @@ -164,6 +164,27 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) return 0; } +static int armpmu_request_irqs(struct arm_pmu *armpmu) +{ + int cpu, err; + + for_each_cpu(cpu, &armpmu->supported_cpus) { + err = armpmu_request_irq(armpmu, cpu); + if (err) + break; + } + + return err; +} + +static void armpmu_free_irqs(struct arm_pmu *armpmu) +{ + int cpu; + + for_each_cpu(cpu, &armpmu->supported_cpus) + armpmu_free_irq(armpmu, cpu); +} + int arm_pmu_device_probe(struct platform_device *pdev, const struct of_device_id *of_table, const struct pmu_probe_info *probe_table) -- cgit v1.2.3 From 0dc1a1851af1d593eee248b94c1277c7c7ccbbce Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 5 Feb 2018 16:41:58 +0000 Subject: arm_pmu: add armpmu_alloc_atomic() In ACPI systems, we don't know the makeup of CPUs until we hotplug them on, and thus have to allocate the PMU datastructures at hotplug time. Thus, we must use GFP_ATOMIC allocations. Let's add an armpmu_alloc_atomic() that we can use in this case. Signed-off-by: Mark Rutland Cc: Will Deacon Signed-off-by: Will Deacon --- drivers/perf/arm_pmu.c | 17 ++++++++++++++--- drivers/perf/arm_pmu_acpi.c | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 373dfd7d8a1d..4f73c5e8d623 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -760,18 +760,18 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu) &cpu_pmu->node); } -struct arm_pmu *armpmu_alloc(void) +static struct arm_pmu *__armpmu_alloc(gfp_t flags) { struct arm_pmu *pmu; int cpu; - pmu = kzalloc(sizeof(*pmu), GFP_KERNEL); + pmu = kzalloc(sizeof(*pmu), flags); if (!pmu) { pr_info("failed to allocate PMU device!\n"); goto out; } - pmu->hw_events = alloc_percpu(struct pmu_hw_events); + pmu->hw_events = alloc_percpu_gfp(struct pmu_hw_events, flags); if (!pmu->hw_events) { pr_info("failed to allocate per-cpu PMU data.\n"); goto out_free_pmu; @@ -817,6 +817,17 @@ out: return NULL; } +struct arm_pmu *armpmu_alloc(void) +{ + return __armpmu_alloc(GFP_KERNEL); +} + +struct arm_pmu *armpmu_alloc_atomic(void) +{ + return __armpmu_alloc(GFP_ATOMIC); +} + + void armpmu_free(struct arm_pmu *pmu) { free_percpu(pmu->hw_events); diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c index 705f1a390e31..30c5f2bbce59 100644 --- a/drivers/perf/arm_pmu_acpi.c +++ b/drivers/perf/arm_pmu_acpi.c @@ -127,7 +127,7 @@ static struct arm_pmu *arm_pmu_acpi_find_alloc_pmu(void) return pmu; } - pmu = armpmu_alloc(); + pmu = armpmu_alloc_atomic(); if (!pmu) { pr_warn("Unable to allocate PMU for CPU%d\n", smp_processor_id()); -- cgit v1.2.3 From 43fc9a2febbd96dd39588d67ace456b7bbc73d9f Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 5 Feb 2018 16:41:59 +0000 Subject: arm_pmu: acpi: check for mismatched PPIs The arm_pmu platform code explicitly checks for mismatched PPIs at probe time, while the ACPI code leaves this to the core code. Future refactoring will make this difficult for the core code to check, so let's have the ACPI code check this explicitly. As before, upon a failure we'll continue on without an interrupt. Ho hum. Signed-off-by: Mark Rutland Cc: Will Deacon Signed-off-by: Will Deacon --- drivers/perf/arm_pmu.c | 17 ++++------------- drivers/perf/arm_pmu_acpi.c | 42 +++++++++++++++++++++++++++++++++++++---- drivers/perf/arm_pmu_platform.c | 7 ------- 3 files changed, 42 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 4f73c5e8d623..ddcabd6a5d52 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -543,19 +543,7 @@ int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) if (!irq) return 0; - if (irq_is_percpu_devid(irq) && cpumask_empty(&armpmu->active_irqs)) { - err = request_percpu_irq(irq, handler, "arm-pmu", - &hw_events->percpu_pmu); - } else if (irq_is_percpu_devid(irq)) { - int other_cpu = cpumask_first(&armpmu->active_irqs); - int other_irq = per_cpu(hw_events->irq, other_cpu); - - if (irq != other_irq) { - pr_warn("mismatched PPIs detected.\n"); - err = -EINVAL; - goto err_out; - } - } else { + if (!irq_is_percpu_devid(irq)) { unsigned long irq_flags; err = irq_force_affinity(irq, cpumask_of(cpu)); @@ -572,6 +560,9 @@ int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) err = request_irq(irq, handler, irq_flags, "arm-pmu", per_cpu_ptr(&hw_events->percpu_pmu, cpu)); + } else if (cpumask_empty(&armpmu->active_irqs)) { + err = request_percpu_irq(irq, handler, "arm-pmu", + &hw_events->percpu_pmu); } if (err) diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c index 30c5f2bbce59..09a1a36cff57 100644 --- a/drivers/perf/arm_pmu_acpi.c +++ b/drivers/perf/arm_pmu_acpi.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -139,6 +141,35 @@ static struct arm_pmu *arm_pmu_acpi_find_alloc_pmu(void) return pmu; } +/* + * Check whether the new IRQ is compatible with those already associated with + * the PMU (e.g. we don't have mismatched PPIs). + */ +static bool pmu_irq_matches(struct arm_pmu *pmu, int irq) +{ + struct pmu_hw_events __percpu *hw_events = pmu->hw_events; + int cpu; + + if (!irq) + return true; + + for_each_cpu(cpu, &pmu->supported_cpus) { + int other_irq = per_cpu(hw_events->irq, cpu); + if (!other_irq) + continue; + + if (irq == other_irq) + continue; + if (!irq_is_percpu_devid(irq) && !irq_is_percpu_devid(other_irq)) + continue; + + pr_warn("mismatched PPIs detected\n"); + return false; + } + + return true; +} + /* * This must run before the common arm_pmu hotplug logic, so that we can * associate a CPU and its interrupt before the common code tries to manage the @@ -164,18 +195,21 @@ static int arm_pmu_acpi_cpu_starting(unsigned int cpu) if (!pmu) return -ENOMEM; - cpumask_set_cpu(cpu, &pmu->supported_cpus); - per_cpu(probed_pmus, cpu) = pmu; + if (pmu_irq_matches(pmu, irq)) { + hw_events = pmu->hw_events; + per_cpu(hw_events->irq, cpu) = irq; + } + + cpumask_set_cpu(cpu, &pmu->supported_cpus); + /* * Log and request the IRQ so the core arm_pmu code can manage it. In * some situations (e.g. mismatched PPIs), we may fail to request the * IRQ. However, it may be too late for us to do anything about it. * The common ARM PMU code will log a warning in this case. */ - hw_events = pmu->hw_events; - per_cpu(hw_events->irq, cpu) = irq; armpmu_request_irq(pmu, cpu); /* diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c index 244558cfdbce..1dc3c1f574e0 100644 --- a/drivers/perf/arm_pmu_platform.c +++ b/drivers/perf/arm_pmu_platform.c @@ -127,13 +127,6 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) pdev->dev.of_node); } - /* - * Some platforms have all PMU IRQs OR'd into a single IRQ, with a - * special platdata function that attempts to demux them. - */ - if (dev_get_platdata(&pdev->dev)) - cpumask_setall(&pmu->supported_cpus); - for (i = 0; i < num_irqs; i++) { int cpu, irq; -- cgit v1.2.3 From 6de3f79112cc26bf24edbb240248d21e1dd85dde Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 5 Feb 2018 16:42:00 +0000 Subject: arm_pmu: explicitly enable/disable SPIs at hotplug To support ACPI systems, we need to request IRQs before CPUs are hotplugged, and thus we need to request IRQs before we know their associated PMU. This is problematic if a PMU IRQ is pending out of reset, as it may be taken before we know the PMU, and thus the IRQ handler won't be able to handle it, leaving it screaming. To avoid such problems, lets request all IRQs in a disabled state, and explicitly enable/disable them at hotplug time, when we're sure the PMU has been probed. Signed-off-by: Mark Rutland Cc: Will Deacon Signed-off-by: Will Deacon --- drivers/perf/arm_pmu.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index ddcabd6a5d52..72118e6f9122 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -558,6 +558,7 @@ int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) IRQF_NOBALANCING | IRQF_NO_THREAD; + irq_set_status_flags(irq, IRQ_NOAUTOEN); err = request_irq(irq, handler, irq_flags, "arm-pmu", per_cpu_ptr(&hw_events->percpu_pmu, cpu)); } else if (cpumask_empty(&armpmu->active_irqs)) { @@ -600,10 +601,10 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node) irq = armpmu_get_cpu_irq(pmu, cpu); if (irq) { - if (irq_is_percpu_devid(irq)) { + if (irq_is_percpu_devid(irq)) enable_percpu_irq(irq, IRQ_TYPE_NONE); - return 0; - } + else + enable_irq(irq); } return 0; @@ -618,8 +619,12 @@ static int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node) return 0; irq = armpmu_get_cpu_irq(pmu, cpu); - if (irq && irq_is_percpu_devid(irq)) - disable_percpu_irq(irq); + if (irq) { + if (irq_is_percpu_devid(irq)) + disable_percpu_irq(irq); + else + disable_irq(irq); + } return 0; } -- cgit v1.2.3 From 84b4be57ae17f8c0b3c1d8629e10f23910838fd7 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 12 Dec 2017 16:56:06 +0000 Subject: arm_pmu: note IRQs and PMUs per-cpu To support ACPI systems, we need to request IRQs before we know the associated PMU, and thus we need some percpu variable that the IRQ handler can find the PMU from. As we're going to request IRQs without the PMU, we can't rely on the arm_pmu::active_irqs mask, and similarly need to track requested IRQs with a percpu variable. Signed-off-by: Mark Rutland [will: made armpmu_count_irq_users static] Signed-off-by: Will Deacon --- drivers/perf/arm_pmu.c | 69 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 72118e6f9122..2b2af35db1b6 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -25,6 +25,9 @@ #include +static DEFINE_PER_CPU(struct arm_pmu *, cpu_armpmu); +static DEFINE_PER_CPU(int, cpu_irq); + static int armpmu_map_cache_event(const unsigned (*cache_map) [PERF_COUNT_HW_CACHE_MAX] @@ -332,6 +335,8 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) * dereference. */ armpmu = *(void **)dev; + if (WARN_ON_ONCE(!armpmu)) + return IRQ_NONE; start_clock = sched_clock(); ret = armpmu->handle_irq(irq, armpmu); @@ -517,29 +522,45 @@ int perf_num_counters(void) } EXPORT_SYMBOL_GPL(perf_num_counters); -void armpmu_free_irq(struct arm_pmu *armpmu, int cpu) +static int armpmu_count_irq_users(const int irq) { - struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; - int irq = per_cpu(hw_events->irq, cpu); + int cpu, count = 0; - if (!cpumask_test_and_clear_cpu(cpu, &armpmu->active_irqs)) - return; + for_each_possible_cpu(cpu) { + if (per_cpu(cpu_irq, cpu) == irq) + count++; + } + + return count; +} - if (irq_is_percpu_devid(irq)) { - free_percpu_irq(irq, &hw_events->percpu_pmu); - cpumask_clear(&armpmu->active_irqs); +void armpmu_free_cpu_irq(int irq, int cpu) +{ + if (per_cpu(cpu_irq, cpu) == 0) return; - } + if (WARN_ON(irq != per_cpu(cpu_irq, cpu))) + return; + + if (!irq_is_percpu_devid(irq)) + free_irq(irq, per_cpu_ptr(&cpu_armpmu, cpu)); + else if (armpmu_count_irq_users(irq) == 1) + free_percpu_irq(irq, &cpu_armpmu); - free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu)); + per_cpu(cpu_irq, cpu) = 0; } -int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) +void armpmu_free_irq(struct arm_pmu *armpmu, int cpu) { - int err = 0; struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; - const irq_handler_t handler = armpmu_dispatch_irq; int irq = per_cpu(hw_events->irq, cpu); + + armpmu_free_cpu_irq(irq, cpu); +} + +int armpmu_request_cpu_irq(int irq, int cpu) +{ + int err = 0; + const irq_handler_t handler = armpmu_dispatch_irq; if (!irq) return 0; @@ -560,16 +581,16 @@ int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) irq_set_status_flags(irq, IRQ_NOAUTOEN); err = request_irq(irq, handler, irq_flags, "arm-pmu", - per_cpu_ptr(&hw_events->percpu_pmu, cpu)); - } else if (cpumask_empty(&armpmu->active_irqs)) { + per_cpu_ptr(&cpu_armpmu, cpu)); + } else if (armpmu_count_irq_users(irq) == 0) { err = request_percpu_irq(irq, handler, "arm-pmu", - &hw_events->percpu_pmu); + &cpu_armpmu); } if (err) goto err_out; - cpumask_set_cpu(cpu, &armpmu->active_irqs); + per_cpu(cpu_irq, cpu) = irq; return 0; err_out: @@ -577,6 +598,16 @@ err_out: return err; } +int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) +{ + struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; + int irq = per_cpu(hw_events->irq, cpu); + if (!irq) + return 0; + + return armpmu_request_cpu_irq(irq, cpu); +} + static int armpmu_get_cpu_irq(struct arm_pmu *pmu, int cpu) { struct pmu_hw_events __percpu *hw_events = pmu->hw_events; @@ -599,6 +630,8 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node) if (pmu->reset) pmu->reset(pmu); + per_cpu(cpu_armpmu, cpu) = pmu; + irq = armpmu_get_cpu_irq(pmu, cpu); if (irq) { if (irq_is_percpu_devid(irq)) @@ -626,6 +659,8 @@ static int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node) disable_irq(irq); } + per_cpu(cpu_armpmu, cpu) = NULL; + return 0; } -- cgit v1.2.3 From 167e61438da0664cab87c825a6c0cb83510d578e Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 9 Oct 2017 17:09:05 +0100 Subject: arm_pmu: acpi: request IRQs up-front We can't request IRQs in atomic context, so for ACPI systems we'll have to request them up-front, and later associate them with CPUs. This patch reorganises the arm_pmu code to do so. As we no longer have the arm_pmu structure at probe time, a number of prototypes need to be adjusted, requiring changes to the common arm_pmu code and arm_pmu platform code. Signed-off-by: Mark Rutland Cc: Will Deacon Signed-off-by: Will Deacon --- drivers/perf/arm_pmu.c | 22 ++-------------------- drivers/perf/arm_pmu_acpi.c | 19 ++++++------------- drivers/perf/arm_pmu_platform.c | 15 ++++++++++++--- 3 files changed, 20 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 2b2af35db1b6..0c2ed11c0603 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -534,7 +534,7 @@ static int armpmu_count_irq_users(const int irq) return count; } -void armpmu_free_cpu_irq(int irq, int cpu) +void armpmu_free_irq(int irq, int cpu) { if (per_cpu(cpu_irq, cpu) == 0) return; @@ -549,15 +549,7 @@ void armpmu_free_cpu_irq(int irq, int cpu) per_cpu(cpu_irq, cpu) = 0; } -void armpmu_free_irq(struct arm_pmu *armpmu, int cpu) -{ - struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; - int irq = per_cpu(hw_events->irq, cpu); - - armpmu_free_cpu_irq(irq, cpu); -} - -int armpmu_request_cpu_irq(int irq, int cpu) +int armpmu_request_irq(int irq, int cpu) { int err = 0; const irq_handler_t handler = armpmu_dispatch_irq; @@ -598,16 +590,6 @@ err_out: return err; } -int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) -{ - struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; - int irq = per_cpu(hw_events->irq, cpu); - if (!irq) - return 0; - - return armpmu_request_cpu_irq(irq, cpu); -} - static int armpmu_get_cpu_irq(struct arm_pmu *pmu, int cpu) { struct pmu_hw_events __percpu *hw_events = pmu->hw_events; diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c index 09a1a36cff57..0f197516d708 100644 --- a/drivers/perf/arm_pmu_acpi.c +++ b/drivers/perf/arm_pmu_acpi.c @@ -89,7 +89,13 @@ static int arm_pmu_acpi_parse_irqs(void) pr_warn("No ACPI PMU IRQ for CPU%d\n", cpu); } + /* + * Log and request the IRQ so the core arm_pmu code can manage + * it. We'll have to sanity-check IRQs later when we associate + * them with their PMUs. + */ per_cpu(pmu_irqs, cpu) = irq; + armpmu_request_irq(irq, cpu); } return 0; @@ -204,14 +210,6 @@ static int arm_pmu_acpi_cpu_starting(unsigned int cpu) cpumask_set_cpu(cpu, &pmu->supported_cpus); - /* - * Log and request the IRQ so the core arm_pmu code can manage it. In - * some situations (e.g. mismatched PPIs), we may fail to request the - * IRQ. However, it may be too late for us to do anything about it. - * The common ARM PMU code will log a warning in this case. - */ - armpmu_request_irq(pmu, cpu); - /* * Ideally, we'd probe the PMU here when we find the first matching * CPU. We can't do that for several reasons; see the comment in @@ -281,11 +279,6 @@ static int arm_pmu_acpi_init(void) if (acpi_disabled) return 0; - /* - * We can't request IRQs yet, since we don't know the cookie value - * until we know which CPUs share the same logical PMU. We'll handle - * that in arm_pmu_acpi_cpu_starting(). - */ ret = arm_pmu_acpi_parse_irqs(); if (ret) return ret; diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c index 1dc3c1f574e0..7729eda5909d 100644 --- a/drivers/perf/arm_pmu_platform.c +++ b/drivers/perf/arm_pmu_platform.c @@ -159,10 +159,15 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) static int armpmu_request_irqs(struct arm_pmu *armpmu) { + struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; int cpu, err; for_each_cpu(cpu, &armpmu->supported_cpus) { - err = armpmu_request_irq(armpmu, cpu); + int irq = per_cpu(hw_events->irq, cpu); + if (!irq) + continue; + + err = armpmu_request_irq(irq, cpu); if (err) break; } @@ -173,9 +178,13 @@ static int armpmu_request_irqs(struct arm_pmu *armpmu) static void armpmu_free_irqs(struct arm_pmu *armpmu) { int cpu; + struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; - for_each_cpu(cpu, &armpmu->supported_cpus) - armpmu_free_irq(armpmu, cpu); + for_each_cpu(cpu, &armpmu->supported_cpus) { + int irq = per_cpu(hw_events->irq, cpu); + + armpmu_free_irq(irq, cpu); + } } int arm_pmu_device_probe(struct platform_device *pdev, -- cgit v1.2.3 From 35b5f14ec6dab281346a2d0ceb34abe2dba94190 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 13 Feb 2018 10:37:59 +0100 Subject: regulator: Fix resume from suspend to idle When resuming from idle with the new suspend mode configuration support we go through the resume callbacks with a state of PM_SUSPEND_TO_IDLE which we don't have regulator constraints for, causing an error: dpm_run_callback(): regulator_resume_early+0x0/0x64 returns -22 PM: Device regulator.0 failed to resume early: error -22 Avoid this and similar errors by treating missing constraints as a noop. See also commit 57a0dd187956ea04 ("regulator: Fix suspend to idle"), which fixed the suspend part. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/regulator/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index dd4708c58480..1fc0c0811da4 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -4310,7 +4310,7 @@ static int _regulator_resume_early(struct device *dev, void *data) rstate = regulator_get_suspend_state(rdev, *state); if (rstate == NULL) - return -EINVAL; + return 0; mutex_lock(&rdev->mutex); -- cgit v1.2.3 From 17539f2f4f0b7fa906b508765c8ada07a1e45f52 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Tue, 20 Feb 2018 07:30:10 -0600 Subject: usb: musb: fix enumeration after resume On dm3730 there are enumeration problems after resume. Investigation led to the cause that the MUSB_POWER_SOFTCONN bit is not set. If it was set before suspend (because it was enabled via musb_pullup()), it is set in musb_restore_context() so the pullup is enabled. But then musb_start() is called which overwrites MUSB_POWER and therefore disables MUSB_POWER_SOFTCONN, so no pullup is enabled and the device is not enumerated. So let's do a subset of what musb_start() does in the same way as musb_suspend() does it. Platform-specific stuff it still called as there might be some phy-related stuff which needs to be enabled. Also interrupts are enabled, as it was the original idea of calling musb_start() in musb_resume() according to Commit 6fc6f4b87cb3 ("usb: musb: Disable interrupts on suspend, enable them on resume") Signed-off-by: Andreas Kemnade Tested-by: Tony Lindgren Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 968bf1e8b0fe..eef4ad578b31 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2708,7 +2708,8 @@ static int musb_resume(struct device *dev) if ((devctl & mask) != (musb->context.devctl & mask)) musb->port1_status = 0; - musb_start(musb); + musb_enable_interrupts(musb); + musb_platform_enable(musb); spin_lock_irqsave(&musb->lock, flags); error = musb_run_resume_work(musb); -- cgit v1.2.3 From 44eb5e12b845cc8a0634f21b70ef07d774eb4b25 Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Tue, 20 Feb 2018 07:31:35 -0600 Subject: Revert "usb: musb: host: don't start next rx urb if current one failed" This reverts commit dbac5d07d13e330e6706813c9fde477140fb5d80. commit dbac5d07d13e ("usb: musb: host: don't start next rx urb if current one failed") along with commit b5801212229f ("usb: musb: host: clear rxcsr error bit if set") try to solve the issue described in [1], but the latter alone is sufficient, and the former causes the issue as in [2], so now revert it. [1] https://marc.info/?l=linux-usb&m=146173995117456&w=2 [2] https://marc.info/?l=linux-usb&m=151689238420622&w=2 Cc: stable@vger.kernel.org # v4.7+ Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_host.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 394b4ac86161..45ed32c2cba9 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -391,13 +391,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb, } } - /* - * The pipe must be broken if current urb->status is set, so don't - * start next urb. - * TODO: to minimize the risk of regression, only check urb->status - * for RX, until we have a test case to understand the behavior of TX. - */ - if ((!status || !is_in) && qh && qh->is_ready) { + if (qh != NULL && qh->is_ready) { musb_dbg(musb, "... next ep%d %cX urb %p", hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh)); musb_start_urb(musb, is_in, qh); -- cgit v1.2.3 From f0efc831d9439589efaf6406695470eca93ba08d Mon Sep 17 00:00:00 2001 From: Lloyd Atkinson Date: Tue, 16 Jan 2018 16:26:01 -0500 Subject: drm/msm/dsi: check for failure on retrieving pll in dsi manager Make msm_dsi_pll_init consistently return an error code instead of NULL when pll initialization fails so that later pll retrieval can check against an error code. Add checks for these failures after retrieval of src_pll to avoid invalid pointer dereferences later in msm_dsi_pll_get_clk_provider. Signed-off-by: Lloyd Atkinson Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_manager.c | 4 ++++ drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 6 +++--- drivers/gpu/drm/msm/dsi/pll/dsi_pll.c | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 855248132b2b..1a54fd67c9c4 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -88,6 +88,8 @@ static int dsi_mgr_setup_components(int id) msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE); src_pll = msm_dsi_phy_get_pll(msm_dsi->phy); + if (IS_ERR(src_pll)) + return PTR_ERR(src_pll); ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll); } else if (!other_dsi) { ret = 0; @@ -116,6 +118,8 @@ static int dsi_mgr_setup_components(int id) msm_dsi_phy_set_usecase(clk_slave_dsi->phy, MSM_DSI_PHY_SLAVE); src_pll = msm_dsi_phy_get_pll(clk_master_dsi->phy); + if (IS_ERR(src_pll)) + return PTR_ERR(src_pll); ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll); if (ret) return ret; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 790ca280cbfd..c8bfaa780651 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -503,10 +503,10 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) goto fail; phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id); - if (!phy->pll) + if (IS_ERR_OR_NULL(phy->pll)) dev_info(dev, - "%s: pll init failed, need separate pll clk driver\n", - __func__); + "%s: pll init failed: %ld, need separate pll clk driver\n", + __func__, PTR_ERR(phy->pll)); dsi_phy_disable_resource(phy); diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c index bc289f5c9078..491f08dce969 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c @@ -173,7 +173,7 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev, if (IS_ERR(pll)) { dev_err(dev, "%s: failed to init DSI PLL\n", __func__); - return NULL; + return pll; } pll->type = type; -- cgit v1.2.3 From 6e1787cf45e48866c01dadc2a1b6c3d63d75b8d1 Mon Sep 17 00:00:00 2001 From: Lloyd Atkinson Date: Tue, 16 Jan 2018 16:26:02 -0500 Subject: drm/msm/dsi: correct DSI id bounds check during registration Check DSI instance id argument against the proper boundary size to protect against invalid configuration of the DSI id. Signed-off-by: Lloyd Atkinson Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 1a54fd67c9c4..4cb1cb68878b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -862,7 +862,7 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi) int id = msm_dsi->id; int ret; - if (id > DSI_MAX) { + if (id >= DSI_MAX) { pr_err("%s: invalid id %d\n", __func__, id); return -EINVAL; } -- cgit v1.2.3 From 3f0689e663524115b068258bab789dff1ddab5da Mon Sep 17 00:00:00 2001 From: Lloyd Atkinson Date: Tue, 16 Jan 2018 16:26:03 -0500 Subject: drm/msm/dsi: check msm_dsi and dsi pointers before use Move null checks of pointer arguments to the beginning of the modeset init function since they are referenced immediately instead of after they have already been used. Signed-off-by: Lloyd Atkinson Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index 98742d7af6dc..ee7e090e27b4 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -196,7 +196,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, struct drm_bridge *ext_bridge; int ret; - if (WARN_ON(!encoder)) + if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev)) return -EINVAL; msm_dsi->dev = dev; @@ -245,19 +245,17 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, return 0; fail: - if (msm_dsi) { - /* bridge/connector are normally destroyed by drm: */ - if (msm_dsi->bridge) { - msm_dsi_manager_bridge_destroy(msm_dsi->bridge); - msm_dsi->bridge = NULL; - } + /* bridge/connector are normally destroyed by drm: */ + if (msm_dsi->bridge) { + msm_dsi_manager_bridge_destroy(msm_dsi->bridge); + msm_dsi->bridge = NULL; + } - /* don't destroy connector if we didn't make it */ - if (msm_dsi->connector && !msm_dsi->external_bridge) - msm_dsi->connector->funcs->destroy(msm_dsi->connector); + /* don't destroy connector if we didn't make it */ + if (msm_dsi->connector && !msm_dsi->external_bridge) + msm_dsi->connector->funcs->destroy(msm_dsi->connector); - msm_dsi->connector = NULL; - } + msm_dsi->connector = NULL; return ret; } -- cgit v1.2.3 From 331dc0bc195bb77fcbe60b4513464b406a6d20cb Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 13 Dec 2017 15:12:56 -0500 Subject: drm/msm: add a5xx specific debugfs Add some debugfs to dump out PFP and ME microcontroller state, as well as some of the queues (MEQ and ROQ). Also add a debugfs file to trigger a GPU reset (and reloading the firmware on next submit). Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/Makefile | 2 + drivers/gpu/drm/msm/adreno/a5xx_debugfs.c | 188 +++++++++++++++++++++++++++++ drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 1 + drivers/gpu/drm/msm/adreno/a5xx_gpu.h | 4 + drivers/gpu/drm/msm/adreno/adreno_device.c | 6 + drivers/gpu/drm/msm/msm_debugfs.c | 5 +- drivers/gpu/drm/msm/msm_gpu.h | 2 + 7 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/msm/adreno/a5xx_debugfs.c (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 92b3844202d2..ebe0c3d0b126 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -62,6 +62,8 @@ msm-y := \ msm_ringbuffer.o \ msm_submitqueue.o +msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o + msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o msm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_pll_8960.o diff --git a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c new file mode 100644 index 000000000000..cef09780ef17 --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c @@ -0,0 +1,188 @@ +/* Copyright (c) 2016-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 + * 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 +#include +#include + +#include "a5xx_gpu.h" + +static int pfp_print(struct msm_gpu *gpu, struct drm_printer *p) +{ + int i; + + drm_printf(p, "PFP state:\n"); + + for (i = 0; i < 36; i++) { + gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, i); + drm_printf(p, " %02x: %08x\n", i, + gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA)); + } + + return 0; +} + +static int me_print(struct msm_gpu *gpu, struct drm_printer *p) +{ + int i; + + drm_printf(p, "ME state:\n"); + + for (i = 0; i < 29; i++) { + gpu_write(gpu, REG_A5XX_CP_ME_STAT_ADDR, i); + drm_printf(p, " %02x: %08x\n", i, + gpu_read(gpu, REG_A5XX_CP_ME_STAT_DATA)); + } + + return 0; +} + +static int meq_print(struct msm_gpu *gpu, struct drm_printer *p) +{ + int i; + + drm_printf(p, "MEQ state:\n"); + gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0); + + for (i = 0; i < 64; i++) { + drm_printf(p, " %02x: %08x\n", i, + gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA)); + } + + return 0; +} + +static int roq_print(struct msm_gpu *gpu, struct drm_printer *p) +{ + int i; + + drm_printf(p, "ROQ state:\n"); + gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0); + + for (i = 0; i < 512 / 4; i++) { + uint32_t val[4]; + int j; + for (j = 0; j < 4; j++) + val[j] = gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA); + drm_printf(p, " %02x: %08x %08x %08x %08x\n", i, + val[0], val[1], val[2], val[3]); + } + + return 0; +} + +static int show(struct seq_file *m, void *arg) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct msm_drm_private *priv = dev->dev_private; + struct drm_printer p = drm_seq_file_printer(m); + int (*show)(struct msm_gpu *gpu, struct drm_printer *p) = + node->info_ent->data; + + return show(priv->gpu, &p); +} + +#define ENT(n) { .name = #n, .show = show, .data = n ##_print } +static struct drm_info_list a5xx_debugfs_list[] = { + ENT(pfp), + ENT(me), + ENT(meq), + ENT(roq), +}; + +/* for debugfs files that can be written to, we can't use drm helper: */ +static int +reset_set(void *data, u64 val) +{ + struct drm_device *dev = data; + struct msm_drm_private *priv = dev->dev_private; + struct msm_gpu *gpu = priv->gpu; + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + + if (!capable(CAP_SYS_ADMIN)) + return -EINVAL; + + /* TODO do we care about trying to make sure the GPU is idle? + * Since this is just a debug feature limited to CAP_SYS_ADMIN, + * maybe it is fine to let the user keep both pieces if they + * try to reset an active GPU. + */ + + mutex_lock(&dev->struct_mutex); + + if (adreno_gpu->pm4) { + release_firmware(adreno_gpu->pm4); + adreno_gpu->pm4 = NULL; + } + + if (adreno_gpu->pfp) { + release_firmware(adreno_gpu->pfp); + adreno_gpu->pfp = NULL; + } + if (a5xx_gpu->pm4_bo) { + if (a5xx_gpu->pm4_iova) + msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace); + drm_gem_object_unreference(a5xx_gpu->pm4_bo); + a5xx_gpu->pm4_bo = NULL; + } + + if (a5xx_gpu->pfp_bo) { + if (a5xx_gpu->pfp_iova) + msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace); + drm_gem_object_unreference(a5xx_gpu->pfp_bo); + a5xx_gpu->pfp_bo = NULL; + } + + gpu->needs_hw_init = true; + + pm_runtime_get_sync(&gpu->pdev->dev); + gpu->funcs->recover(gpu); + + pm_runtime_put_sync(&gpu->pdev->dev); + mutex_unlock(&dev->struct_mutex); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n"); + + +int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct dentry *ent; + int ret; + + if (!minor) + return 0; + + ret = drm_debugfs_create_files(a5xx_debugfs_list, + ARRAY_SIZE(a5xx_debugfs_list), + minor->debugfs_root, minor); + + if (ret) { + dev_err(dev->dev, "could not install a5xx_debugfs_list\n"); + return ret; + } + + ent = debugfs_create_file("reset", S_IWUGO, + minor->debugfs_root, + dev, &reset_fops); + if (!ent) + return -ENOMEM; + + return 0; +} diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 7e09d44e4a15..579c28c8c994 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -1195,6 +1195,7 @@ static const struct adreno_gpu_funcs funcs = { .destroy = a5xx_destroy, #ifdef CONFIG_DEBUG_FS .show = a5xx_show, + .debugfs_init = a5xx_debugfs_init, #endif .gpu_busy = a5xx_gpu_busy, }, diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h index 6fb8c2f9b9e4..7d71860c4bee 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h @@ -49,6 +49,10 @@ struct a5xx_gpu { #define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base) +#ifdef CONFIG_DEBUG_FS +int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor); +#endif + /* * In order to do lockless preemption we use a simple state machine to progress * through the process. diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 62bdb7316da1..6263cb906b3c 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -150,6 +150,12 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev) return NULL; } + if (gpu->funcs->debugfs_init) { + gpu->funcs->debugfs_init(gpu, dev->primary); + gpu->funcs->debugfs_init(gpu, dev->render); + gpu->funcs->debugfs_init(gpu, dev->control); + } + return gpu; } diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 1855182c76ce..ba74cb4f94df 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -161,8 +161,11 @@ int msm_debugfs_init(struct drm_minor *minor) return ret; } - if (priv->kms->funcs->debugfs_init) + if (priv->kms->funcs->debugfs_init) { ret = priv->kms->funcs->debugfs_init(priv->kms, minor); + if (ret) + return ret; + } return ret; } diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index fccfccd303af..b8241179175a 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -65,6 +65,8 @@ struct msm_gpu_funcs { #ifdef CONFIG_DEBUG_FS /* show GPU status in debugfs: */ void (*show)(struct msm_gpu *gpu, struct seq_file *m); + /* for generation specific debugfs: */ + int (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor); #endif int (*gpu_busy)(struct msm_gpu *gpu, uint64_t *value); }; -- cgit v1.2.3 From 6a8bd08d0465b2b8d214007c58598e2c15312296 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 13 Dec 2017 15:12:57 -0500 Subject: drm/msm: add sudo flag to submit ioctl This flags cause cmdstream to be executed from the ringbuffer (RB) instead of IB1. Normally not something you'd ever want to do, but it is super useful for firmware debugging. Hidden behind CAP_SYS_RAWIO and a default=n kconfig option which depends on EXPERT (and has a suitably scary warning), to prevent it from being used on accident. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/Kconfig | 13 +++++++ drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 65 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_gem.h | 1 + drivers/gpu/drm/msm/msm_gem_submit.c | 9 +++++ 4 files changed, 88 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 99d39b2aefa6..3065cb290aa8 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -28,6 +28,19 @@ config DRM_MSM_REGISTER_LOGGING that can be parsed by envytools demsm tool. If enabled, register logging can be switched on via msm.reglog=y module param. +config DRM_MSM_GPU_SUDO + bool "Enable SUDO flag on submits" + depends on DRM_MSM && EXPERT + default n + help + Enable userspace that has CAP_SYS_RAWIO to submit GPU commands + that are run from RB instead of IB1. This essentially gives + userspace kernel level access, but is useful for firmware + debugging. + + Only use this if you are a driver developer. This should *not* + be enabled for production kernels. If unsure, say N. + config DRM_MSM_HDMI_HDCP bool "Enable HDMI HDCP support in MSM DRM driver" depends on DRM_MSM && QCOM_SCM diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 579c28c8c994..fa08b4897a56 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -140,6 +140,65 @@ static void a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring) gpu_write(gpu, REG_A5XX_CP_RB_WPTR, wptr); } +static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit, + struct msm_file_private *ctx) +{ + struct msm_drm_private *priv = gpu->dev->dev_private; + struct msm_ringbuffer *ring = submit->ring; + struct msm_gem_object *obj; + uint32_t *ptr, dwords; + unsigned int i; + + for (i = 0; i < submit->nr_cmds; i++) { + switch (submit->cmd[i].type) { + case MSM_SUBMIT_CMD_IB_TARGET_BUF: + break; + case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: + if (priv->lastctx == ctx) + break; + case MSM_SUBMIT_CMD_BUF: + /* copy commands into RB: */ + obj = submit->bos[submit->cmd[i].idx].obj; + dwords = submit->cmd[i].size; + + ptr = msm_gem_get_vaddr(&obj->base); + + /* _get_vaddr() shouldn't fail at this point, + * since we've already mapped it once in + * submit_reloc() + */ + if (WARN_ON(!ptr)) + return; + + for (i = 0; i < dwords; i++) { + /* normally the OUT_PKTn() would wait + * for space for the packet. But since + * we just OUT_RING() the whole thing, + * need to call adreno_wait_ring() + * ourself: + */ + adreno_wait_ring(ring, 1); + OUT_RING(ring, ptr[i]); + } + + msm_gem_put_vaddr(&obj->base); + + break; + } + } + + a5xx_flush(gpu, ring); + a5xx_preempt_trigger(gpu); + + /* we might not necessarily have a cmd from userspace to + * trigger an event to know that submit has completed, so + * do this manually: + */ + a5xx_idle(gpu, ring); + ring->memptrs->fence = submit->seqno; + msm_gpu_retire(gpu); +} + static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_file_private *ctx) { @@ -149,6 +208,12 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_ringbuffer *ring = submit->ring; unsigned int i, ibs = 0; + if (IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) && submit->in_rb) { + priv->lastctx = NULL; + a5xx_submit_in_rb(gpu, submit, ctx); + return; + } + OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1); OUT_RING(ring, 0x02); diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 9320e184b48d..c5d9bd3e47a8 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -146,6 +146,7 @@ struct msm_gem_submit { struct msm_gpu_submitqueue *queue; struct pid *pid; /* submitting process */ bool valid; /* true if no cmdstream patching needed */ + bool in_rb; /* "sudo" mode, copy cmds into RB */ struct msm_ringbuffer *ring; unsigned int nr_cmds; unsigned int nr_bos; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index b8dc8f96caf2..7bd83e0afa97 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -430,6 +430,12 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (MSM_PIPE_FLAGS(args->flags) & ~MSM_SUBMIT_FLAGS) return -EINVAL; + if (args->flags & MSM_SUBMIT_SUDO) { + if (!IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) || + !capable(CAP_SYS_RAWIO)) + return -EINVAL; + } + queue = msm_submitqueue_get(ctx, args->queueid); if (!queue) return -ENOENT; @@ -471,6 +477,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, goto out_unlock; } + if (args->flags & MSM_SUBMIT_SUDO) + submit->in_rb = true; + ret = submit_lookup_objects(submit, args, file); if (ret) goto out; -- cgit v1.2.3 From 6d5796af7136046835621ffe680eb15ce88500b6 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 17 Jan 2018 11:35:24 +0530 Subject: drm/msm/dsi: Update generated headers for 10nm PLL/PHY Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi.xml.h | 187 +++++++++++++++++++++++++++++++++++--- 1 file changed, 174 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h b/drivers/gpu/drm/msm/dsi/dsi.xml.h index 479086ccf180..f6a9471b70c8 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.xml.h +++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h @@ -8,19 +8,10 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 37411 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 33004 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2017-05-17 13:21:27) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 41799 bytes, from 2017-06-16 12:32:42) -- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2017-05-17 13:21:27) - -Copyright (C) 2013-2017 by the following authors: +- /local/mnt/workspace/source_trees/envytools/rnndb/../rnndb/dsi/dsi.xml ( 37239 bytes, from 2018-01-12 09:09:22) +- /local/mnt/workspace/source_trees/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2016-05-09 06:32:54) + +Copyright (C) 2013-2018 by the following authors: - Rob Clark (robclark) - Ilia Mirkin (imirkin) @@ -1556,5 +1547,175 @@ static inline uint32_t REG_DSI_14nm_PHY_LN_VREG_CNTRL(uint32_t i0) { return 0x00 #define REG_DSI_14nm_PHY_PLL_PLL_BANDGAP 0x00000108 +#define REG_DSI_10nm_PHY_CMN_REVISION_ID0 0x00000000 + +#define REG_DSI_10nm_PHY_CMN_REVISION_ID1 0x00000004 + +#define REG_DSI_10nm_PHY_CMN_REVISION_ID2 0x00000008 + +#define REG_DSI_10nm_PHY_CMN_REVISION_ID3 0x0000000c + +#define REG_DSI_10nm_PHY_CMN_CLK_CFG0 0x00000010 + +#define REG_DSI_10nm_PHY_CMN_CLK_CFG1 0x00000014 + +#define REG_DSI_10nm_PHY_CMN_GLBL_CTRL 0x00000018 + +#define REG_DSI_10nm_PHY_CMN_RBUF_CTRL 0x0000001c + +#define REG_DSI_10nm_PHY_CMN_VREG_CTRL 0x00000020 + +#define REG_DSI_10nm_PHY_CMN_CTRL_0 0x00000024 + +#define REG_DSI_10nm_PHY_CMN_CTRL_1 0x00000028 + +#define REG_DSI_10nm_PHY_CMN_CTRL_2 0x0000002c + +#define REG_DSI_10nm_PHY_CMN_LANE_CFG0 0x00000030 + +#define REG_DSI_10nm_PHY_CMN_LANE_CFG1 0x00000034 + +#define REG_DSI_10nm_PHY_CMN_PLL_CNTRL 0x00000038 + +#define REG_DSI_10nm_PHY_CMN_LANE_CTRL0 0x00000098 + +#define REG_DSI_10nm_PHY_CMN_LANE_CTRL1 0x0000009c + +#define REG_DSI_10nm_PHY_CMN_LANE_CTRL2 0x000000a0 + +#define REG_DSI_10nm_PHY_CMN_LANE_CTRL3 0x000000a4 + +#define REG_DSI_10nm_PHY_CMN_LANE_CTRL4 0x000000a8 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_0 0x000000ac + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_1 0x000000b0 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_2 0x000000b4 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_3 0x000000b8 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_4 0x000000bc + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_5 0x000000c0 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_6 0x000000c4 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_7 0x000000c8 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_8 0x000000cc + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_9 0x000000d0 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_10 0x000000d4 + +#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_11 0x000000d8 + +#define REG_DSI_10nm_PHY_CMN_PHY_STATUS 0x000000ec + +#define REG_DSI_10nm_PHY_CMN_LANE_STATUS0 0x000000f4 + +#define REG_DSI_10nm_PHY_CMN_LANE_STATUS1 0x000000f8 + +static inline uint32_t REG_DSI_10nm_PHY_LN(uint32_t i0) { return 0x00000000 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_CFG0(uint32_t i0) { return 0x00000000 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_CFG1(uint32_t i0) { return 0x00000004 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_CFG2(uint32_t i0) { return 0x00000008 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_CFG3(uint32_t i0) { return 0x0000000c + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_TEST_DATAPATH(uint32_t i0) { return 0x00000010 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_PIN_SWAP(uint32_t i0) { return 0x00000014 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_HSTX_STR_CTRL(uint32_t i0) { return 0x00000018 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(uint32_t i0) { return 0x0000001c + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(uint32_t i0) { return 0x00000020 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(uint32_t i0) { return 0x00000024 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_LPRX_CTRL(uint32_t i0) { return 0x00000028 + 0x80*i0; } + +static inline uint32_t REG_DSI_10nm_PHY_LN_TX_DCTRL(uint32_t i0) { return 0x0000002c + 0x80*i0; } + +#define REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE 0x00000000 + +#define REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO 0x00000004 + +#define REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE 0x00000010 + +#define REG_DSI_10nm_PHY_PLL_DSM_DIVIDER 0x0000001c + +#define REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER 0x00000020 + +#define REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES 0x00000024 + +#define REG_DSI_10nm_PHY_PLL_CMODE 0x0000002c + +#define REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS 0x00000030 + +#define REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE 0x00000054 + +#define REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE 0x00000064 + +#define REG_DSI_10nm_PHY_PLL_PFILT 0x0000007c + +#define REG_DSI_10nm_PHY_PLL_IFILT 0x00000080 + +#define REG_DSI_10nm_PHY_PLL_OUTDIV 0x00000094 + +#define REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE 0x000000a4 + +#define REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE 0x000000a8 + +#define REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO 0x000000b4 + +#define REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1 0x000000cc + +#define REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1 0x000000d0 + +#define REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1 0x000000d4 + +#define REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1 0x000000d8 + +#define REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1 0x0000010c + +#define REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1 0x00000110 + +#define REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1 0x00000114 + +#define REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1 0x00000118 + +#define REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1 0x0000011c + +#define REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1 0x00000120 + +#define REG_DSI_10nm_PHY_PLL_SSC_CONTROL 0x0000013c + +#define REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE 0x00000140 + +#define REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1 0x00000144 + +#define REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1 0x0000014c + +#define REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1 0x00000154 + +#define REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1 0x0000015c + +#define REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x00000164 + +#define REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE 0x00000180 + +#define REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY 0x00000184 + +#define REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS 0x0000018c + +#define REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE 0x000001a0 + #endif /* DSI_XML */ -- cgit v1.2.3 From 973e02db35c2c4036693e32ed6f250eefd8c322c Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 17 Jan 2018 11:35:25 +0530 Subject: drm/msm/dsi: Add skeleton 10nm PHY/PLL code Add new 10nm DSI PLL/PHY files that will be used on SDM845. Just populate empty pll/phy funcs for now. These will be filled up later. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/Kconfig | 7 ++ drivers/gpu/drm/msm/Makefile | 2 + drivers/gpu/drm/msm/dsi/dsi.h | 1 + drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 4 + drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | 1 + drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c | 52 +++++++++ drivers/gpu/drm/msm/dsi/pll/dsi_pll.c | 3 + drivers/gpu/drm/msm/dsi/pll/dsi_pll.h | 9 ++ drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c | 176 +++++++++++++++++++++++++++++ 9 files changed, 255 insertions(+) create mode 100644 drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c create mode 100644 drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 3065cb290aa8..38cbde971b48 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -94,3 +94,10 @@ config DRM_MSM_DSI_14NM_PHY default y help Choose this option if DSI PHY on 8996 is used on the platform. + +config DRM_MSM_DSI_10NM_PHY + bool "Enable DSI 10nm PHY driver in MSM DRM (used by SDM845)" + depends on DRM_MSM_DSI + default y + help + Choose this option if DSI PHY on SDM845 is used on the platform. diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index ebe0c3d0b126..f74d449476f4 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -83,12 +83,14 @@ msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/phy/dsi_phy_28nm.o msm-$(CONFIG_DRM_MSM_DSI_20NM_PHY) += dsi/phy/dsi_phy_20nm.o msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/phy/dsi_phy_28nm_8960.o msm-$(CONFIG_DRM_MSM_DSI_14NM_PHY) += dsi/phy/dsi_phy_14nm.o +msm-$(CONFIG_DRM_MSM_DSI_10NM_PHY) += dsi/phy/dsi_phy_10nm.o ifeq ($(CONFIG_DRM_MSM_DSI_PLL),y) msm-y += dsi/pll/dsi_pll.o msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/pll/dsi_pll_28nm.o msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/pll/dsi_pll_28nm_8960.o msm-$(CONFIG_DRM_MSM_DSI_14NM_PHY) += dsi/pll/dsi_pll_14nm.o +msm-$(CONFIG_DRM_MSM_DSI_10NM_PHY) += dsi/pll/dsi_pll_10nm.o endif obj-$(CONFIG_DRM_MSM) += msm.o diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 2302046197a8..70d9a9a47acd 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -36,6 +36,7 @@ enum msm_dsi_phy_type { MSM_DSI_PHY_20NM, MSM_DSI_PHY_28NM_8960, MSM_DSI_PHY_14NM, + MSM_DSI_PHY_10NM, MSM_DSI_PHY_MAX }; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index c8bfaa780651..8e9d5c255820 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -394,6 +394,10 @@ static const struct of_device_id dsi_phy_dt_match[] = { #ifdef CONFIG_DRM_MSM_DSI_14NM_PHY { .compatible = "qcom,dsi-phy-14nm", .data = &dsi_phy_14nm_cfgs }, +#endif +#ifdef CONFIG_DRM_MSM_DSI_10NM_PHY + { .compatible = "qcom,dsi-phy-10nm", + .data = &dsi_phy_10nm_cfgs }, #endif {} }; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 1733f6608a09..c56268cbdb3d 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -48,6 +48,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs; struct msm_dsi_dphy_timing { u32 clk_pre; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c new file mode 100644 index 000000000000..b7545fb63bf5 --- /dev/null +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018, The Linux Foundation + */ + +#include + +#include "dsi_phy.h" +#include "dsi.xml.h" + +static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, + struct msm_dsi_phy_clk_request *clk_req) +{ + return 0; +} + +static void dsi_10nm_phy_disable(struct msm_dsi_phy *phy) +{ +} + +static int dsi_10nm_phy_init(struct msm_dsi_phy *phy) +{ + struct platform_device *pdev = phy->pdev; + + phy->lane_base = msm_ioremap(pdev, "dsi_phy_lane", + "DSI_PHY_LANE"); + if (IS_ERR(phy->lane_base)) { + dev_err(&pdev->dev, "%s: failed to map phy lane base\n", + __func__); + return -ENOMEM; + } + + return 0; +} + +const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs = { + .type = MSM_DSI_PHY_10NM, + .src_pll_truthtable = { {false, false}, {true, false} }, + .reg_cfg = { + .num = 1, + .regs = { + {"vdds", 36000, 32}, + }, + }, + .ops = { + .enable = dsi_10nm_phy_enable, + .disable = dsi_10nm_phy_disable, + .init = dsi_10nm_phy_init, + }, + .io_start = { 0xae94400, 0xae96400 }, + .num_dsi_phy = 2, +}; diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c index 491f08dce969..613e206fa4fc 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c @@ -166,6 +166,9 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev, case MSM_DSI_PHY_14NM: pll = msm_dsi_pll_14nm_init(pdev, id); break; + case MSM_DSI_PHY_10NM: + pll = msm_dsi_pll_10nm_init(pdev, id); + break; default: pll = ERR_PTR(-ENXIO); break; diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h index f63e7ada74a8..8b32271cbc24 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h @@ -115,5 +115,14 @@ msm_dsi_pll_14nm_init(struct platform_device *pdev, int id) return ERR_PTR(-ENODEV); } #endif +#ifdef CONFIG_DRM_MSM_DSI_10NM_PHY +struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id); +#else +static inline struct msm_dsi_pll * +msm_dsi_pll_10nm_init(struct platform_device *pdev, int id) +{ + return ERR_PTR(-ENODEV); +} +#endif #endif /* __DSI_PLL_H__ */ diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c new file mode 100644 index 000000000000..34c24442d34b --- /dev/null +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c @@ -0,0 +1,176 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018, The Linux Foundation + */ + +#include +#include +#include + +#include "dsi_pll.h" +#include "dsi.xml.h" + +struct dsi_pll_10nm { + struct msm_dsi_pll base; + + int id; + struct platform_device *pdev; + + void __iomem *phy_cmn_mmio; + void __iomem *mmio; + + int vco_delay; + + enum msm_dsi_phy_usecase uc; + struct dsi_pll_10nm *slave; +}; + +#define to_pll_10nm(x) container_of(x, struct dsi_pll_10nm, base) + +/* + * Global list of private DSI PLL struct pointers. We need this for Dual DSI + * mode, where the master PLL's clk_ops needs access the slave's private data + */ +static struct dsi_pll_10nm *pll_10nm_list[DSI_MAX]; + +static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + + DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_10nm->id, rate, + parent_rate); + + return 0; +} + +static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + u64 vco_rate = 0x0; + + DBG("DSI PLL%d returning vco rate = %lu", pll_10nm->id, + (unsigned long)vco_rate); + + return (unsigned long)vco_rate; +} + +static const struct clk_ops clk_ops_dsi_pll_10nm_vco = { + .round_rate = msm_dsi_pll_helper_clk_round_rate, + .set_rate = dsi_pll_10nm_vco_set_rate, + .recalc_rate = dsi_pll_10nm_vco_recalc_rate, + .prepare = msm_dsi_pll_helper_clk_prepare, + .unprepare = msm_dsi_pll_helper_clk_unprepare, +}; + +/* + * PLL Callbacks + */ + +static void dsi_pll_10nm_save_state(struct msm_dsi_pll *pll) +{ + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + + DBG("DSI PLL%d", pll_10nm->id); +} + +static int dsi_pll_10nm_restore_state(struct msm_dsi_pll *pll) +{ + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + + DBG("DSI PLL%d", pll_10nm->id); + + return 0; +} + +static int dsi_pll_10nm_set_usecase(struct msm_dsi_pll *pll, + enum msm_dsi_phy_usecase uc) +{ + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + + DBG("DSI PLL%d", pll_10nm->id); + + return 0; +} + +static int dsi_pll_10nm_get_provider(struct msm_dsi_pll *pll, + struct clk **byte_clk_provider, + struct clk **pixel_clk_provider) +{ + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + + DBG("DSI PLL%d", pll_10nm->id); + + if (byte_clk_provider) + *byte_clk_provider = NULL; + if (pixel_clk_provider) + *pixel_clk_provider = NULL; + + return 0; +} + +static void dsi_pll_10nm_destroy(struct msm_dsi_pll *pll) +{ + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + + DBG("DSI PLL%d", pll_10nm->id); +} + +static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) +{ + return 0; +} + +struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id) +{ + struct dsi_pll_10nm *pll_10nm; + struct msm_dsi_pll *pll; + int ret; + + if (!pdev) + return ERR_PTR(-ENODEV); + + pll_10nm = devm_kzalloc(&pdev->dev, sizeof(*pll_10nm), GFP_KERNEL); + if (!pll_10nm) + return ERR_PTR(-ENOMEM); + + DBG("DSI PLL%d", id); + + pll_10nm->pdev = pdev; + pll_10nm->id = id; + pll_10nm_list[id] = pll_10nm; + + pll_10nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY"); + if (IS_ERR_OR_NULL(pll_10nm->phy_cmn_mmio)) { + dev_err(&pdev->dev, "failed to map CMN PHY base\n"); + return ERR_PTR(-ENOMEM); + } + + pll_10nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); + if (IS_ERR_OR_NULL(pll_10nm->mmio)) { + dev_err(&pdev->dev, "failed to map PLL base\n"); + return ERR_PTR(-ENOMEM); + } + + pll = &pll_10nm->base; + pll->min_rate = 1000000000UL; + pll->max_rate = 3500000000UL; + pll->get_provider = dsi_pll_10nm_get_provider; + pll->destroy = dsi_pll_10nm_destroy; + pll->save_state = dsi_pll_10nm_save_state; + pll->restore_state = dsi_pll_10nm_restore_state; + pll->set_usecase = dsi_pll_10nm_set_usecase; + + pll_10nm->vco_delay = 1; + + ret = pll_10nm_register(pll_10nm); + if (ret) { + dev_err(&pdev->dev, "failed to register PLL: %d\n", ret); + return ERR_PTR(ret); + } + + return pll; +} -- cgit v1.2.3 From 28e4309ab9c2bade2a93bd3b4c583be5ec440b84 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 17 Jan 2018 11:35:26 +0530 Subject: drm/msm/dsi: Populate PLL 10nm clock ops Populate PLL clock ops from downstream. This contains the VCO PLL ops and the registration of standard clk_divider and clk_mux clocks. Unlike 14nm PLL, the postdividers/mux of the slave PLL doesn't need to be set to the same values of the postdivs/mux of the master PLL. Hence, we don't need special postdivider clock ops like we did with the 14nm PLL driver. Like the previous PLL drivers, the implementation is slightly different from downstream. We don't use shadow clocks, but have the ability to reparent the RCGs to a different source. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c | 662 ++++++++++++++++++++++++++++- 1 file changed, 654 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c index 34c24442d34b..c4c37a7df637 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c @@ -10,6 +10,78 @@ #include "dsi_pll.h" #include "dsi.xml.h" +/* + * DSI PLL 10nm - clock diagram (eg: DSI0): + * + * dsi0_pll_out_div_clk dsi0_pll_bit_clk + * | | + * | | + * +---------+ | +----------+ | +----+ + * dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- dsi0pllbyte + * +---------+ | +----------+ | +----+ + * | | + * | | dsi0_pll_by_2_bit_clk + * | | | + * | | +----+ | |\ dsi0_pclk_mux + * | |--| /2 |--o--| \ | + * | | +----+ | \ | +---------+ + * | --------------| |--o--| div_7_4 |-- dsi0pll + * |------------------------------| / +---------+ + * | +-----+ | / + * -----------| /4? |--o----------|/ + * +-----+ | | + * | |dsiclk_sel + * | + * dsi0_pll_post_out_div_clk + */ + +#define DSI_BYTE_PLL_CLK 0 +#define DSI_PIXEL_PLL_CLK 1 +#define NUM_PROVIDED_CLKS 2 + +struct dsi_pll_regs { + u32 pll_prop_gain_rate; + u32 pll_lockdet_rate; + u32 decimal_div_start; + u32 frac_div_start_low; + u32 frac_div_start_mid; + u32 frac_div_start_high; + u32 pll_clock_inverters; + u32 ssc_stepsize_low; + u32 ssc_stepsize_high; + u32 ssc_div_per_low; + u32 ssc_div_per_high; + u32 ssc_adjper_low; + u32 ssc_adjper_high; + u32 ssc_control; +}; + +struct dsi_pll_config { + u32 ref_freq; + bool div_override; + u32 output_div; + bool ignore_frac; + bool disable_prescaler; + bool enable_ssc; + bool ssc_center; + u32 dec_bits; + u32 frac_bits; + u32 lock_timer; + u32 ssc_freq; + u32 ssc_offset; + u32 ssc_adj_per; + u32 thresh_cycles; + u32 refclk_cycles; +}; + +struct pll_10nm_cached_state { + unsigned long vco_rate; + u8 bit_clk_div; + u8 pix_clk_div; + u8 pll_out_div; + u8 pll_mux; +}; + struct dsi_pll_10nm { struct msm_dsi_pll base; @@ -19,7 +91,24 @@ struct dsi_pll_10nm { void __iomem *phy_cmn_mmio; void __iomem *mmio; + u64 vco_ref_clk_rate; + u64 vco_current_rate; + + /* protects REG_DSI_10nm_PHY_CMN_CLK_CFG0 register */ + spinlock_t postdiv_lock; + int vco_delay; + struct dsi_pll_config pll_configuration; + struct dsi_pll_regs reg_setup; + + /* private clocks: */ + struct clk_hw *hws[NUM_DSI_CLOCKS_MAX]; + u32 num_hws; + + /* clock-provider: */ + struct clk_hw_onecell_data *hw_data; + + struct pll_10nm_cached_state cached_state; enum msm_dsi_phy_usecase uc; struct dsi_pll_10nm *slave; @@ -33,6 +122,190 @@ struct dsi_pll_10nm { */ static struct dsi_pll_10nm *pll_10nm_list[DSI_MAX]; +static void dsi_pll_setup_config(struct dsi_pll_10nm *pll) +{ + struct dsi_pll_config *config = &pll->pll_configuration; + + config->ref_freq = pll->vco_ref_clk_rate; + config->output_div = 1; + config->dec_bits = 8; + config->frac_bits = 18; + config->lock_timer = 64; + config->ssc_freq = 31500; + config->ssc_offset = 5000; + config->ssc_adj_per = 2; + config->thresh_cycles = 32; + config->refclk_cycles = 256; + + config->div_override = false; + config->ignore_frac = false; + config->disable_prescaler = false; + + config->enable_ssc = false; + config->ssc_center = 0; +} + +static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll) +{ + struct dsi_pll_config *config = &pll->pll_configuration; + struct dsi_pll_regs *regs = &pll->reg_setup; + u64 fref = pll->vco_ref_clk_rate; + u64 pll_freq; + u64 divider; + u64 dec, dec_multiple; + u32 frac; + u64 multiplier; + + pll_freq = pll->vco_current_rate; + + if (config->disable_prescaler) + divider = fref; + else + divider = fref * 2; + + multiplier = 1 << config->frac_bits; + dec_multiple = div_u64(pll_freq * multiplier, divider); + div_u64_rem(dec_multiple, multiplier, &frac); + + dec = div_u64(dec_multiple, multiplier); + + if (pll_freq <= 1900000000UL) + regs->pll_prop_gain_rate = 8; + else if (pll_freq <= 3000000000UL) + regs->pll_prop_gain_rate = 10; + else + regs->pll_prop_gain_rate = 12; + if (pll_freq < 1100000000UL) + regs->pll_clock_inverters = 8; + else + regs->pll_clock_inverters = 0; + + regs->pll_lockdet_rate = config->lock_timer; + regs->decimal_div_start = dec; + regs->frac_div_start_low = (frac & 0xff); + regs->frac_div_start_mid = (frac & 0xff00) >> 8; + regs->frac_div_start_high = (frac & 0x30000) >> 16; +} + +#define SSC_CENTER BIT(0) +#define SSC_EN BIT(1) + +static void dsi_pll_calc_ssc(struct dsi_pll_10nm *pll) +{ + struct dsi_pll_config *config = &pll->pll_configuration; + struct dsi_pll_regs *regs = &pll->reg_setup; + u32 ssc_per; + u32 ssc_mod; + u64 ssc_step_size; + u64 frac; + + if (!config->enable_ssc) { + DBG("SSC not enabled\n"); + return; + } + + ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - 1; + ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1); + ssc_per -= ssc_mod; + + frac = regs->frac_div_start_low | + (regs->frac_div_start_mid << 8) | + (regs->frac_div_start_high << 16); + ssc_step_size = regs->decimal_div_start; + ssc_step_size *= (1 << config->frac_bits); + ssc_step_size += frac; + ssc_step_size *= config->ssc_offset; + ssc_step_size *= (config->ssc_adj_per + 1); + ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1)); + ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000); + + regs->ssc_div_per_low = ssc_per & 0xFF; + regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8; + regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF); + regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8); + regs->ssc_adjper_low = config->ssc_adj_per & 0xFF; + regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8; + + regs->ssc_control = config->ssc_center ? SSC_CENTER : 0; + + pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n", + regs->decimal_div_start, frac, config->frac_bits); + pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n", + ssc_per, (u32)ssc_step_size, config->ssc_adj_per); +} + +static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll) +{ + void __iomem *base = pll->mmio; + struct dsi_pll_regs *regs = &pll->reg_setup; + + if (pll->pll_configuration.enable_ssc) { + pr_debug("SSC is enabled\n"); + + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1, + regs->ssc_stepsize_low); + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1, + regs->ssc_stepsize_high); + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1, + regs->ssc_div_per_low); + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1, + regs->ssc_div_per_high); + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1, + regs->ssc_adjper_low); + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1, + regs->ssc_adjper_high); + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_CONTROL, + SSC_EN | regs->ssc_control); + } +} + +static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll) +{ + void __iomem *base = pll->mmio; + + pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE, 0x80); + pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03); + pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00); + pll_write(base + REG_DSI_10nm_PHY_PLL_DSM_DIVIDER, 0x00); + pll_write(base + REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e); + pll_write(base + REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40); + pll_write(base + REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE, + 0xba); + pll_write(base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c); + pll_write(base + REG_DSI_10nm_PHY_PLL_OUTDIV, 0x00); + pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE, 0x00); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x08); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1, 0xc0); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, + 0x4c); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80); + pll_write(base + REG_DSI_10nm_PHY_PLL_PFILT, 0x29); + pll_write(base + REG_DSI_10nm_PHY_PLL_IFILT, 0x3f); +} + +static void dsi_pll_commit(struct dsi_pll_10nm *pll) +{ + void __iomem *base = pll->mmio; + struct dsi_pll_regs *reg = &pll->reg_setup; + + pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12); + pll_write(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1, + reg->decimal_div_start); + pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1, + reg->frac_div_start_low); + pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1, + reg->frac_div_start_mid); + pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1, + reg->frac_div_start_high); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1, 0x40); + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY, 0x06); + pll_write(base + REG_DSI_10nm_PHY_PLL_CMODE, 0x10); + pll_write(base + REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS, + reg->pll_clock_inverters); +} + static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { @@ -42,18 +315,192 @@ static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long rate, DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_10nm->id, rate, parent_rate); + pll_10nm->vco_current_rate = rate; + pll_10nm->vco_ref_clk_rate = parent_rate; + + dsi_pll_setup_config(pll_10nm); + + dsi_pll_calc_dec_frac(pll_10nm); + + dsi_pll_calc_ssc(pll_10nm); + + dsi_pll_commit(pll_10nm); + + dsi_pll_config_hzindep_reg(pll_10nm); + + dsi_pll_ssc_commit(pll_10nm); + + /* flush, ensure all register writes are done*/ + wmb(); + return 0; } +static int dsi_pll_10nm_lock_status(struct dsi_pll_10nm *pll) +{ + int rc; + u32 status = 0; + u32 const delay_us = 100; + u32 const timeout_us = 5000; + + rc = readl_poll_timeout_atomic(pll->mmio + + REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE, + status, + ((status & BIT(0)) > 0), + delay_us, + timeout_us); + if (rc) + pr_err("DSI PLL(%d) lock failed, status=0x%08x\n", + pll->id, status); + + return rc; +} + +static void dsi_pll_disable_pll_bias(struct dsi_pll_10nm *pll) +{ + u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0); + + pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0); + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0, + data & ~BIT(5)); + ndelay(250); +} + +static void dsi_pll_enable_pll_bias(struct dsi_pll_10nm *pll) +{ + u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0); + + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0, + data | BIT(5)); + pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0xc0); + ndelay(250); +} + +static void dsi_pll_disable_global_clk(struct dsi_pll_10nm *pll) +{ + u32 data; + + data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1); + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, + data & ~BIT(5)); +} + +static void dsi_pll_enable_global_clk(struct dsi_pll_10nm *pll) +{ + u32 data; + + data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1); + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, + data | BIT(5)); +} + +static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + int rc; + + dsi_pll_enable_pll_bias(pll_10nm); + if (pll_10nm->slave) + dsi_pll_enable_pll_bias(pll_10nm->slave); + + /* Start PLL */ + pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, + 0x01); + + /* + * ensure all PLL configurations are written prior to checking + * for PLL lock. + */ + wmb(); + + /* Check for PLL lock */ + rc = dsi_pll_10nm_lock_status(pll_10nm); + if (rc) { + pr_err("PLL(%d) lock failed\n", pll_10nm->id); + goto error; + } + + pll->pll_on = true; + + dsi_pll_enable_global_clk(pll_10nm); + if (pll_10nm->slave) + dsi_pll_enable_global_clk(pll_10nm->slave); + + pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, + 0x01); + if (pll_10nm->slave) + pll_write(pll_10nm->slave->phy_cmn_mmio + + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x01); + +error: + return rc; +} + +static void dsi_pll_disable_sub(struct dsi_pll_10nm *pll) +{ + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0); + dsi_pll_disable_pll_bias(pll); +} + +static void dsi_pll_10nm_vco_unprepare(struct clk_hw *hw) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + + /* + * To avoid any stray glitches while abruptly powering down the PLL + * make sure to gate the clock using the clock enable bit before + * powering down the PLL + */ + dsi_pll_disable_global_clk(pll_10nm); + pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0); + dsi_pll_disable_sub(pll_10nm); + if (pll_10nm->slave) { + dsi_pll_disable_global_clk(pll_10nm->slave); + dsi_pll_disable_sub(pll_10nm->slave); + } + /* flush, ensure all register writes are done */ + wmb(); + pll->pll_on = false; +} + static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct msm_dsi_pll *pll = hw_clk_to_pll(hw); struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + void __iomem *base = pll_10nm->mmio; + u64 ref_clk = pll_10nm->vco_ref_clk_rate; u64 vco_rate = 0x0; - - DBG("DSI PLL%d returning vco rate = %lu", pll_10nm->id, - (unsigned long)vco_rate); + u64 multiplier; + u32 frac; + u32 dec; + u64 pll_freq, tmp64; + + dec = pll_read(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1); + dec &= 0xff; + + frac = pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1); + frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1) & + 0xff) << 8); + frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1) & + 0x3) << 16); + + /* + * TODO: + * 1. Assumes prescaler is disabled + * 2. Multiplier is 2^18. it should be 2^(num_of_frac_bits) + */ + multiplier = 1 << 18; + pll_freq = dec * (ref_clk * 2); + tmp64 = (ref_clk * 2 * frac); + pll_freq += div_u64(tmp64, multiplier); + + vco_rate = pll_freq; + + DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x", + pll_10nm->id, (unsigned long)vco_rate, dec, frac); return (unsigned long)vco_rate; } @@ -62,8 +509,8 @@ static const struct clk_ops clk_ops_dsi_pll_10nm_vco = { .round_rate = msm_dsi_pll_helper_clk_round_rate, .set_rate = dsi_pll_10nm_vco_set_rate, .recalc_rate = dsi_pll_10nm_vco_recalc_rate, - .prepare = msm_dsi_pll_helper_clk_prepare, - .unprepare = msm_dsi_pll_helper_clk_unprepare, + .prepare = dsi_pll_10nm_vco_prepare, + .unprepare = dsi_pll_10nm_vco_unprepare, }; /* @@ -73,13 +520,45 @@ static const struct clk_ops clk_ops_dsi_pll_10nm_vco = { static void dsi_pll_10nm_save_state(struct msm_dsi_pll *pll) { struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + struct pll_10nm_cached_state *cached = &pll_10nm->cached_state; + void __iomem *phy_base = pll_10nm->phy_cmn_mmio; + u32 cmn_clk_cfg0, cmn_clk_cfg1; - DBG("DSI PLL%d", pll_10nm->id); + cached->pll_out_div = pll_read(pll_10nm->mmio + + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); + cached->pll_out_div &= 0x3; + + cmn_clk_cfg0 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0); + cached->bit_clk_div = cmn_clk_cfg0 & 0xf; + cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4; + + cmn_clk_cfg1 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); + cached->pll_mux = cmn_clk_cfg1 & 0x3; + + DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x", + pll_10nm->id, cached->pll_out_div, cached->bit_clk_div, + cached->pix_clk_div, cached->pll_mux); } static int dsi_pll_10nm_restore_state(struct msm_dsi_pll *pll) { struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + struct pll_10nm_cached_state *cached = &pll_10nm->cached_state; + void __iomem *phy_base = pll_10nm->phy_cmn_mmio; + u32 val; + + val = pll_read(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); + val &= ~0x3; + val |= cached->pll_out_div; + pll_write(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, val); + + pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0, + cached->bit_clk_div | (cached->pix_clk_div << 4)); + + val = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); + val &= ~0x3; + val |= cached->pll_mux; + pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, val); DBG("DSI PLL%d", pll_10nm->id); @@ -90,9 +569,29 @@ static int dsi_pll_10nm_set_usecase(struct msm_dsi_pll *pll, enum msm_dsi_phy_usecase uc) { struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + void __iomem *base = pll_10nm->phy_cmn_mmio; + u32 data = 0x0; /* internal PLL */ DBG("DSI PLL%d", pll_10nm->id); + switch (uc) { + case MSM_DSI_PHY_STANDALONE: + break; + case MSM_DSI_PHY_MASTER: + pll_10nm->slave = pll_10nm_list[(pll_10nm->id + 1) % DSI_MAX]; + break; + case MSM_DSI_PHY_SLAVE: + data = 0x1; /* external PLL */ + break; + default: + return -EINVAL; + } + + /* set PLL src */ + pll_write(base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, (data << 2)); + + pll_10nm->uc = uc; + return 0; } @@ -101,13 +600,14 @@ static int dsi_pll_10nm_get_provider(struct msm_dsi_pll *pll, struct clk **pixel_clk_provider) { struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + struct clk_hw_onecell_data *hw_data = pll_10nm->hw_data; DBG("DSI PLL%d", pll_10nm->id); if (byte_clk_provider) - *byte_clk_provider = NULL; + *byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk; if (pixel_clk_provider) - *pixel_clk_provider = NULL; + *pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk; return 0; } @@ -119,8 +619,151 @@ static void dsi_pll_10nm_destroy(struct msm_dsi_pll *pll) DBG("DSI PLL%d", pll_10nm->id); } +/* + * The post dividers and mux clocks are created using the standard divider and + * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its dividers/mux + * state to follow the master PLL's divider/mux state. Therefore, we don't + * require special clock ops that also configure the slave PLL registers + */ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) { + char clk_name[32], parent[32], vco_name[32]; + char parent2[32], parent3[32], parent4[32]; + struct clk_init_data vco_init = { + .parent_names = (const char *[]){ "xo" }, + .num_parents = 1, + .name = vco_name, + .flags = CLK_IGNORE_UNUSED, + .ops = &clk_ops_dsi_pll_10nm_vco, + }; + struct device *dev = &pll_10nm->pdev->dev; + struct clk_hw **hws = pll_10nm->hws; + struct clk_hw_onecell_data *hw_data; + struct clk_hw *hw; + int num = 0; + int ret; + + DBG("DSI%d", pll_10nm->id); + + hw_data = devm_kzalloc(dev, sizeof(*hw_data) + + NUM_PROVIDED_CLKS * sizeof(struct clk_hw *), + GFP_KERNEL); + if (!hw_data) + return -ENOMEM; + + snprintf(vco_name, 32, "dsi%dvco_clk", pll_10nm->id); + pll_10nm->base.clk_hw.init = &vco_init; + + ret = clk_hw_register(dev, &pll_10nm->base.clk_hw); + if (ret) + return ret; + + hws[num++] = &pll_10nm->base.clk_hw; + + snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); + snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->id); + + hw = clk_hw_register_divider(dev, clk_name, + parent, CLK_SET_RATE_PARENT, + pll_10nm->mmio + + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, + 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + + snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->id); + snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); + + /* BIT CLK: DIV_CTRL_3_0 */ + hw = clk_hw_register_divider(dev, clk_name, parent, + CLK_SET_RATE_PARENT, + pll_10nm->phy_cmn_mmio + + REG_DSI_10nm_PHY_CMN_CLK_CFG0, + 0, 4, CLK_DIVIDER_ONE_BASED, + &pll_10nm->postdiv_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + + snprintf(clk_name, 32, "dsi%dpllbyte", pll_10nm->id); + snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); + + /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */ + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, + CLK_SET_RATE_PARENT, 1, 8); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + hw_data->hws[DSI_BYTE_PLL_CLK] = hw; + + snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); + snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); + + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, + 0, 1, 2); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + + snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); + snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); + + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, + 0, 1, 4); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + + snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->id); + snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); + snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); + snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); + snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); + + hw = clk_hw_register_mux(dev, clk_name, + (const char *[]){ + parent, parent2, parent3, parent4 + }, 4, 0, pll_10nm->phy_cmn_mmio + + REG_DSI_10nm_PHY_CMN_CLK_CFG1, + 0, 2, 0, NULL); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + + snprintf(clk_name, 32, "dsi%dpll", pll_10nm->id); + snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->id); + + /* PIX CLK DIV : DIV_CTRL_7_4*/ + hw = clk_hw_register_divider(dev, clk_name, parent, + 0, pll_10nm->phy_cmn_mmio + + REG_DSI_10nm_PHY_CMN_CLK_CFG0, + 4, 4, CLK_DIVIDER_ONE_BASED, + &pll_10nm->postdiv_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + hws[num++] = hw; + hw_data->hws[DSI_PIXEL_PLL_CLK] = hw; + + pll_10nm->num_hws = num; + + hw_data->num = NUM_PROVIDED_CLKS; + pll_10nm->hw_data = hw_data; + + ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, + pll_10nm->hw_data); + if (ret) { + dev_err(dev, "failed to register clk provider: %d\n", ret); + return ret; + } + return 0; } @@ -172,5 +815,8 @@ struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id) return ERR_PTR(ret); } + /* TODO: Remove this when we have proper display handover support */ + msm_dsi_pll_save_state(pll); + return pll; } -- cgit v1.2.3 From ff73ff19406098f71ec7628b951e0765f1df8128 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 17 Jan 2018 11:35:27 +0530 Subject: drm/msm/dsi: Populate the 10nm PHY funcs Populate the PHY ops with the downstream driver as reference. There are a couple of TODOs which need to be resolved: - The PHY timings are all hardcoded for now. This needs to be replaced with automatic calculations once we get/understand them. - There are some lane configuration registers which use a new representation between physical and logical lane mappings. For now, we've hardcoced them to follow the default mapping (i.e logical 0 -> phy 0, logical 1 -> phy 1 etc). Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c | 199 +++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c index b7545fb63bf5..0af951aaeea1 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c @@ -8,9 +8,208 @@ #include "dsi_phy.h" #include "dsi.xml.h" +static int dsi_phy_hw_v3_0_is_pll_on(struct msm_dsi_phy *phy) +{ + void __iomem *base = phy->base; + u32 data = 0; + + data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL); + mb(); /* make sure read happened */ + + return (data & BIT(0)); +} + +static void dsi_phy_hw_v3_0_config_lpcdrx(struct msm_dsi_phy *phy, bool enable) +{ + void __iomem *lane_base = phy->lane_base; + int phy_lane_0 = 0; /* TODO: Support all lane swap configs */ + + /* + * LPRX and CDRX need to enabled only for physical data lane + * corresponding to the logical data lane 0 + */ + if (enable) + dsi_phy_write(lane_base + + REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0), 0x3); + else + dsi_phy_write(lane_base + + REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0), 0); +} + +static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy) +{ + int i; + u8 tx_dctrl[] = { 0x00, 0x00, 0x00, 0x04, 0x01 }; + void __iomem *lane_base = phy->lane_base; + + /* Strength ctrl settings */ + for (i = 0; i < 5; i++) { + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(i), + 0x55); + /* + * Disable LPRX and CDRX for all lanes. And later on, it will + * be only enabled for the physical data lane corresponding + * to the logical data lane 0 + */ + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPRX_CTRL(i), 0); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_PIN_SWAP(i), 0x0); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_HSTX_STR_CTRL(i), + 0x88); + } + + dsi_phy_hw_v3_0_config_lpcdrx(phy, true); + + /* other settings */ + for (i = 0; i < 5; i++) { + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG0(i), 0x0); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG1(i), 0x0); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG2(i), 0x0); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG3(i), + i == 4 ? 0x80 : 0x0); + dsi_phy_write(lane_base + + REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(i), 0x0); + dsi_phy_write(lane_base + + REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(i), 0x0); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(i), + tx_dctrl[i]); + } + + /* Toggle BIT 0 to release freeze I/0 */ + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x05); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x04); +} + +static int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing, + struct msm_dsi_phy_clk_request *clk_req) +{ + /* + * TODO: These params need to be computed, they're currently hardcoded + * for a 1440x2560@60Hz panel with a byteclk of 100.618 Mhz, and a + * default escape clock of 19.2 Mhz. + */ + + timing->hs_halfbyte_en = 0; + timing->clk_zero = 0x1c; + timing->clk_prepare = 0x07; + timing->clk_trail = 0x07; + timing->hs_exit = 0x23; + timing->hs_zero = 0x21; + timing->hs_prepare = 0x07; + timing->hs_trail = 0x07; + timing->hs_rqst = 0x05; + timing->ta_sure = 0x00; + timing->ta_go = 0x03; + timing->ta_get = 0x04; + + timing->shared_timings.clk_pre = 0x2d; + timing->shared_timings.clk_post = 0x0d; + + return 0; +} + static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, struct msm_dsi_phy_clk_request *clk_req) { + int ret; + u32 status; + u32 const delay_us = 5; + u32 const timeout_us = 1000; + struct msm_dsi_dphy_timing *timing = &phy->timing; + void __iomem *base = phy->base; + u32 data; + + DBG(""); + + if (msm_dsi_dphy_timing_calc_v3(timing, clk_req)) { + dev_err(&phy->pdev->dev, + "%s: D-PHY timing calculation failed\n", __func__); + return -EINVAL; + } + + if (dsi_phy_hw_v3_0_is_pll_on(phy)) + pr_warn("PLL turned on before configuring PHY\n"); + + /* wait for REFGEN READY */ + ret = readl_poll_timeout_atomic(base + REG_DSI_10nm_PHY_CMN_PHY_STATUS, + status, (status & BIT(0)), + delay_us, timeout_us); + if (ret) { + pr_err("Ref gen not ready. Aborting\n"); + return -EINVAL; + } + + /* de-assert digital and pll power down */ + data = BIT(6) | BIT(5); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data); + + /* Assert PLL core reset */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0x00); + + /* turn off resync FIFO */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x00); + + /* Select MS1 byte-clk */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_GLBL_CTRL, 0x10); + + /* Enable LDO */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_VREG_CTRL, 0x59); + + /* Configure PHY lane swap (TODO: we need to calculate this) */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG0, 0x21); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG1, 0x84); + + /* DSI PHY timings */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_0, + timing->hs_halfbyte_en); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_1, + timing->clk_zero); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_2, + timing->clk_prepare); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_3, + timing->clk_trail); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_4, + timing->hs_exit); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_5, + timing->hs_zero); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_6, + timing->hs_prepare); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_7, + timing->hs_trail); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_8, + timing->hs_rqst); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_9, + timing->ta_go | (timing->ta_sure << 3)); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_10, + timing->ta_get); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_11, + 0x00); + + /* Remove power down from all blocks */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, 0x7f); + + /* power up lanes */ + data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_CTRL_0); + + /* TODO: only power up lanes that are used */ + data |= 0x1F; + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data); + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CTRL0, 0x1F); + + /* Select full-rate mode */ + dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_2, 0x40); + + ret = msm_dsi_pll_set_usecase(phy->pll, phy->usecase); + if (ret) { + dev_err(&phy->pdev->dev, "%s: set pll usecase failed, %d\n", + __func__, ret); + return ret; + } + + /* DSI lane settings */ + dsi_phy_hw_v3_0_lane_settings(phy); + + DBG("DSI%d PHY enabled", phy->id); + return 0; } -- cgit v1.2.3 From 29a1157ceba2bf885479d6dcd2933a6b0778266b Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 17 Jan 2018 15:04:42 +0530 Subject: drm/msm/dsi: Use msm_clk_get in dsi_get_config We try to get the interface clock in dsi_get_config early during DSI's component bind. Try getting both the "iface" and "iface_clk" clock name variants so that we are compatible with both new and legacy DT. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_host.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 0f7324a686ca..7611fe014036 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -214,7 +214,7 @@ static const struct msm_dsi_cfg_handler *dsi_get_config( goto exit; } - ahb_clk = clk_get(dev, "iface_clk"); + ahb_clk = msm_clk_get(msm_host->pdev, "iface"); if (IS_ERR(ahb_clk)) { pr_err("%s: cannot get interface clock\n", __func__); goto put_gdsc; @@ -225,7 +225,7 @@ static const struct msm_dsi_cfg_handler *dsi_get_config( ret = regulator_enable(gdsc_reg); if (ret) { pr_err("%s: unable to enable gdsc\n", __func__); - goto put_clk; + goto put_gdsc; } ret = clk_prepare_enable(ahb_clk); @@ -249,8 +249,6 @@ disable_clks: disable_gdsc: regulator_disable(gdsc_reg); pm_runtime_put_sync(dev); -put_clk: - clk_put(ahb_clk); put_gdsc: regulator_put(gdsc_reg); exit: -- cgit v1.2.3 From 02f7a6ca1692ffe1012abd512b8a88ba9a925095 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 17 Jan 2018 15:04:43 +0530 Subject: drm/msm/dsi: Add SDM845 in dsi_cfg SDM845 contains 2 DSI6G v2.2.1 host controllers. Add them in dsi_cfg. Cc: Jordan Crouse Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_cfg.c | 19 +++++++++++++++++++ drivers/gpu/drm/msm/dsi/dsi_cfg.h | 1 + 2 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index 65c1dfbbe019..0327bb54b01b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -118,6 +118,24 @@ static const struct msm_dsi_config msm8996_dsi_cfg = { .num_dsi = 2, }; +static const char * const dsi_sdm845_bus_clk_names[] = { + "iface", "bus", +}; + +static const struct msm_dsi_config sdm845_dsi_cfg = { + .io_offset = DSI_6G_REG_SHIFT, + .reg_cfg = { + .num = 1, + .regs = { + {"vdda", 21800, 4 }, /* 1.2 V */ + }, + }, + .bus_clk_names = dsi_sdm845_bus_clk_names, + .num_bus_clks = ARRAY_SIZE(dsi_sdm845_bus_clk_names), + .io_start = { 0xae94000, 0xae96000 }, + .num_dsi = 2, +}; + static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { {MSM_DSI_VER_MAJOR_V2, MSM_DSI_V2_VER_MINOR_8064, &apq8064_dsi_cfg}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_0, @@ -131,6 +149,7 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3, &msm8994_dsi_cfg}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3_1, &msm8916_dsi_cfg}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_1, &msm8996_dsi_cfg}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, &sdm845_dsi_cfg}, }; const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor) diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h index 00a5da2663c6..9cfdcf1c95d5 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -25,6 +25,7 @@ #define MSM_DSI_6G_VER_MINOR_V1_3 0x10030000 #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 +#define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 #define MSM_DSI_V2_VER_MINOR_8064 0x0 -- cgit v1.2.3 From c1d97083cd48a2b3f4382f0122889d1d73661b2e Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 17 Jan 2018 15:04:44 +0530 Subject: drm/msm/dsi: Add byte_intf_clk DSI6G v2.0+ blocks have a new clock input to them called byte_intf_clk. It's rate is to be set as byte_clk / 2. Within the clock controller (CC) subsystem, this clock is a child/descendant of the byte_clk. Set it up as an optional clock in the DSI host driver. Make sure that we enable/set its rate only after we configure byte_clk. This is required for the ancestor clocks in the CC to be configured correctly. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_host.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 7611fe014036..f675975c2655 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -115,6 +115,7 @@ struct msm_dsi_host { struct clk *pixel_clk; struct clk *byte_clk_src; struct clk *pixel_clk_src; + struct clk *byte_intf_clk; u32 byte_clk_rate; u32 esc_clk_rate; @@ -377,6 +378,14 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host) goto exit; } + msm_host->byte_intf_clk = msm_clk_get(pdev, "byte_intf"); + if (IS_ERR(msm_host->byte_intf_clk)) { + ret = PTR_ERR(msm_host->byte_intf_clk); + pr_debug("%s: can't find byte_intf clock. ret=%d\n", + __func__, ret); + msm_host->byte_intf_clk = NULL; + } + msm_host->byte_clk_src = clk_get_parent(msm_host->byte_clk); if (!msm_host->byte_clk_src) { ret = -ENODEV; @@ -502,6 +511,16 @@ static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) goto error; } + if (msm_host->byte_intf_clk) { + ret = clk_set_rate(msm_host->byte_intf_clk, + msm_host->byte_clk_rate / 2); + if (ret) { + pr_err("%s: Failed to set rate byte intf clk, %d\n", + __func__, ret); + goto error; + } + } + ret = clk_prepare_enable(msm_host->esc_clk); if (ret) { pr_err("%s: Failed to enable dsi esc clk\n", __func__); @@ -520,8 +539,19 @@ static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) goto pixel_clk_err; } + if (msm_host->byte_intf_clk) { + ret = clk_prepare_enable(msm_host->byte_intf_clk); + if (ret) { + pr_err("%s: Failed to enable byte intf clk\n", + __func__); + goto byte_intf_clk_err; + } + } + return 0; +byte_intf_clk_err: + clk_disable_unprepare(msm_host->pixel_clk); pixel_clk_err: clk_disable_unprepare(msm_host->byte_clk); byte_clk_err: @@ -615,6 +645,8 @@ static void dsi_link_clk_disable(struct msm_dsi_host *msm_host) if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { clk_disable_unprepare(msm_host->esc_clk); clk_disable_unprepare(msm_host->pixel_clk); + if (msm_host->byte_intf_clk) + clk_disable_unprepare(msm_host->byte_intf_clk); clk_disable_unprepare(msm_host->byte_clk); } else { clk_disable_unprepare(msm_host->pixel_clk); -- cgit v1.2.3 From 52a8988de97f5e7370d15261e81613779e7f057d Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Wed, 17 Jan 2018 18:55:47 +0000 Subject: drm/msm/mdp5: Fix trailing semicolon The trailing semicolon is an empty statement that does no operation. Removing it since it doesn't do anything. Signed-off-by: Luis de Bethencourt Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 3e9bba4d6624..6d8e3a9a6fc0 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -680,7 +680,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) } else { dev_info(&pdev->dev, "no iommu, fallback to phys contig buffers for scanout\n"); - aspace = NULL;; + aspace = NULL; } pm_runtime_put_sync(&pdev->dev); -- cgit v1.2.3 From cccb9723821806b5ec167d7910c6e82622f4a305 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Mon, 22 Jan 2018 08:34:05 +0100 Subject: drm/msm/hdmi: fix semicolon.cocci warnings Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci CC: Laurent Pinchart Signed-off-by: Fengguang Wu Signed-off-by: Julia Lawall Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c index 6e767979aab3..3656155e3793 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c @@ -769,7 +769,7 @@ static int msm_hdmi_hdcp_auth_part1_key_exchange(struct hdmi_hdcp_ctrl *hdcp_ctr if (rc) { pr_err("%s: wait key and an ready failed\n", __func__); return rc; - }; + } /* Read BCAPS and send to HDCP engine */ rc = msm_hdmi_hdcp_recv_bcaps(hdcp_ctrl); -- cgit v1.2.3 From dc9a9b32053efea0a2610be98814519ec59570b4 Mon Sep 17 00:00:00 2001 From: Steve Kowalik Date: Fri, 26 Jan 2018 14:55:54 +1100 Subject: drm/msm: Replace gem_object deprecated functions drm_gem_object_{reference,unreference,unreference_unlocked} are deprecated functions, and merely alias to the get/put functions. Switch to the new names. Signed-off-by: Steve Kowalik Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 6 +++--- drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c | 6 +++--- drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 2 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 2 +- drivers/gpu/drm/msm/msm_drv.c | 8 ++++---- drivers/gpu/drm/msm/msm_fb.c | 6 +++--- drivers/gpu/drm/msm/msm_gem.c | 12 ++++++------ drivers/gpu/drm/msm/msm_gpu.c | 8 ++++---- drivers/gpu/drm/msm/msm_ringbuffer.c | 2 +- 9 files changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index fa08b4897a56..795fe11a9371 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -858,19 +858,19 @@ static void a5xx_destroy(struct msm_gpu *gpu) if (a5xx_gpu->pm4_bo) { if (a5xx_gpu->pm4_iova) msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace); - drm_gem_object_unreference_unlocked(a5xx_gpu->pm4_bo); + drm_gem_object_put_unlocked(a5xx_gpu->pm4_bo); } if (a5xx_gpu->pfp_bo) { if (a5xx_gpu->pfp_iova) msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace); - drm_gem_object_unreference_unlocked(a5xx_gpu->pfp_bo); + drm_gem_object_put_unlocked(a5xx_gpu->pfp_bo); } if (a5xx_gpu->gpmu_bo) { if (a5xx_gpu->gpmu_iova) msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->aspace); - drm_gem_object_unreference_unlocked(a5xx_gpu->gpmu_bo); + drm_gem_object_put_unlocked(a5xx_gpu->gpmu_bo); } adreno_gpu_cleanup(adreno_gpu); diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index 14bd3bd3e040..6e5e1aa54ce1 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -129,7 +129,7 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val) struct msm_kms *kms = &mdp4_kms->base.base; msm_gem_put_iova(val, kms->aspace); - drm_gem_object_unreference_unlocked(val); + drm_gem_object_put_unlocked(val); } static void mdp4_crtc_destroy(struct drm_crtc *crtc) @@ -382,7 +382,7 @@ static void update_cursor(struct drm_crtc *crtc) if (next_bo) { /* take a obj ref + iova ref when we start scanning out: */ - drm_gem_object_reference(next_bo); + drm_gem_object_get(next_bo); msm_gem_get_iova(next_bo, kms->aspace, &iova); /* enable cursor: */ @@ -467,7 +467,7 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc, return 0; fail: - drm_gem_object_unreference_unlocked(cursor_bo); + drm_gem_object_put_unlocked(cursor_bo); return ret; } diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index f7f087419ed8..4b646bf9c214 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -164,7 +164,7 @@ static void mdp4_destroy(struct msm_kms *kms) if (mdp4_kms->blank_cursor_iova) msm_gem_put_iova(mdp4_kms->blank_cursor_bo, kms->aspace); - drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo); + drm_gem_object_put_unlocked(mdp4_kms->blank_cursor_bo); if (aspace) { aspace->mmu->funcs->detach(aspace->mmu, diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index e414850dbbda..8c5ed0b59e46 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -170,7 +170,7 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val) struct msm_kms *kms = &mdp5_kms->base.base; msm_gem_put_iova(val, kms->aspace); - drm_gem_object_unreference_unlocked(val); + drm_gem_object_put_unlocked(val); } static void mdp5_crtc_destroy(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index d90ef1d78a1b..30cd514d8f7c 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -660,7 +660,7 @@ static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, ret = msm_gem_cpu_prep(obj, args->op, &timeout); - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ret; } @@ -678,7 +678,7 @@ static int msm_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, ret = msm_gem_cpu_fini(obj); - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ret; } @@ -718,7 +718,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, args->offset = msm_gem_mmap_offset(obj); } - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ret; } @@ -783,7 +783,7 @@ static int msm_ioctl_gem_madvise(struct drm_device *dev, void *data, ret = 0; } - drm_gem_object_unreference(obj); + drm_gem_object_put(obj); unlock: mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index fc175e724ad6..0e0c87252ab0 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -53,7 +53,7 @@ static void msm_framebuffer_destroy(struct drm_framebuffer *fb) for (i = 0; i < n; i++) { struct drm_gem_object *bo = msm_fb->planes[i]; - drm_gem_object_unreference_unlocked(bo); + drm_gem_object_put_unlocked(bo); } kfree(msm_fb); @@ -160,7 +160,7 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, out_unref: for (i = 0; i < n; i++) - drm_gem_object_unreference_unlocked(bos[i]); + drm_gem_object_put_unlocked(bos[i]); return ERR_PTR(ret); } @@ -274,7 +274,7 @@ msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format /* note: if fb creation failed, we can't rely on fb destroy * to unref the bo: */ - drm_gem_object_unreference_unlocked(bo); + drm_gem_object_put_unlocked(bo); return ERR_CAST(fb); } diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 07376de9ff4c..0e5073af3913 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -470,7 +470,7 @@ int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, *offset = msm_gem_mmap_offset(obj); - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); fail: return ret; @@ -854,7 +854,7 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, ret = drm_gem_handle_create(file, obj, handle); /* drop reference from allocate - handle holds it now */ - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ret; } @@ -974,7 +974,7 @@ static struct drm_gem_object *_msm_gem_new(struct drm_device *dev, return obj; fail: - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ERR_PTR(ret); } @@ -1034,7 +1034,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, return obj; fail: - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ERR_PTR(ret); } @@ -1052,7 +1052,7 @@ static void *_msm_gem_kernel_new(struct drm_device *dev, uint32_t size, if (iova) { ret = msm_gem_get_iova(obj, aspace, iova); if (ret) { - drm_gem_object_unreference(obj); + drm_gem_object_put(obj); return ERR_PTR(ret); } } @@ -1060,7 +1060,7 @@ static void *_msm_gem_kernel_new(struct drm_device *dev, uint32_t size, vaddr = msm_gem_get_vaddr(obj); if (IS_ERR(vaddr)) { msm_gem_put_iova(obj, aspace); - drm_gem_object_unreference(obj); + drm_gem_object_put(obj); return ERR_CAST(vaddr); } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index bd376f9e18a7..8078e4d52fe0 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -552,7 +552,7 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) /* move to inactive: */ msm_gem_move_to_inactive(&msm_obj->base); msm_gem_put_iova(&msm_obj->base, gpu->aspace); - drm_gem_object_unreference(&msm_obj->base); + drm_gem_object_put(&msm_obj->base); } pm_runtime_mark_last_busy(&gpu->pdev->dev); @@ -634,7 +634,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, WARN_ON(is_active(msm_obj) && (msm_obj->gpu != gpu)); /* submit takes a reference to the bo and iova until retired: */ - drm_gem_object_reference(&msm_obj->base); + drm_gem_object_get(&msm_obj->base); msm_gem_get_iova(&msm_obj->base, submit->gpu->aspace, &iova); @@ -865,7 +865,7 @@ fail: if (gpu->memptrs_bo) { msm_gem_put_vaddr(gpu->memptrs_bo); msm_gem_put_iova(gpu->memptrs_bo, gpu->aspace); - drm_gem_object_unreference_unlocked(gpu->memptrs_bo); + drm_gem_object_put_unlocked(gpu->memptrs_bo); } platform_set_drvdata(pdev, NULL); @@ -888,7 +888,7 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) if (gpu->memptrs_bo) { msm_gem_put_vaddr(gpu->memptrs_bo); msm_gem_put_iova(gpu->memptrs_bo, gpu->aspace); - drm_gem_object_unreference_unlocked(gpu->memptrs_bo); + drm_gem_object_put_unlocked(gpu->memptrs_bo); } if (!IS_ERR_OR_NULL(gpu->aspace)) { diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index 6ca98da35f63..6f5295b3f2f6 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -76,7 +76,7 @@ void msm_ringbuffer_destroy(struct msm_ringbuffer *ring) if (ring->bo) { msm_gem_put_iova(ring->bo, ring->gpu->aspace); msm_gem_put_vaddr(ring->bo); - drm_gem_object_unreference_unlocked(ring->bo); + drm_gem_object_put_unlocked(ring->bo); } kfree(ring); } -- cgit v1.2.3 From 9d20a0e6a8f4edf37d75f3bca41f99f52a440c22 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Mon, 22 Jan 2018 11:10:45 -0700 Subject: drm/msm/gpu: Set number of clocks to 0 if the list allocation fails If we fail to allocate gpu->grp_clks reset the number of available clocks to zero to avoid referencing the missing array later. Signed-off-by: Jordan Crouse Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gpu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 8078e4d52fe0..1c09acfb4028 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -682,8 +682,10 @@ static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu) gpu->grp_clks = devm_kcalloc(dev, sizeof(struct clk *), gpu->nr_clocks, GFP_KERNEL); - if (!gpu->grp_clks) + if (!gpu->grp_clks) { + gpu->nr_clocks = 0; return -ENOMEM; + } of_property_for_each_string(dev->of_node, "clock-names", prop, name) { gpu->grp_clks[i] = get_clock(dev, name); -- cgit v1.2.3 From edf5ceac316a95539a0b063d60d03f3226046f10 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Mon, 22 Jan 2018 11:10:46 -0700 Subject: drm/msm: Pass the correct aperture end to drm_mm_init drm_mm_init() takes the start and length of the intended virtual memory address region but the msm code is passing the end of the region instead. That would work out if the region started at 0 but it doesn't so the top of the region sneaks above the 32 bit boundary which won't work because the driver doesn't support 64 bit addresses for the GPU yet. Signed-off-by: Jordan Crouse Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem_vma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index d34e331554f3..ffbec224551b 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -96,6 +96,8 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, const char *name) { struct msm_gem_address_space *aspace; + u64 size = domain->geometry.aperture_end - + domain->geometry.aperture_start; aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); if (!aspace) @@ -106,7 +108,7 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, aspace->mmu = msm_iommu_new(dev, domain); drm_mm_init(&aspace->mm, (domain->geometry.aperture_start >> PAGE_SHIFT), - (domain->geometry.aperture_end >> PAGE_SHIFT) - 1); + size >> PAGE_SHIFT); kref_init(&aspace->kref); -- cgit v1.2.3 From f306953fdb1145020dd2a838698792d686feb2e3 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Mon, 22 Jan 2018 11:10:47 -0700 Subject: drm/msm/adreno: Rename gpmufw to powerfw The power management device on the a5xx cores is known as the GPMU (Graphics Power Management Unit). On a6xx cores the device was expanded and renamed as the GMU (Graphics Management Unit). Rename the 'gpmufw' name struct adreno_info as 'powerfw' to avoid confusion. Signed-off-by: Jordan Crouse Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a5xx_power.c | 2 +- drivers/gpu/drm/msm/adreno/adreno_device.c | 2 +- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/adreno/a5xx_power.c b/drivers/gpu/drm/msm/adreno/a5xx_power.c index 4e4d965fd9ab..6630e6c0c8be 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_power.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_power.c @@ -270,7 +270,7 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) return; /* Get the firmware */ - fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->gpmufw); + fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->powerfw); if (IS_ERR(fw)) { DRM_ERROR("%s: Could not get GPMU firmware. GPMU will not be active\n", gpu->name); diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 6263cb906b3c..d64ceeb0d6f0 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -84,7 +84,7 @@ static const struct adreno_info gpulist[] = { .quirks = ADRENO_QUIRK_TWO_PASS_USE_WFI | ADRENO_QUIRK_FAULT_DETECT_MASK, .init = a5xx_gpu_init, - .gpmufw = "a530v3_gpmu.fw2", + .powerfw = "a530v3_gpmu.fw2", .zapfw = "a530_zap.mdt", }, }; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 8d3d0a924908..0a869bb8ee9d 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -73,7 +73,7 @@ struct adreno_info { uint32_t revn; const char *name; const char *pm4fw, *pfpfw; - const char *gpmufw; + const char *powerfw; uint32_t gmem; enum adreno_quirks quirks; struct msm_gpu *(*init)(struct drm_device *dev); -- cgit v1.2.3 From c5e3548c295ace44c2ec8c3af1c10e82bc47f9b3 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Thu, 1 Feb 2018 12:15:16 -0700 Subject: drm/msm/adreno: Define a list of firmware files to load per target The number and type of firmware files required differs for each target. Instead of using a fixed struct member for each possible firmware file use a generic list of files that should be loaded on boot. Use some semi-target specific enums to help each target find the appropriate firmware(s) that it needs to load. Signed-off-by: Jordan Crouse Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 8 +++--- drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 8 +++--- drivers/gpu/drm/msm/adreno/a5xx_debugfs.c | 13 ++++----- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 8 +++--- drivers/gpu/drm/msm/adreno/a5xx_power.c | 26 +++++------------- drivers/gpu/drm/msm/adreno/adreno_device.c | 44 ++++++++++++++++++++---------- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 33 ++++++++++++---------- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 12 ++++++-- 8 files changed, 80 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 4baef2738178..1dd84d3489ae 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -256,8 +256,8 @@ static int a3xx_hw_init(struct msm_gpu *gpu) */ /* Load PM4: */ - ptr = (uint32_t *)(adreno_gpu->pm4->data); - len = adreno_gpu->pm4->size / 4; + ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data); + len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4; DBG("loading PM4 ucode version: %x", ptr[1]); gpu_write(gpu, REG_AXXX_CP_DEBUG, @@ -268,8 +268,8 @@ static int a3xx_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]); /* Load PFP: */ - ptr = (uint32_t *)(adreno_gpu->pfp->data); - len = adreno_gpu->pfp->size / 4; + ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data); + len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4; DBG("loading PFP ucode version: %x", ptr[5]); gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0); diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 8199a4b9f2fa..2884b1b1660c 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -274,16 +274,16 @@ static int a4xx_hw_init(struct msm_gpu *gpu) return ret; /* Load PM4: */ - ptr = (uint32_t *)(adreno_gpu->pm4->data); - len = adreno_gpu->pm4->size / 4; + ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data); + len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4; DBG("loading PM4 ucode version: %u", ptr[0]); gpu_write(gpu, REG_A4XX_CP_ME_RAM_WADDR, 0); for (i = 1; i < len; i++) gpu_write(gpu, REG_A4XX_CP_ME_RAM_DATA, ptr[i]); /* Load PFP: */ - ptr = (uint32_t *)(adreno_gpu->pfp->data); - len = adreno_gpu->pfp->size / 4; + ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data); + len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4; DBG("loading PFP ucode version: %u", ptr[0]); gpu_write(gpu, REG_A4XX_CP_PFP_UCODE_ADDR, 0); diff --git a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c index cef09780ef17..6b279414b9c0 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c @@ -123,15 +123,12 @@ reset_set(void *data, u64 val) mutex_lock(&dev->struct_mutex); - if (adreno_gpu->pm4) { - release_firmware(adreno_gpu->pm4); - adreno_gpu->pm4 = NULL; - } + release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]); + adreno_gpu->fw[ADRENO_FW_PM4] = NULL; + + release_firmware(adreno_gpu->fw[ADRENO_FW_PFP]); + adreno_gpu->fw[ADRENO_FW_PFP] = NULL; - if (adreno_gpu->pfp) { - release_firmware(adreno_gpu->pfp); - adreno_gpu->pfp = NULL; - } if (a5xx_gpu->pm4_bo) { if (a5xx_gpu->pm4_iova) msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace); diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 795fe11a9371..517e19c3f9ed 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -523,8 +523,8 @@ static int a5xx_ucode_init(struct msm_gpu *gpu) int ret; if (!a5xx_gpu->pm4_bo) { - a5xx_gpu->pm4_bo = a5xx_ucode_load_bo(gpu, adreno_gpu->pm4, - &a5xx_gpu->pm4_iova); + a5xx_gpu->pm4_bo = a5xx_ucode_load_bo(gpu, + adreno_gpu->fw[ADRENO_FW_PM4], &a5xx_gpu->pm4_iova); if (IS_ERR(a5xx_gpu->pm4_bo)) { ret = PTR_ERR(a5xx_gpu->pm4_bo); @@ -536,8 +536,8 @@ static int a5xx_ucode_init(struct msm_gpu *gpu) } if (!a5xx_gpu->pfp_bo) { - a5xx_gpu->pfp_bo = a5xx_ucode_load_bo(gpu, adreno_gpu->pfp, - &a5xx_gpu->pfp_iova); + a5xx_gpu->pfp_bo = a5xx_ucode_load_bo(gpu, + adreno_gpu->fw[ADRENO_FW_PFP], &a5xx_gpu->pfp_iova); if (IS_ERR(a5xx_gpu->pfp_bo)) { ret = PTR_ERR(a5xx_gpu->pfp_bo); diff --git a/drivers/gpu/drm/msm/adreno/a5xx_power.c b/drivers/gpu/drm/msm/adreno/a5xx_power.c index 6630e6c0c8be..e9c0e56dbec0 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_power.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_power.c @@ -261,7 +261,6 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); struct drm_device *drm = gpu->dev; - const struct firmware *fw; uint32_t dwords = 0, offset = 0, bosize; unsigned int *data, *ptr, *cmds; unsigned int cmds_size; @@ -269,15 +268,7 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) if (a5xx_gpu->gpmu_bo) return; - /* Get the firmware */ - fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->powerfw); - if (IS_ERR(fw)) { - DRM_ERROR("%s: Could not get GPMU firmware. GPMU will not be active\n", - gpu->name); - return; - } - - data = (unsigned int *) fw->data; + data = (unsigned int *) adreno_gpu->fw[ADRENO_FW_GPMU]->data; /* * The first dword is the size of the remaining data in dwords. Use it @@ -285,12 +276,14 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) * the firmware that we read */ - if (fw->size < 8 || (data[0] < 2) || (data[0] >= (fw->size >> 2))) - goto out; + if (adreno_gpu->fw[ADRENO_FW_GPMU]->size < 8 || + (data[0] < 2) || (data[0] >= + (adreno_gpu->fw[ADRENO_FW_GPMU]->size >> 2))) + return; /* The second dword is an ID - look for 2 (GPMU_FIRMWARE_ID) */ if (data[1] != 2) - goto out; + return; cmds = data + data[2] + 3; cmds_size = data[0] - data[2] - 2; @@ -325,8 +318,7 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu) msm_gem_put_vaddr(a5xx_gpu->gpmu_bo); a5xx_gpu->gpmu_dwords = dwords; - goto out; - + return; err: if (a5xx_gpu->gpmu_iova) msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->aspace); @@ -336,8 +328,4 @@ err: a5xx_gpu->gpmu_bo = NULL; a5xx_gpu->gpmu_iova = 0; a5xx_gpu->gpmu_dwords = 0; - -out: - /* No need to keep that firmware laying around anymore */ - release_firmware(fw); } diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index d64ceeb0d6f0..f07d3ec7d77b 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -30,61 +30,75 @@ static const struct adreno_info gpulist[] = { .rev = ADRENO_REV(3, 0, 5, ANY_ID), .revn = 305, .name = "A305", - .pm4fw = "a300_pm4.fw", - .pfpfw = "a300_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a300_pm4.fw", + [ADRENO_FW_PFP] = "a300_pfp.fw", + }, .gmem = SZ_256K, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(3, 0, 6, 0), .revn = 307, /* because a305c is revn==306 */ .name = "A306", - .pm4fw = "a300_pm4.fw", - .pfpfw = "a300_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a300_pm4.fw", + [ADRENO_FW_PFP] = "a300_pfp.fw", + }, .gmem = SZ_128K, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(3, 2, ANY_ID, ANY_ID), .revn = 320, .name = "A320", - .pm4fw = "a300_pm4.fw", - .pfpfw = "a300_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a300_pm4.fw", + [ADRENO_FW_PFP] = "a300_pfp.fw", + }, .gmem = SZ_512K, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(3, 3, 0, ANY_ID), .revn = 330, .name = "A330", - .pm4fw = "a330_pm4.fw", - .pfpfw = "a330_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a330_pm4.fw", + [ADRENO_FW_PFP] = "a330_pfp.fw", + }, .gmem = SZ_1M, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(4, 2, 0, ANY_ID), .revn = 420, .name = "A420", - .pm4fw = "a420_pm4.fw", - .pfpfw = "a420_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a420_pm4.fw", + [ADRENO_FW_PFP] = "a420_pfp.fw", + }, .gmem = (SZ_1M + SZ_512K), .init = a4xx_gpu_init, }, { .rev = ADRENO_REV(4, 3, 0, ANY_ID), .revn = 430, .name = "A430", - .pm4fw = "a420_pm4.fw", - .pfpfw = "a420_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a420_pm4.fw", + [ADRENO_FW_PFP] = "a420_pfp.fw", + }, .gmem = (SZ_1M + SZ_512K), .init = a4xx_gpu_init, }, { .rev = ADRENO_REV(5, 3, 0, 2), .revn = 530, .name = "A530", - .pm4fw = "a530_pm4.fw", - .pfpfw = "a530_pfp.fw", + .fw = { + [ADRENO_FW_PM4] = "a530_pm4.fw", + [ADRENO_FW_PFP] = "a530_pfp.fw", + [ADRENO_FW_GPMU] = "a530v3_gpmu.fw2", + }, .gmem = SZ_1M, .quirks = ADRENO_QUIRK_TWO_PASS_USE_WFI | ADRENO_QUIRK_FAULT_DETECT_MASK, .init = a5xx_gpu_init, - .powerfw = "a530v3_gpmu.fw2", .zapfw = "a530_zap.mdt", }, }; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index de63ff26a062..4a8ee5ec571e 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -140,23 +140,24 @@ adreno_request_fw(struct adreno_gpu *adreno_gpu, const char *fwname) static int adreno_load_fw(struct adreno_gpu *adreno_gpu) { - const struct firmware *fw; + int i; - if (adreno_gpu->pm4) - return 0; + for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++) { + const struct firmware *fw; - fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->pm4fw); - if (IS_ERR(fw)) - return PTR_ERR(fw); - adreno_gpu->pm4 = fw; + if (!adreno_gpu->info->fw[i]) + continue; - fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->pfpfw); - if (IS_ERR(fw)) { - release_firmware(adreno_gpu->pm4); - adreno_gpu->pm4 = NULL; - return PTR_ERR(fw); + /* Skip if the firmware has already been loaded */ + if (adreno_gpu->fw[i]) + continue; + + fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->fw[i]); + if (IS_ERR(fw)) + return PTR_ERR(fw); + + adreno_gpu->fw[i] = fw; } - adreno_gpu->pfp = fw; return 0; } @@ -569,8 +570,10 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu) { - release_firmware(adreno_gpu->pm4); - release_firmware(adreno_gpu->pfp); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++) + release_firmware(adreno_gpu->fw[i]); msm_gpu_cleanup(&adreno_gpu->base); } diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 0a869bb8ee9d..499092af81a2 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -48,6 +48,13 @@ enum adreno_regs { REG_ADRENO_REGISTER_MAX, }; +enum { + ADRENO_FW_PM4 = 0, + ADRENO_FW_PFP = 1, + ADRENO_FW_GPMU = 2, + ADRENO_FW_MAX, +}; + enum adreno_quirks { ADRENO_QUIRK_TWO_PASS_USE_WFI = 1, ADRENO_QUIRK_FAULT_DETECT_MASK = 2, @@ -72,8 +79,7 @@ struct adreno_info { struct adreno_rev rev; uint32_t revn; const char *name; - const char *pm4fw, *pfpfw; - const char *powerfw; + const char *fw[ADRENO_FW_MAX]; uint32_t gmem; enum adreno_quirks quirks; struct msm_gpu *(*init)(struct drm_device *dev); @@ -115,7 +121,7 @@ struct adreno_gpu { } fwloc; /* firmware: */ - const struct firmware *pm4, *pfp; + const struct firmware *fw[ADRENO_FW_MAX]; /* * Register offsets are different between some GPUs. -- cgit v1.2.3 From 9de43e79c10149d29c77ff2c3dae048d1db9cbce Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Thu, 1 Feb 2018 12:15:17 -0700 Subject: drm/msm/adreno: Use generic function to load firmware to a buffer object Move a5xx specific code to load firmware into a buffer object to the generic Adreno code. This will come in useful for future targets. Signed-off-by: Jordan Crouse Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 23 ++--------------------- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 19 +++++++++++++++++++ drivers/gpu/drm/msm/adreno/adreno_gpu.h | 2 ++ 3 files changed, 23 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 517e19c3f9ed..a4f68affc13b 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -497,25 +497,6 @@ static int a5xx_preempt_start(struct msm_gpu *gpu) return a5xx_idle(gpu, ring) ? 0 : -EINVAL; } - -static struct drm_gem_object *a5xx_ucode_load_bo(struct msm_gpu *gpu, - const struct firmware *fw, u64 *iova) -{ - struct drm_gem_object *bo; - void *ptr; - - ptr = msm_gem_kernel_new_locked(gpu->dev, fw->size - 4, - MSM_BO_UNCACHED | MSM_BO_GPU_READONLY, gpu->aspace, &bo, iova); - - if (IS_ERR(ptr)) - return ERR_CAST(ptr); - - memcpy(ptr, &fw->data[4], fw->size - 4); - - msm_gem_put_vaddr(bo); - return bo; -} - static int a5xx_ucode_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); @@ -523,7 +504,7 @@ static int a5xx_ucode_init(struct msm_gpu *gpu) int ret; if (!a5xx_gpu->pm4_bo) { - a5xx_gpu->pm4_bo = a5xx_ucode_load_bo(gpu, + a5xx_gpu->pm4_bo = adreno_fw_create_bo(gpu, adreno_gpu->fw[ADRENO_FW_PM4], &a5xx_gpu->pm4_iova); if (IS_ERR(a5xx_gpu->pm4_bo)) { @@ -536,7 +517,7 @@ static int a5xx_ucode_init(struct msm_gpu *gpu) } if (!a5xx_gpu->pfp_bo) { - a5xx_gpu->pfp_bo = a5xx_ucode_load_bo(gpu, + a5xx_gpu->pfp_bo = adreno_fw_create_bo(gpu, adreno_gpu->fw[ADRENO_FW_PFP], &a5xx_gpu->pfp_iova); if (IS_ERR(a5xx_gpu->pfp_bo)) { diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 4a8ee5ec571e..87133c6c6f91 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -162,6 +162,25 @@ static int adreno_load_fw(struct adreno_gpu *adreno_gpu) return 0; } +struct drm_gem_object *adreno_fw_create_bo(struct msm_gpu *gpu, + const struct firmware *fw, u64 *iova) +{ + struct drm_gem_object *bo; + void *ptr; + + ptr = msm_gem_kernel_new_locked(gpu->dev, fw->size - 4, + MSM_BO_UNCACHED | MSM_BO_GPU_READONLY, gpu->aspace, &bo, iova); + + if (IS_ERR(ptr)) + return ERR_CAST(ptr); + + memcpy(ptr, &fw->data[4], fw->size - 4); + + msm_gem_put_vaddr(bo); + + return bo; +} + int adreno_hw_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 499092af81a2..d6b0e7b813f4 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -206,6 +206,8 @@ static inline int adreno_is_a530(struct adreno_gpu *gpu) int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); const struct firmware *adreno_request_fw(struct adreno_gpu *adreno_gpu, const char *fwname); +struct drm_gem_object *adreno_fw_create_bo(struct msm_gpu *gpu, + const struct firmware *fw, u64 *iova); int adreno_hw_init(struct msm_gpu *gpu); void adreno_recover(struct msm_gpu *gpu); void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, -- cgit v1.2.3 From fb48989edb628342af0fad478174ae30b2e1e23a Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 12 Feb 2018 12:01:07 +0530 Subject: drm/msm/dsi: Get byte_intf_clk only for versions that need it Newer DSI host controllers (SDM845 in particular) require a new clock called byte_intf_clk. A recent patch tried to add this as an optional clock, but it still set 'ret' to an error number if it didn't find it. This breaks the host's probe for all previous DSI host versions. Instead of setting this up as an optional clock, try to get the clock only for the DSI version that supports it. Fixes: 56558fb ("drm/msm/dsi: Add byte_intf_clk") Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_host.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index f675975c2655..62ac614eccf9 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -378,11 +378,16 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host) goto exit; } - msm_host->byte_intf_clk = msm_clk_get(pdev, "byte_intf"); - if (IS_ERR(msm_host->byte_intf_clk)) { - ret = PTR_ERR(msm_host->byte_intf_clk); - pr_debug("%s: can't find byte_intf clock. ret=%d\n", - __func__, ret); + if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G && + cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V2_2_1) { + msm_host->byte_intf_clk = msm_clk_get(pdev, "byte_intf"); + if (IS_ERR(msm_host->byte_intf_clk)) { + ret = PTR_ERR(msm_host->byte_intf_clk); + pr_err("%s: can't find byte_intf clock. ret=%d\n", + __func__, ret); + goto exit; + } + } else { msm_host->byte_intf_clk = NULL; } -- cgit v1.2.3 From 8a1949455aaa22b3ff581766a640ed7f92cf8cef Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 20 Feb 2018 09:37:38 +0000 Subject: drm/mm: Fix caching of leftmost node in the interval tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we descend the tree to find our slot, if we step to the right, we are no longer the leftmost node. Fixes: f808c13fd373 ("lib/interval_tree: fast overlap detection") Signed-off-by: Chris Wilson Cc: Davidlohr Bueso Cc: Jérôme Glisse Cc: Christian König Reviewed-by: Joonas Lahtinen Acked-by: Christian König for now. Link: https://patchwork.freedesktop.org/patch/msgid/20180220093738.1461-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 186c4e90cc1c..a351bd888a61 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -180,7 +180,7 @@ static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node, struct drm_mm *mm = hole_node->mm; struct rb_node **link, *rb; struct drm_mm_node *parent; - bool leftmost = true; + bool leftmost; node->__subtree_last = LAST(node); @@ -201,6 +201,7 @@ static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node, } else { rb = NULL; link = &mm->interval_tree.rb_root.rb_node; + leftmost = true; } while (*link) { @@ -208,11 +209,11 @@ static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node, parent = rb_entry(rb, struct drm_mm_node, rb); if (parent->__subtree_last < node->__subtree_last) parent->__subtree_last = node->__subtree_last; - if (node->start < parent->start) + if (node->start < parent->start) { link = &parent->rb.rb_left; - else { + } else { link = &parent->rb.rb_right; - leftmost = true; + leftmost = false; } } -- cgit v1.2.3 From 7ff662b76167fd9a68254352287c5de0dc698942 Mon Sep 17 00:00:00 2001 From: Devesh Sharma Date: Thu, 15 Feb 2018 21:20:08 -0800 Subject: RDMA/bnxt_re: Disable atomic capability on bnxt_re adapters More testing needs to be done before enabling this feature. Disabling the feature temporarily Signed-off-by: Selvin Xavier Signed-off-by: Doug Ledford --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 6 ++---- drivers/infiniband/hw/bnxt_re/qplib_sp.c | 14 +------------- 2 files changed, 3 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index ae9e9ff54826..280354ffa642 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -174,10 +174,8 @@ int bnxt_re_query_device(struct ib_device *ibdev, ib_attr->max_pd = dev_attr->max_pd; ib_attr->max_qp_rd_atom = dev_attr->max_qp_rd_atom; ib_attr->max_qp_init_rd_atom = dev_attr->max_qp_init_rd_atom; - if (dev_attr->is_atomic) { - ib_attr->atomic_cap = IB_ATOMIC_HCA; - ib_attr->masked_atomic_cap = IB_ATOMIC_HCA; - } + ib_attr->atomic_cap = IB_ATOMIC_NONE; + ib_attr->masked_atomic_cap = IB_ATOMIC_NONE; ib_attr->max_ee_rd_atom = 0; ib_attr->max_res_rd_atom = 0; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index c015c1861351..03057983341f 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -52,18 +52,6 @@ const struct bnxt_qplib_gid bnxt_qplib_gid_zero = {{ 0, 0, 0, 0, 0, 0, 0, 0, /* Device */ -static bool bnxt_qplib_is_atomic_cap(struct bnxt_qplib_rcfw *rcfw) -{ - int rc; - u16 pcie_ctl2; - - rc = pcie_capability_read_word(rcfw->pdev, PCI_EXP_DEVCTL2, - &pcie_ctl2); - if (rc) - return false; - return !!(pcie_ctl2 & PCI_EXP_DEVCTL2_ATOMIC_REQ); -} - static void bnxt_qplib_query_version(struct bnxt_qplib_rcfw *rcfw, char *fw_ver) { @@ -165,7 +153,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, attr->tqm_alloc_reqs[i * 4 + 3] = *(++tqm_alloc); } - attr->is_atomic = bnxt_qplib_is_atomic_cap(rcfw); + attr->is_atomic = 0; bail: bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); return rc; -- cgit v1.2.3 From 6b4521f5174c26020ae0deb3ef7f2c28557cf445 Mon Sep 17 00:00:00 2001 From: Devesh Sharma Date: Thu, 15 Feb 2018 21:20:10 -0800 Subject: RDMA/bnxt_re: Unpin SQ and RQ memory if QP create fails Driver leaves the QP memory pinned if QP create command fails from the FW. Avoids this scenario by adding a proper exit path if the FW command fails. Signed-off-by: Devesh Sharma Signed-off-by: Selvin Xavier Signed-off-by: Doug Ledford --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 280354ffa642..29e6b1736504 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -1183,7 +1183,7 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd, rc = bnxt_qplib_create_qp(&rdev->qplib_res, &qp->qplib_qp); if (rc) { dev_err(rdev_to_dev(rdev), "Failed to create HW QP"); - goto fail; + goto free_umem; } } @@ -1211,6 +1211,13 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd, return &qp->ib_qp; qp_destroy: bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp); +free_umem: + if (udata) { + if (qp->rumem) + ib_umem_release(qp->rumem); + if (qp->sumem) + ib_umem_release(qp->sumem); + } fail: kfree(qp); return ERR_PTR(rc); -- cgit v1.2.3 From 3b921e3bc4c20af58a663ed238ad57e87493dde2 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Thu, 15 Feb 2018 21:20:11 -0800 Subject: RDMA/bnxt_re: Synchronize destroy_qp with poll_cq Avoid system crash when destroy_qp is invoked while the driver is processing the poll_cq. Synchronize these functions using the cq_lock. Signed-off-by: Selvin Xavier Signed-off-by: Doug Ledford --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 39 +++++++++++++++++++++++++++++--- drivers/infiniband/hw/bnxt_re/ib_verbs.h | 2 ++ drivers/infiniband/hw/bnxt_re/qplib_fp.c | 21 +++++------------ drivers/infiniband/hw/bnxt_re/qplib_fp.h | 4 +++- 4 files changed, 47 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 29e6b1736504..643174d949a8 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -785,20 +785,51 @@ int bnxt_re_query_ah(struct ib_ah *ib_ah, struct rdma_ah_attr *ah_attr) return 0; } +static unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp) + __acquires(&qp->scq->cq_lock) __acquires(&qp->rcq->cq_lock) +{ + unsigned long flags; + + spin_lock_irqsave(&qp->scq->cq_lock, flags); + if (qp->rcq != qp->scq) + spin_lock(&qp->rcq->cq_lock); + else + __acquire(&qp->rcq->cq_lock); + + return flags; +} + +static void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, + unsigned long flags) + __releases(&qp->scq->cq_lock) __releases(&qp->rcq->cq_lock) +{ + if (qp->rcq != qp->scq) + spin_unlock(&qp->rcq->cq_lock); + else + __release(&qp->rcq->cq_lock); + spin_unlock_irqrestore(&qp->scq->cq_lock, flags); +} + /* Queue Pairs */ int bnxt_re_destroy_qp(struct ib_qp *ib_qp) { struct bnxt_re_qp *qp = container_of(ib_qp, struct bnxt_re_qp, ib_qp); struct bnxt_re_dev *rdev = qp->rdev; int rc; + unsigned int flags; bnxt_qplib_flush_cqn_wq(&qp->qplib_qp); - bnxt_qplib_del_flush_qp(&qp->qplib_qp); rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp); if (rc) { dev_err(rdev_to_dev(rdev), "Failed to destroy HW QP"); return rc; } + + flags = bnxt_re_lock_cqs(qp); + bnxt_qplib_clean_qp(&qp->qplib_qp); + bnxt_re_unlock_cqs(qp, flags); + bnxt_qplib_free_qp_res(&rdev->qplib_res, &qp->qplib_qp); + if (ib_qp->qp_type == IB_QPT_GSI && rdev->qp1_sqp) { rc = bnxt_qplib_destroy_ah(&rdev->qplib_res, &rdev->sqp_ah->qplib_ah); @@ -808,7 +839,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp) return rc; } - bnxt_qplib_del_flush_qp(&qp->qplib_qp); + bnxt_qplib_clean_qp(&qp->qplib_qp); rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &rdev->qp1_sqp->qplib_qp); if (rc) { @@ -1067,6 +1098,7 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd, goto fail; } qp->qplib_qp.scq = &cq->qplib_cq; + qp->scq = cq; } if (qp_init_attr->recv_cq) { @@ -1078,6 +1110,7 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd, goto fail; } qp->qplib_qp.rcq = &cq->qplib_cq; + qp->rcq = cq; } if (qp_init_attr->srq) { @@ -1608,7 +1641,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, dev_dbg(rdev_to_dev(rdev), "Move QP = %p out of flush list\n", qp); - bnxt_qplib_del_flush_qp(&qp->qplib_qp); + bnxt_qplib_clean_qp(&qp->qplib_qp); } } if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) { diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h index 423ebe012f95..b88a48d43a9d 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h @@ -89,6 +89,8 @@ struct bnxt_re_qp { /* QP1 */ u32 send_psn; struct ib_ud_header qp1_hdr; + struct bnxt_re_cq *scq; + struct bnxt_re_cq *rcq; }; struct bnxt_re_cq { diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index 1b0e94697fe3..3ea5b9624f6b 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -173,7 +173,7 @@ static void __bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp) } } -void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp) +void bnxt_qplib_clean_qp(struct bnxt_qplib_qp *qp) { unsigned long flags; @@ -1419,7 +1419,6 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_rcfw *rcfw = res->rcfw; struct cmdq_destroy_qp req; struct creq_destroy_qp_resp resp; - unsigned long flags; u16 cmd_flags = 0; int rc; @@ -1437,19 +1436,12 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res, return rc; } - /* Must walk the associated CQs to nullified the QP ptr */ - spin_lock_irqsave(&qp->scq->hwq.lock, flags); - - __clean_cq(qp->scq, (u64)(unsigned long)qp); - - if (qp->rcq && qp->rcq != qp->scq) { - spin_lock(&qp->rcq->hwq.lock); - __clean_cq(qp->rcq, (u64)(unsigned long)qp); - spin_unlock(&qp->rcq->hwq.lock); - } - - spin_unlock_irqrestore(&qp->scq->hwq.lock, flags); + return 0; +} +void bnxt_qplib_free_qp_res(struct bnxt_qplib_res *res, + struct bnxt_qplib_qp *qp) +{ bnxt_qplib_free_qp_hdr_buf(res, qp); bnxt_qplib_free_hwq(res->pdev, &qp->sq.hwq); kfree(qp->sq.swq); @@ -1462,7 +1454,6 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res, if (qp->orrq.max_elements) bnxt_qplib_free_hwq(res->pdev, &qp->orrq); - return 0; } void *bnxt_qplib_get_qp1_sq_buf(struct bnxt_qplib_qp *qp, diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h index 211b27a8f9e2..ca0a2ffa3509 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h @@ -478,6 +478,9 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp); int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp); int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp); int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp); +void bnxt_qplib_clean_qp(struct bnxt_qplib_qp *qp); +void bnxt_qplib_free_qp_res(struct bnxt_qplib_res *res, + struct bnxt_qplib_qp *qp); void *bnxt_qplib_get_qp1_sq_buf(struct bnxt_qplib_qp *qp, struct bnxt_qplib_sge *sge); void *bnxt_qplib_get_qp1_rq_buf(struct bnxt_qplib_qp *qp, @@ -500,7 +503,6 @@ void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type); void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq); int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq); void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp); -void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp); void bnxt_qplib_acquire_cq_locks(struct bnxt_qplib_qp *qp, unsigned long *flags); void bnxt_qplib_release_cq_locks(struct bnxt_qplib_qp *qp, -- cgit v1.2.3 From dcdaba08062b4726500b9456f8664bfda896c664 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Thu, 15 Feb 2018 21:20:12 -0800 Subject: RDMA/bnxt_re: Fix system crash during load/unload During driver unload, the driver proceeds with cleanup without waiting for the scheduled events. So the device pointers get freed up and driver crashes when the events are scheduled later. Flush the bnxt_re_task work queue before starting device removal. Signed-off-by: Selvin Xavier Signed-off-by: Doug Ledford --- drivers/infiniband/hw/bnxt_re/main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 508d00a5a106..7f9298db507b 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -1578,6 +1578,11 @@ static void __exit bnxt_re_mod_exit(void) */ list_for_each_entry_safe_reverse(rdev, next, &to_be_deleted, list) { dev_info(rdev_to_dev(rdev), "Unregistering Device"); + /* + * Flush out any scheduled tasks before destroying the + * resources + */ + flush_workqueue(bnxt_re_wq); bnxt_re_dev_stop(rdev); bnxt_re_ib_unreg(rdev, true); bnxt_re_remove_one(rdev); -- cgit v1.2.3 From 7374fbd9e167ddc4f380d056ca74518be5d45518 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Thu, 15 Feb 2018 21:20:13 -0800 Subject: RDMA/bnxt_re: Avoid system hang during device un-reg BNXT_RE_FLAG_TASK_IN_PROG doesn't handle multiple work requests posted together. Track schedule of multiple workqueue items by maintaining a per device counter and proceed with IB dereg only if this counter is zero. flush_workqueue is no longer required from NETDEV_UNREGISTER path. Signed-off-by: Selvin Xavier Signed-off-by: Doug Ledford --- drivers/infiniband/hw/bnxt_re/bnxt_re.h | 2 +- drivers/infiniband/hw/bnxt_re/main.c | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h index ca32057e886f..3eb7a8387116 100644 --- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h +++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h @@ -120,7 +120,6 @@ struct bnxt_re_dev { #define BNXT_RE_FLAG_HAVE_L2_REF 3 #define BNXT_RE_FLAG_RCFW_CHANNEL_EN 4 #define BNXT_RE_FLAG_QOS_WORK_REG 5 -#define BNXT_RE_FLAG_TASK_IN_PROG 6 #define BNXT_RE_FLAG_ISSUE_ROCE_STATS 29 struct net_device *netdev; unsigned int version, major, minor; @@ -158,6 +157,7 @@ struct bnxt_re_dev { atomic_t srq_count; atomic_t mr_count; atomic_t mw_count; + atomic_t sched_count; /* Max of 2 lossless traffic class supported per port */ u16 cosq[2]; diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 7f9298db507b..33a448036c2e 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -656,7 +656,6 @@ static void bnxt_re_dev_remove(struct bnxt_re_dev *rdev) mutex_unlock(&bnxt_re_dev_lock); synchronize_rcu(); - flush_workqueue(bnxt_re_wq); ib_dealloc_device(&rdev->ibdev); /* rdev is gone */ @@ -1441,7 +1440,7 @@ static void bnxt_re_task(struct work_struct *work) break; } smp_mb__before_atomic(); - clear_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags); + atomic_dec(&rdev->sched_count); kfree(re_work); } @@ -1503,7 +1502,7 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier, /* netdev notifier will call NETDEV_UNREGISTER again later since * we are still holding the reference to the netdev */ - if (test_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags)) + if (atomic_read(&rdev->sched_count) > 0) goto exit; bnxt_re_ib_unreg(rdev, false); bnxt_re_remove_one(rdev); @@ -1523,7 +1522,7 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier, re_work->vlan_dev = (real_dev == netdev ? NULL : netdev); INIT_WORK(&re_work->work, bnxt_re_task); - set_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags); + atomic_inc(&rdev->sched_count); queue_work(bnxt_re_wq, &re_work->work); } } -- cgit v1.2.3 From abe27a885d9e6575e663a16176dabc58ce9d7188 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 19 Feb 2018 20:12:57 -0600 Subject: ibmvnic: Check for NULL skb's in NAPI poll routine After introduction of commit d0869c0071e4, there were some instances of RX queue entries from a previous session (before the device was closed and reopened) returned to the NAPI polling routine. Since the corresponding socket buffers were freed, this resulted in a panic on reopen. Include a check for a NULL skb here to avoid this. Fixes: d0869c0071e4 ("ibmvnic: Clean RX pool buffers during device close") Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 996f47568f9e..1495cb99f924 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1901,6 +1901,11 @@ restart_poll: dev_kfree_skb_any(rx_buff->skb); remove_buff_from_pool(adapter, rx_buff); continue; + } else if (!rx_buff->skb) { + /* free the entry */ + next->rx_comp.first = 0; + remove_buff_from_pool(adapter, rx_buff); + continue; } length = be32_to_cpu(next->rx_comp.len); -- cgit v1.2.3 From 5825acf5c958a6820b04e9811caeb2f5e572bcd8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 13 Feb 2018 14:25:11 -0500 Subject: drm/amd/powerplay/vega10: allow mclk switching with no displays If there are no displays attached, there is no reason to disable mclk switching. Fixes mclks getting set to high when there are no displays attached. Reviewed-by: Eric Huang Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 2d55dabc77d4..5f9c3efb532f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -3168,10 +3168,13 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, disable_mclk_switching_for_vr = PP_CAP(PHM_PlatformCaps_DisableMclkSwitchForVR); force_mclk_high = PP_CAP(PHM_PlatformCaps_ForceMclkHigh); - disable_mclk_switching = (info.display_count > 1) || - disable_mclk_switching_for_frame_lock || - disable_mclk_switching_for_vr || - force_mclk_high; + if (info.display_count == 0) + disable_mclk_switching = false; + else + disable_mclk_switching = (info.display_count > 1) || + disable_mclk_switching_for_frame_lock || + disable_mclk_switching_for_vr || + force_mclk_high; sclk = vega10_ps->performance_levels[0].gfx_clock; mclk = vega10_ps->performance_levels[0].mem_clock; -- cgit v1.2.3 From 51954e17914aaadf18d97b21c2a2cee16fa29513 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 13 Feb 2018 14:26:54 -0500 Subject: drm/amd/powerplay/smu7: allow mclk switching with no displays If there are no displays attached, there is no reason to disable mclk switching. Fixes mclks getting set to high when there are no displays attached. Reviewed-by: Eric Huang Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 41e42beff213..45be31327340 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -2756,10 +2756,13 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, PHM_PlatformCaps_DisableMclkSwitchingForFrameLock); - disable_mclk_switching = ((1 < info.display_count) || - disable_mclk_switching_for_frame_lock || - smu7_vblank_too_short(hwmgr, mode_info.vblank_time_us) || - (mode_info.refresh_rate > 120)); + if (info.display_count == 0) + disable_mclk_switching = false; + else + disable_mclk_switching = ((1 < info.display_count) || + disable_mclk_switching_for_frame_lock || + smu7_vblank_too_short(hwmgr, mode_info.vblank_time_us) || + (mode_info.refresh_rate > 120)); sclk = smu7_ps->performance_levels[0].engine_clock; mclk = smu7_ps->performance_levels[0].memory_clock; -- cgit v1.2.3 From 53bf277b487eb5ae6695db01bede0fe406792119 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 15 Feb 2018 08:40:30 -0500 Subject: Revert "drm/radeon/pm: autoswitch power state when in balanced mode" This reverts commit 1c331f75aa6ccbf64ebcc5a019183e617c9d818a. Breaks resume on some systems. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=100759 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_pm.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 326ad068c15a..4b6542538ff9 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -47,7 +47,6 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev); static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); static void radeon_pm_update_profile(struct radeon_device *rdev); static void radeon_pm_set_clocks(struct radeon_device *rdev); -static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev); int radeon_pm_get_type_index(struct radeon_device *rdev, enum radeon_pm_state_type ps_type, @@ -80,8 +79,6 @@ void radeon_pm_acpi_event_handler(struct radeon_device *rdev) radeon_dpm_enable_bapm(rdev, rdev->pm.dpm.ac_power); } mutex_unlock(&rdev->pm.mutex); - /* allow new DPM state to be picked */ - radeon_pm_compute_clocks_dpm(rdev); } else if (rdev->pm.pm_method == PM_METHOD_PROFILE) { if (rdev->pm.profile == PM_PROFILE_AUTO) { mutex_lock(&rdev->pm.mutex); @@ -885,8 +882,7 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF; /* balanced states don't exist at the moment */ if (dpm_state == POWER_STATE_TYPE_BALANCED) - dpm_state = rdev->pm.dpm.ac_power ? - POWER_STATE_TYPE_PERFORMANCE : POWER_STATE_TYPE_BATTERY; + dpm_state = POWER_STATE_TYPE_PERFORMANCE; restart_search: /* Pick the best power state based on current conditions */ -- cgit v1.2.3 From 5893f6e8a87243c951ddcb0bb95842bd5aef4d8f Mon Sep 17 00:00:00 2001 From: Mikita Lipski Date: Fri, 19 Jan 2018 11:21:04 -0500 Subject: drm/amdgpu: Add a missing lock for drm_mm_takedown Inside amdgpu_gtt_mgr_fini add a missing lock to maintain locking balance Signed-off-by: Mikita Lipski Reviewed-by: Andrey Grodzovsky Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c index e14ab34d8262..7c2be32c5aea 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c @@ -75,7 +75,7 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man) { struct amdgpu_gtt_mgr *mgr = man->priv; - + spin_lock(&mgr->lock); drm_mm_takedown(&mgr->mm); spin_unlock(&mgr->lock); kfree(mgr); -- cgit v1.2.3 From 09c381e0f34abaeff68ba5ac3d949928f32757c5 Mon Sep 17 00:00:00 2001 From: Mikita Lipski Date: Sat, 3 Feb 2018 15:19:20 -0500 Subject: drm/amdgpu: Unify the dm resume calls into one amdgpu_dm_display_resume is now called from dm_resume to unify DAL resume call into a single function call There is no more need to separately call 2 resume functions for DM. Initially they were separated to resume display state after cursor is pinned. But because there is no longer any corruption with the cursor - the calls can be merged into one function hook. Signed-off-by: Mikita Lipski Reviewed-by: Harry Wentland Reviewed-by: Andrey Grodzovsky Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 9 --------- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 +++- 2 files changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 00a50cc5ec9a..829dc2edace6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2284,14 +2284,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); } drm_modeset_unlock_all(dev); - } else { - /* - * There is no equivalent atomic helper to turn on - * display, so we defined our own function for this, - * once suspend resume is supported by the atomic - * framework this will be reworked - */ - amdgpu_dm_display_resume(adev); } } @@ -2726,7 +2718,6 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, if (amdgpu_device_has_dc_support(adev)) { if (drm_atomic_helper_resume(adev->ddev, state)) dev_info(adev->dev, "drm resume failed:%d\n", r); - amdgpu_dm_display_resume(adev); } else { drm_helper_resume_force_mode(adev->ddev); } 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 1ce4c98385e3..862835dc054e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -629,11 +629,13 @@ static int dm_resume(void *handle) { struct amdgpu_device *adev = handle; struct amdgpu_display_manager *dm = &adev->dm; + int ret = 0; /* power on hardware */ dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0); - return 0; + ret = amdgpu_dm_display_resume(adev); + return ret; } int amdgpu_dm_display_resume(struct amdgpu_device *adev) -- cgit v1.2.3 From 4909c6de7d7ada493e1c2f0d8bf0145a750d2dd6 Mon Sep 17 00:00:00 2001 From: Hersen Wu Date: Tue, 30 Jan 2018 11:46:16 -0500 Subject: drm/amd/display: VGA black screen from s3 when attached to hook [Description] For MST, DC already notify MST sink for MST mode, DC stll check DP SINK DPCD register to see if MST enabled. DP RX firmware may not handle this properly. Signed-off-by: Hersen Wu Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') 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 61e8c3e02d16..51f5a5757ff0 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 @@ -1465,7 +1465,7 @@ void decide_link_settings(struct dc_stream_state *stream, /* MST doesn't perform link training for now * TODO: add MST specific link training routine */ - if (is_mst_supported(link)) { + if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { *link_setting = link->verified_link_cap; return; } -- cgit v1.2.3 From 8babd44d2079079f9d5a4aca7005aed80236efe0 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Wed, 20 Dec 2017 08:48:24 +0200 Subject: net/mlx5e: Fix TCP checksum in LRO buffers When receiving an LRO packet, the checksum field is set by the hardware to the checksum of the first coalesced packet. Obviously, this checksum is not valid for the merged LRO packet and should be fixed. We can use the CQE checksum which covers the checksum of the entire merged packet TCP payload to help us calculate the checksum incrementally. Tested by sending IPv4/6 traffic with LRO enabled, RX checksum disabled and watching nstat checksum error counters (in addition to the obvious bandwidth drop caused by checksum errors). This bug is usually "hidden" since LRO packets would go through the CHECKSUM_UNNECESSARY flow which does not validate the packet checksum. It's important to note that previous to this patch, LRO packets provided with CHECKSUM_UNNECESSARY are indeed packets with a correct validated checksum (even though the checksum inside the TCP header is incorrect), since the hardware LRO aggregation is terminated upon receiving a packet with bad checksum. Fixes: e586b3b0baee ("net/mlx5: Ethernet Datapath files") Signed-off-by: Gal Pressman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 49 ++++++++++++++++++------- 1 file changed, 35 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 0d4bb0688faa..e5c3ab46a24a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "en.h" #include "en_tc.h" #include "eswitch.h" @@ -546,20 +547,33 @@ bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq) return true; } +static void mlx5e_lro_update_tcp_hdr(struct mlx5_cqe64 *cqe, struct tcphdr *tcp) +{ + u8 l4_hdr_type = get_cqe_l4_hdr_type(cqe); + u8 tcp_ack = (l4_hdr_type == CQE_L4_HDR_TYPE_TCP_ACK_NO_DATA) || + (l4_hdr_type == CQE_L4_HDR_TYPE_TCP_ACK_AND_DATA); + + tcp->check = 0; + tcp->psh = get_cqe_lro_tcppsh(cqe); + + if (tcp_ack) { + tcp->ack = 1; + tcp->ack_seq = cqe->lro_ack_seq_num; + tcp->window = cqe->lro_tcp_win; + } +} + static void mlx5e_lro_update_hdr(struct sk_buff *skb, struct mlx5_cqe64 *cqe, u32 cqe_bcnt) { struct ethhdr *eth = (struct ethhdr *)(skb->data); struct tcphdr *tcp; int network_depth = 0; + __wsum check; __be16 proto; u16 tot_len; void *ip_p; - u8 l4_hdr_type = get_cqe_l4_hdr_type(cqe); - u8 tcp_ack = (l4_hdr_type == CQE_L4_HDR_TYPE_TCP_ACK_NO_DATA) || - (l4_hdr_type == CQE_L4_HDR_TYPE_TCP_ACK_AND_DATA); - proto = __vlan_get_protocol(skb, eth->h_proto, &network_depth); tot_len = cqe_bcnt - network_depth; @@ -576,23 +590,30 @@ static void mlx5e_lro_update_hdr(struct sk_buff *skb, struct mlx5_cqe64 *cqe, ipv4->check = 0; ipv4->check = ip_fast_csum((unsigned char *)ipv4, ipv4->ihl); + + mlx5e_lro_update_tcp_hdr(cqe, tcp); + check = csum_partial(tcp, tcp->doff * 4, + csum_unfold((__force __sum16)cqe->check_sum)); + /* Almost done, don't forget the pseudo header */ + tcp->check = csum_tcpudp_magic(ipv4->saddr, ipv4->daddr, + tot_len - sizeof(struct iphdr), + IPPROTO_TCP, check); } else { + u16 payload_len = tot_len - sizeof(struct ipv6hdr); struct ipv6hdr *ipv6 = ip_p; tcp = ip_p + sizeof(struct ipv6hdr); skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; ipv6->hop_limit = cqe->lro_min_ttl; - ipv6->payload_len = cpu_to_be16(tot_len - - sizeof(struct ipv6hdr)); - } - - tcp->psh = get_cqe_lro_tcppsh(cqe); - - if (tcp_ack) { - tcp->ack = 1; - tcp->ack_seq = cqe->lro_ack_seq_num; - tcp->window = cqe->lro_tcp_win; + ipv6->payload_len = cpu_to_be16(payload_len); + + mlx5e_lro_update_tcp_hdr(cqe, tcp); + check = csum_partial(tcp, tcp->doff * 4, + csum_unfold((__force __sum16)cqe->check_sum)); + /* Almost done, don't forget the pseudo header */ + tcp->check = csum_ipv6_magic(&ipv6->saddr, &ipv6->daddr, payload_len, + IPPROTO_TCP, check); } } -- cgit v1.2.3 From ef7a3518f7dd4f4cf5e5b5358c93d1eb78df28fb Mon Sep 17 00:00:00 2001 From: Inbar Karmy Date: Thu, 7 Dec 2017 17:26:33 +0200 Subject: net/mlx5e: Fix loopback self test when GRO is off When GRO is off, the transport header pointer in sk_buff is initialized to network's header. To find the udp header, instead of using udp_hdr() which assumes skb_network_header was set, manually calculate the udp header offset. Fixes: 0952da791c97 ("net/mlx5e: Add support for loopback selftest") Signed-off-by: Inbar Karmy Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c index 5a4608281f38..707976482c09 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c @@ -216,7 +216,8 @@ mlx5e_test_loopback_validate(struct sk_buff *skb, if (iph->protocol != IPPROTO_UDP) goto out; - udph = udp_hdr(skb); + /* Don't assume skb_transport_header() was set */ + udph = (struct udphdr *)((u8 *)iph + 4 * iph->ihl); if (udph->dest != htons(9)) goto out; -- cgit v1.2.3 From f600c6088018d1dbc5777d18daa83660f7ea4a64 Mon Sep 17 00:00:00 2001 From: Eran Ben Elisha Date: Thu, 25 Jan 2018 11:18:09 +0200 Subject: net/mlx5e: Verify inline header size do not exceed SKB linear size Driver tries to copy at least MLX5E_MIN_INLINE bytes into the control segment of the WQE. It assumes that the linear part contains at least MLX5E_MIN_INLINE bytes, which can be wrong. Cited commit verified that driver will not copy more bytes into the inline header part that the actual size of the packet. Re-factor this check to make sure we do not exceed the linear part as well. This fix is aligned with the current driver's assumption that the entire L2 will be present in the linear part of the SKB. Fixes: 6aace17e64f4 ("net/mlx5e: Fix inline header size for small packets") Signed-off-by: Eran Ben Elisha Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 569b42a01026..11b4f1089d1c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -176,7 +176,7 @@ static inline u16 mlx5e_calc_min_inline(enum mlx5_inline_modes mode, default: hlen = mlx5e_skb_l2_header_offset(skb); } - return min_t(u16, hlen, skb->len); + return min_t(u16, hlen, skb_headlen(skb)); } static inline void mlx5e_tx_skb_pull_inline(unsigned char **skb_data, -- cgit v1.2.3 From 9afe9a5353778994d4396f3d5ff639221bfa5cc9 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 1 Jan 2018 13:19:51 +0000 Subject: net/mlx5e: Eliminate build warnings on no previous prototype Fix these gcc warnings on drivers/net/ethernet/mellanox/mlx5: [..]/core/lib/clock.c:454:6: warning: no previous prototype for 'mlx5_init_clock' [-Wmissing-prototypes] [..]/core/lib/clock.c:510:6: warning: no previous prototype for 'mlx5_cleanup_clock' [-Wmissing-prototypes] [..]/core/en_main.c:3141:5: warning: no previous prototype for 'mlx5e_setup_tc' [-Wmissing-prototypes] Signed-off-by: Or Gerlitz Reviewed-by: Matan Barak Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 47bab842c5ee..a64b9226d281 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -2994,8 +2994,8 @@ static int mlx5e_setup_tc_block(struct net_device *dev, } #endif -int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type, - void *type_data) +static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type, + void *type_data) { switch (type) { #ifdef CONFIG_MLX5_ESWITCH diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index e159243e0fcf..857035583ccd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -34,6 +34,7 @@ #include #include #include "en.h" +#include "clock.h" enum { MLX5_CYCLES_SHIFT = 23 -- cgit v1.2.3 From 4f5c02f949973b7c9dfa8a7c23d766b1208d208f Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 1 Jan 2018 13:29:53 +0000 Subject: net/mlx5: Address static checker warnings on non-constant initializers Address these sparse warnings on drivers/net/ethernet/mellanox/mlx5 [..]/core/diag/fs_tracepoint.c:99:53: warning: non-constant initializer for static object [..]/core/diag/fs_tracepoint.c:102:53: warning: non-constant initializer for static object etc Signed-off-by: Or Gerlitz Reviewed-by: Matan Barak Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.c index 0be4575b58a2..fd509160c8f6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.c @@ -96,10 +96,10 @@ static void print_lyr_2_4_hdrs(struct trace_seq *p, "%pI4"); } else if (ethertype.v == ETH_P_IPV6) { static const struct in6_addr full_ones = { - .in6_u.u6_addr32 = {htonl(0xffffffff), - htonl(0xffffffff), - htonl(0xffffffff), - htonl(0xffffffff)}, + .in6_u.u6_addr32 = {__constant_htonl(0xffffffff), + __constant_htonl(0xffffffff), + __constant_htonl(0xffffffff), + __constant_htonl(0xffffffff)}, }; DECLARE_MASK_VAL(struct in6_addr, src_ipv6); DECLARE_MASK_VAL(struct in6_addr, dst_ipv6); -- cgit v1.2.3 From 001a2fc0c8cc29241305e44ffbce52d1daf8782b Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 30 Jan 2018 13:16:58 +0200 Subject: net/mlx5e: Return error if prio is specified when offloading eswitch vlan push This isn't supported when we emulate eswitch vlan push action which is the current state of things. Fixes: 8b32580df1cb ('net/mlx5e: Add TC vlan action for SRIOV offloads') Signed-off-by: Or Gerlitz Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index fd98b0dc610f..fa86a1466718 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -2529,7 +2529,8 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, if (tcf_vlan_action(a) == TCA_VLAN_ACT_POP) { attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; } else if (tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) { - if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q)) + if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q) || + tcf_vlan_push_prio(a)) return -EOPNOTSUPP; attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH; -- cgit v1.2.3 From 2f0db87901698cd73d828cc6fb1957b8916fc911 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Thu, 25 Jan 2018 18:00:41 +0200 Subject: net/mlx5e: Specify numa node when allocating drop rq When allocating a drop rq, no numa node is explicitly set which means allocations are done on node zero. This is not necessarily the nearest numa node to the HCA, and even worse, might even be a memoryless numa node. Choose the numa_node given to us by the pci device in order to properly allocate the coherent dma memory instead of assuming zero is valid. Fixes: 556dd1b9c313 ("net/mlx5e: Set drop RQ's necessary parameters only") Signed-off-by: Gal Pressman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index a64b9226d281..da94c8cba5ee 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1768,13 +1768,16 @@ static void mlx5e_build_rq_param(struct mlx5e_priv *priv, param->wq.linear = 1; } -static void mlx5e_build_drop_rq_param(struct mlx5e_rq_param *param) +static void mlx5e_build_drop_rq_param(struct mlx5_core_dev *mdev, + struct mlx5e_rq_param *param) { void *rqc = param->rqc; void *wq = MLX5_ADDR_OF(rqc, rqc, wq); MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_LINKED_LIST); MLX5_SET(wq, wq, log_wq_stride, ilog2(sizeof(struct mlx5e_rx_wqe))); + + param->wq.buf_numa_node = dev_to_node(&mdev->pdev->dev); } static void mlx5e_build_sq_param_common(struct mlx5e_priv *priv, @@ -2634,6 +2637,9 @@ static int mlx5e_alloc_drop_cq(struct mlx5_core_dev *mdev, struct mlx5e_cq *cq, struct mlx5e_cq_param *param) { + param->wq.buf_numa_node = dev_to_node(&mdev->pdev->dev); + param->wq.db_numa_node = dev_to_node(&mdev->pdev->dev); + return mlx5e_alloc_cq_common(mdev, param, cq); } @@ -2645,7 +2651,7 @@ static int mlx5e_open_drop_rq(struct mlx5_core_dev *mdev, struct mlx5e_cq *cq = &drop_rq->cq; int err; - mlx5e_build_drop_rq_param(&rq_param); + mlx5e_build_drop_rq_param(mdev, &rq_param); err = mlx5e_alloc_drop_cq(mdev, cq, &cq_param); if (err) -- cgit v1.2.3 From c67f100edae0d2f43e8b35955f7710d702efd590 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Fri, 2 Feb 2018 09:32:53 -0600 Subject: net/mlx5: Use 128B cacheline size for 128B or larger cachelines The adapter uses the cache_line_128byte setting to set the bounds for end padding. On systems where the cacheline size is greater than 128B use 128B instead of the default of 64B. This results in fewer partial cacheline writes. There's a 50% chance it will pad to the end of a 256B cache line vs only 25% when using 64B. Fixes: f32f5bd2eb7e ("net/mlx5: Configure cache line size for start and end padding") Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 2ef641c91c26..ae391e4b7070 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -551,7 +551,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev) MLX5_SET(cmd_hca_cap, set_hca_cap, cache_line_128byte, - cache_line_size() == 128 ? 1 : 0); + cache_line_size() >= 128 ? 1 : 0); if (MLX5_CAP_GEN_MAX(dev, dct)) MLX5_SET(cmd_hca_cap, set_hca_cap, dct, 1); -- cgit v1.2.3 From 96de67a77293b4da48a05f6ec0385f60006a7ba6 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 11 Feb 2018 13:26:06 +0200 Subject: net/mlx5: Add header re-write to the checks for conflicting actions We can't allow only some of the rules sharing an FTE to ask for header re-write, add it to the conflicting action checks. Fixes: 0d235c3fabb7 ('net/mlx5: Add hash table to search FTEs in a flow-group') Signed-off-by: Or Gerlitz Reviewed-by: Matan Barak Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index c025c98700e4..6caa4a7ad869 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -1429,7 +1429,8 @@ static bool check_conflicting_actions(u32 action1, u32 action2) if (xored_actions & (MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_ENCAP | - MLX5_FLOW_CONTEXT_ACTION_DECAP)) + MLX5_FLOW_CONTEXT_ACTION_DECAP | + MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)) return true; return false; -- cgit v1.2.3 From 26a0f6e82997d5c8345782b55d3a7894421f777f Mon Sep 17 00:00:00 2001 From: Eugenia Emantayev Date: Wed, 31 Jan 2018 09:36:29 +0200 Subject: net/mlx5: E-Switch, Fix drop counters use before creation First use of drop counters happens in esw_apply_vport_conf function, while they are allocated later in the flow. Fix that by moving esw_vport_create_drop_counters function to be called before the first use. Fixes: b8a0dbe3a90b ("net/mlx5e: E-switch, Add steering drop counters") Signed-off-by: Eugenia Emantayev Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 5ecf2cddc16d..c2b1d7d351fc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1529,6 +1529,10 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num, esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num); + /* Create steering drop counters for ingress and egress ACLs */ + if (vport_num && esw->mode == SRIOV_LEGACY) + esw_vport_create_drop_counters(vport); + /* Restore old vport configuration */ esw_apply_vport_conf(esw, vport); @@ -1545,10 +1549,6 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num, if (!vport_num) vport->info.trusted = true; - /* create steering drop counters for ingress and egress ACLs */ - if (vport_num && esw->mode == SRIOV_LEGACY) - esw_vport_create_drop_counters(vport); - esw_vport_change_handle_locked(vport); esw->enabled_vports++; -- cgit v1.2.3 From 9238e380e823a39983ee8d6b6ee8d1a9c4ba8a65 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Tue, 6 Feb 2018 10:52:19 +0200 Subject: net/mlx5: Fix error handling when adding flow rules If building match list or adding existing fg fails when node is locked, function returned without unlocking it. This happened if node version changed or adding existing fg returned with EAGAIN after jumping to search_again_locked label. Fixes: bd71b08ec2ee ("net/mlx5: Support multiple updates of steering rules in parallel") Signed-off-by: Vlad Buslov Reviewed-by: Maor Gottlieb Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 6caa4a7ad869..31fc2cfac3b3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -1759,8 +1759,11 @@ search_again_locked: /* Collect all fgs which has a matching match_criteria */ err = build_match_list(&match_head, ft, spec); - if (err) + if (err) { + if (take_write) + up_write_ref_node(&ft->node); return ERR_PTR(err); + } if (!take_write) up_read_ref_node(&ft->node); @@ -1769,8 +1772,11 @@ search_again_locked: dest_num, version); free_match_list(&match_head); if (!IS_ERR(rule) || - (PTR_ERR(rule) != -ENOENT && PTR_ERR(rule) != -EAGAIN)) + (PTR_ERR(rule) != -ENOENT && PTR_ERR(rule) != -EAGAIN)) { + if (take_write) + up_write_ref_node(&ft->node); return rule; + } if (!take_write) { nested_down_write_ref_node(&ft->node, FS_LOCK_GRANDPARENT); -- cgit v1.2.3 From b17e5729a630d8326a48ec34ef02e6b4464a6aef Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Sun, 18 Feb 2018 22:17:09 +0800 Subject: libata: disable LPM for Crucial BX100 SSD 500GB drive After Laptop Mode Tools starts to use min_power for LPM, a user found out Crucial BX100 SSD can't get mounted. Crucial BX100 SSD 500GB drive don't work well with min_power. This also happens to med_power_with_dipm. So let's disable LPM for Crucial BX100 SSD 500GB drive. BugLink: https://bugs.launchpad.net/bugs/1726930 Signed-off-by: Kai-Heng Feng Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org --- drivers/ata/libata-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 28cad49fc846..cb789f8849ae 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4530,6 +4530,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "PIONEER DVD-RW DVR-212D", NULL, ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, + /* Crucial BX100 SSD 500GB has broken LPM support */ + { "CT500BX100SSD1", "MU02", ATA_HORKAGE_NOLPM }, + /* The 512GB version of the MX100 has both queued TRIM and LPM issues */ { "Crucial_CT512MX100*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM | -- cgit v1.2.3 From 423688abd9ab654044bddd82eb5983189eb9630d Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Fri, 16 Feb 2018 14:01:18 +0100 Subject: ocxl: Fix potential bad errno on irq allocation Fix some issues found by a static checker: When allocating an AFU interrupt, if the driver cannot copy the output parameters to userland, the errno value was not set to EFAULT Remove a (now) useless cast. Reported-by: Dan Carpenter Signed-off-by: Frederic Barrat Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/ocxl/file.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c index 2dd2db9bc1c9..337462e1569f 100644 --- a/drivers/misc/ocxl/file.c +++ b/drivers/misc/ocxl/file.c @@ -133,8 +133,10 @@ static long afu_ioctl(struct file *file, unsigned int cmd, if (!rc) { rc = copy_to_user((u64 __user *) args, &irq_offset, sizeof(irq_offset)); - if (rc) + if (rc) { ocxl_afu_irq_free(ctx, irq_offset); + return -EFAULT; + } } break; @@ -329,7 +331,7 @@ static ssize_t afu_read(struct file *file, char __user *buf, size_t count, used += sizeof(header); - rc = (ssize_t) used; + rc = used; return rc; } -- cgit v1.2.3 From b3b12ea3661958bc093e258b7c0dd0a13bdcc719 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 19 Feb 2018 18:59:36 +0100 Subject: drm/edid: quirk Oculus Rift headsets as non-desktop This uses the EDID info from Oculus Rift DK1 (OVR-0001), DK2 (OVR-0003), and CV1 (OVR-0004) to mark them as non-desktop. Signed-off-by: Philipp Zabel Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_edid.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index ddd537914575..d6fa56bb6906 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -162,6 +162,11 @@ static const struct edid_quirk { /* HTC Vive VR Headset */ { "HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP }, + + /* Oculus Rift DK1, DK2, and CV1 VR Headsets */ + { "OVR", 0x0001, EDID_QUIRK_NON_DESKTOP }, + { "OVR", 0x0003, EDID_QUIRK_NON_DESKTOP }, + { "OVR", 0x0004, EDID_QUIRK_NON_DESKTOP }, }; /* -- cgit v1.2.3 From 90eda8fc8016cfe39e2c73222e14665f0e5dabb1 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 19 Feb 2018 18:59:37 +0100 Subject: drm/edid: quirk Windows Mixed Reality headsets as non-desktop This uses the EDID info from Lenovo Explorer (LEN-b800), Acer AH100 (ACR-7fce), and Samsung Odyssey (SEC-144a) to mark them as non-desktop. The other entries are for the HP Windows Mixed Reality Headset (HPN-3515), the Fujitsu Windows Mixed Reality headset (FUJ-1970), the Dell Visor (DEL-7fce), and the ASUS HC102 (AUS-c102). They are not tested with real hardware, but listed as HMD monitors alongside the tested headsets in the Microsoft HololensSensors driver package. Signed-off-by: Philipp Zabel Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_edid.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index d6fa56bb6906..bfd89b47b162 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -167,6 +167,16 @@ static const struct edid_quirk { { "OVR", 0x0001, EDID_QUIRK_NON_DESKTOP }, { "OVR", 0x0003, EDID_QUIRK_NON_DESKTOP }, { "OVR", 0x0004, EDID_QUIRK_NON_DESKTOP }, + + /* Windows Mixed Reality Headsets */ + { "ACR", 0x7fce, EDID_QUIRK_NON_DESKTOP }, + { "HPN", 0x3515, EDID_QUIRK_NON_DESKTOP }, + { "LEN", 0x0408, EDID_QUIRK_NON_DESKTOP }, + { "LEN", 0xb800, EDID_QUIRK_NON_DESKTOP }, + { "FUJ", 0x1970, EDID_QUIRK_NON_DESKTOP }, + { "DEL", 0x7fce, EDID_QUIRK_NON_DESKTOP }, + { "SEC", 0x144a, EDID_QUIRK_NON_DESKTOP }, + { "AUS", 0xc102, EDID_QUIRK_NON_DESKTOP }, }; /* -- cgit v1.2.3 From ccffc9ebfa66e3f2cc5e17b2579202786050b32e Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 19 Feb 2018 18:59:38 +0100 Subject: drm/edid: quirk Sony PlayStation VR headset as non-desktop This uses the EDID info from the Sony PlayStation VR headset, when connected directly, to mark it as non-desktop. Since the connection box (product id b403) defaults to HDMI pass-through to the TV, it is not marked as non-desktop. Signed-off-by: Philipp Zabel Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_edid.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index bfd89b47b162..9796c29dc004 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -177,6 +177,9 @@ static const struct edid_quirk { { "DEL", 0x7fce, EDID_QUIRK_NON_DESKTOP }, { "SEC", 0x144a, EDID_QUIRK_NON_DESKTOP }, { "AUS", 0xc102, EDID_QUIRK_NON_DESKTOP }, + + /* Sony PlayStation VR Headset */ + { "SNY", 0x0704, EDID_QUIRK_NON_DESKTOP }, }; /* -- cgit v1.2.3 From fba4adbbf670577e605f9ad306629db6031cd48b Mon Sep 17 00:00:00 2001 From: Ben Gardner Date: Wed, 14 Feb 2018 09:29:52 -0600 Subject: i2c: designware: must wait for enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One I2C bus on my Atom E3845 board has been broken since 4.9. It has two devices, both declared by ACPI and with built-in drivers. There are two back-to-back transactions originating from the kernel, one targeting each device. The first transaction works, the second one locks up the I2C controller. The controller never recovers. These kernel logs show up whenever an I2C transaction is attempted after this failure. i2c-designware-pci 0000:00:18.3: timeout in disabling adapter i2c-designware-pci 0000:00:18.3: timeout waiting for bus ready Waiting for the I2C controller status to indicate that it is enabled before programming it fixes the issue. I have tested this patch on 4.14 and 4.15. Fixes: commit 2702ea7dbec5 ("i2c: designware: wait for disable/enable only if necessary") Cc: linux-stable #4.13+ Signed-off-by: Ben Gardner Acked-by: Jarkko Nikula Reviewed-by: José Roberto de Souza Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-master.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index ae691884d071..55926ef41ef1 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -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_and_wait(dev, true); /* Clear and enable interrupts */ dw_readl(dev, DW_IC_CLR_INTR); -- cgit v1.2.3 From 15407798835a94f0936c7cbabb2f611bf20f467a Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 16 Feb 2018 11:24:29 +0200 Subject: i2c: i801: Add missing documentation entries for Braswell and Kaby Lake Commits adding PCI IDs for Intel Braswell and Kaby Lake PCH-H lacked the respective Kconfig and Documentation/i2c/busses/i2c-i801 change. Add them now. Signed-off-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 2 ++ drivers/i2c/busses/i2c-i801.c | 1 + 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a9805c7cb305..e2954fb86d65 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -123,8 +123,10 @@ config I2C_I801 Wildcat Point (PCH) Wildcat Point-LP (PCH) BayTrail (SOC) + Braswell (SOC) Sunrise Point-H (PCH) Sunrise Point-LP (PCH) + Kaby Lake-H (PCH) DNV (SOC) Broxton (SOC) Lewisburg (PCH) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 8eac00efadc1..692b34125866 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -58,6 +58,7 @@ * Wildcat Point (PCH) 0x8ca2 32 hard yes yes yes * Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes * BayTrail (SOC) 0x0f12 32 hard yes yes yes + * Braswell (SOC) 0x2292 32 hard yes yes yes * Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes * Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes * DNV (SOC) 0x19df 32 hard yes yes yes -- cgit v1.2.3 From f4bc0c813e03bdb93f5300c3e06d7a0f07f65a74 Mon Sep 17 00:00:00 2001 From: Artur Paszkiewicz Date: Tue, 20 Feb 2018 10:10:36 +0100 Subject: raid5-ppl: fix handling flush requests Add missing bio completion. Without this any flush request would hang. Fixes: 1532d9e87e8b ("raid5-ppl: PPL support for disks with write-back cache enabled") Signed-off-by: Artur Paszkiewicz Signed-off-by: Shaohua Li --- drivers/md/raid5-log.h | 3 ++- drivers/md/raid5-ppl.c | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/raid5-log.h b/drivers/md/raid5-log.h index 0c76bcedfc1c..a001808a2b77 100644 --- a/drivers/md/raid5-log.h +++ b/drivers/md/raid5-log.h @@ -44,6 +44,7 @@ extern void ppl_write_stripe_run(struct r5conf *conf); extern void ppl_stripe_write_finished(struct stripe_head *sh); extern int ppl_modify_log(struct r5conf *conf, struct md_rdev *rdev, bool add); extern void ppl_quiesce(struct r5conf *conf, int quiesce); +extern int ppl_handle_flush_request(struct r5l_log *log, struct bio *bio); static inline bool raid5_has_ppl(struct r5conf *conf) { @@ -104,7 +105,7 @@ static inline int log_handle_flush_request(struct r5conf *conf, struct bio *bio) if (conf->log) ret = r5l_handle_flush_request(conf->log, bio); else if (raid5_has_ppl(conf)) - ret = 0; + ret = ppl_handle_flush_request(conf->log, bio); return ret; } diff --git a/drivers/md/raid5-ppl.c b/drivers/md/raid5-ppl.c index 2764c2290062..42890a08375b 100644 --- a/drivers/md/raid5-ppl.c +++ b/drivers/md/raid5-ppl.c @@ -693,6 +693,16 @@ void ppl_quiesce(struct r5conf *conf, int quiesce) } } +int ppl_handle_flush_request(struct r5l_log *log, struct bio *bio) +{ + if (bio->bi_iter.bi_size == 0) { + bio_endio(bio); + return 0; + } + bio->bi_opf &= ~REQ_PREFLUSH; + return -EAGAIN; +} + void ppl_stripe_write_finished(struct stripe_head *sh) { struct ppl_io_unit *io; -- cgit v1.2.3 From 53b8d89ddbdbb0e4625a46d2cdbb6f106c52f801 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 20 Feb 2018 14:09:11 +0100 Subject: md: raid5: avoid string overflow warning gcc warns about a possible overflow of the kmem_cache string, when adding four characters to a string of the same length: drivers/md/raid5.c: In function 'setup_conf': drivers/md/raid5.c:2207:34: error: '-alt' directive writing 4 bytes into a region of size between 1 and 32 [-Werror=format-overflow=] sprintf(conf->cache_name[1], "%s-alt", conf->cache_name[0]); ^~~~ drivers/md/raid5.c:2207:2: note: 'sprintf' output between 5 and 36 bytes into a destination of size 32 sprintf(conf->cache_name[1], "%s-alt", conf->cache_name[0]); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If I'm counting correctly, we need 11 characters for the fixed part of the string and 18 characters for a 64-bit pointer (when no gendisk is used), so that leaves three characters for conf->level, which should always be sufficient. This makes the code use snprintf() with the correct length, to make the code more robust against changes, and to get the compiler to shut up. In commit f4be6b43f1ac ("md/raid5: ensure we create a unique name for kmem_cache when mddev has no gendisk") from 2010, Neil said that the pointer could be removed "shortly" once devices without gendisk are disallowed. I have no idea if that happened, but if it did, that should probably be changed as well. Signed-off-by: Arnd Bergmann Signed-off-by: Shaohua Li --- drivers/md/raid5.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 36e050678f5a..e3b0f799fbfa 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2196,15 +2196,16 @@ static int grow_one_stripe(struct r5conf *conf, gfp_t gfp) static int grow_stripes(struct r5conf *conf, int num) { struct kmem_cache *sc; + size_t namelen = sizeof(conf->cache_name[0]); int devs = max(conf->raid_disks, conf->previous_raid_disks); if (conf->mddev->gendisk) - sprintf(conf->cache_name[0], + snprintf(conf->cache_name[0], namelen, "raid%d-%s", conf->level, mdname(conf->mddev)); else - sprintf(conf->cache_name[0], + snprintf(conf->cache_name[0], namelen, "raid%d-%p", conf->level, conf->mddev); - sprintf(conf->cache_name[1], "%s-alt", conf->cache_name[0]); + snprintf(conf->cache_name[1], namelen, "%.27s-alt", conf->cache_name[0]); conf->active_name = 0; sc = kmem_cache_create(conf->cache_name[conf->active_name], -- cgit v1.2.3 From f45765872e7aae7b81feb3044aaf9886b21885ef Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 21 Feb 2018 10:25:01 +0200 Subject: RDMA/uverbs: Fix kernel panic while using XRC_TGT QP type Attempt to modify XRC_TGT QP type from the user space (ibv_xsrq_pingpong invocation) will trigger the following kernel panic. It is caused by the fact that such QPs missed uobject initialization. [ 17.408845] BUG: unable to handle kernel NULL pointer dereference at 0000000000000048 [ 17.412645] IP: rdma_lookup_put_uobject+0x9/0x50 [ 17.416567] PGD 0 P4D 0 [ 17.419262] Oops: 0000 [#1] SMP PTI [ 17.422915] CPU: 0 PID: 455 Comm: ibv_xsrq_pingpo Not tainted 4.16.0-rc1+ #86 [ 17.424765] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 [ 17.427399] RIP: 0010:rdma_lookup_put_uobject+0x9/0x50 [ 17.428445] RSP: 0018:ffffb8c7401e7c90 EFLAGS: 00010246 [ 17.429543] RAX: 0000000000000000 RBX: ffffb8c7401e7cf8 RCX: 0000000000000000 [ 17.432426] RDX: 0000000000000001 RSI: 0000000000000000 RDI: 0000000000000000 [ 17.437448] RBP: 0000000000000000 R08: 00000000000218f0 R09: ffffffff8ebc4cac [ 17.440223] R10: fffff6038052cd80 R11: ffff967694b36400 R12: ffff96769391f800 [ 17.442184] R13: ffffb8c7401e7cd8 R14: 0000000000000000 R15: ffff967699f60000 [ 17.443971] FS: 00007fc29207d700(0000) GS:ffff96769fc00000(0000) knlGS:0000000000000000 [ 17.446623] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 17.448059] CR2: 0000000000000048 CR3: 000000001397a000 CR4: 00000000000006b0 [ 17.449677] Call Trace: [ 17.450247] modify_qp.isra.20+0x219/0x2f0 [ 17.451151] ib_uverbs_modify_qp+0x90/0xe0 [ 17.452126] ib_uverbs_write+0x1d2/0x3c0 [ 17.453897] ? __handle_mm_fault+0x93c/0xe40 [ 17.454938] __vfs_write+0x36/0x180 [ 17.455875] vfs_write+0xad/0x1e0 [ 17.456766] SyS_write+0x52/0xc0 [ 17.457632] do_syscall_64+0x75/0x180 [ 17.458631] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 17.460004] RIP: 0033:0x7fc29198f5a0 [ 17.460982] RSP: 002b:00007ffccc71f018 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 [ 17.463043] RAX: ffffffffffffffda RBX: 0000000000000078 RCX: 00007fc29198f5a0 [ 17.464581] RDX: 0000000000000078 RSI: 00007ffccc71f050 RDI: 0000000000000003 [ 17.466148] RBP: 0000000000000000 R08: 0000000000000078 R09: 00007ffccc71f050 [ 17.467750] R10: 000055b6cf87c248 R11: 0000000000000246 R12: 00007ffccc71f300 [ 17.469541] R13: 000055b6cf8733a0 R14: 0000000000000000 R15: 0000000000000000 [ 17.471151] Code: 00 00 0f 1f 44 00 00 48 8b 47 48 48 8b 00 48 8b 40 10 e9 0b 8b 68 00 90 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 55 53 89 f5 <48> 8b 47 48 48 89 fb 40 0f b6 f6 48 8b 00 48 8b 40 20 e8 e0 8a [ 17.475185] RIP: rdma_lookup_put_uobject+0x9/0x50 RSP: ffffb8c7401e7c90 [ 17.476841] CR2: 0000000000000048 [ 17.477764] ---[ end trace 1dbcc5354071a712 ]--- [ 17.478880] Kernel panic - not syncing: Fatal exception [ 17.480277] Kernel Offset: 0xd000000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff) Fixes: 2f08ee363fe0 ("RDMA/restrack: don't use uaccess_kernel()") Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs_cmd.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 25a0e0e083b3..a148de35df8d 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1553,6 +1553,9 @@ static int create_qp(struct ib_uverbs_file *file, atomic_inc(&attr.srq->usecnt); if (ind_tbl) atomic_inc(&ind_tbl->usecnt); + } else { + /* It is done in _ib_create_qp for other QP types */ + qp->uobject = &obj->uevent.uobject; } obj->uevent.uobject.object = qp; -- cgit v1.2.3 From 7324f5399b06cdbbd1520b8fde8024035953179d Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 20 Feb 2018 14:32:04 +0100 Subject: virtio_net: disable XDP_REDIRECT in receive_mergeable() case The virtio_net code have three different RX code-paths in receive_buf(). Two of these code paths can handle XDP, but one of them is broken for at least XDP_REDIRECT. Function(1): receive_big() does not support XDP. Function(2): receive_small() support XDP fully and uses build_skb(). Function(3): receive_mergeable() broken XDP_REDIRECT uses napi_alloc_skb(). The simple explanation is that receive_mergeable() is broken because it uses napi_alloc_skb(), which violates XDP given XDP assumes packet header+data in single page and enough tail room for skb_shared_info. The longer explaination is that receive_mergeable() tries to work-around and satisfy these XDP requiresments e.g. by having a function xdp_linearize_page() that allocates and memcpy RX buffers around (in case packet is scattered across multiple rx buffers). This does currently satisfy XDP_PASS, XDP_DROP and XDP_TX (but only because we have not implemented bpf_xdp_adjust_tail yet). The XDP_REDIRECT action combined with cpumap is broken, and cause hard to debug crashes. The main issue is that the RX packet does not have the needed tail-room (SKB_DATA_ALIGN(skb_shared_info)), causing skb_shared_info to overlap the next packets head-room (in which cpumap stores info). Reproducing depend on the packet payload length and if RX-buffer size happened to have tail-room for skb_shared_info or not. But to make this even harder to troubleshoot, the RX-buffer size is runtime dynamically change based on an Exponentially Weighted Moving Average (EWMA) over the packet length, when refilling RX rings. This patch only disable XDP_REDIRECT support in receive_mergeable() case, because it can cause a real crash. IMHO we should consider NOT supporting XDP in receive_mergeable() at all, because the principles behind XDP are to gain speed by (1) code simplicity, (2) sacrificing memory and (3) where possible moving runtime checks to setup time. These principles are clearly being violated in receive_mergeable(), that e.g. runtime track average buffer size to save memory consumption. In the longer run, we should consider introducing a separate receive function when attaching an XDP program, and also change the memory model to be compatible with XDP when attaching an XDP prog. Fixes: 186b3c998c50 ("virtio-net: support XDP_REDIRECT") Signed-off-by: Jesper Dangaard Brouer Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 626c27352ae2..0ca91942a884 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -677,7 +677,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, struct bpf_prog *xdp_prog; unsigned int truesize; unsigned int headroom = mergeable_ctx_to_headroom(ctx); - int err; head_skb = NULL; @@ -754,12 +753,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, goto err_xdp; rcu_read_unlock(); goto xdp_xmit; - case XDP_REDIRECT: - err = xdp_do_redirect(dev, &xdp, xdp_prog); - if (!err) - *xdp_xmit = true; - rcu_read_unlock(); - goto xdp_xmit; default: bpf_warn_invalid_xdp_action(act); case XDP_ABORTED: -- cgit v1.2.3 From 95dbe9e7b3720efa5cf83d21f44f6d953f7cf4a2 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 20 Feb 2018 14:32:10 +0100 Subject: virtio_net: fix XDP code path in receive_small() When configuring virtio_net to use the code path 'receive_small()', in-order to get correct XDP_REDIRECT support, I discovered TCP packets would get silently dropped when loading an XDP program action XDP_PASS. The bug seems to be that receive_small() when XDP is loaded check that hdr->hdr.flags is zero, which seems wrong as hdr.flags contains the flags VIRTIO_NET_HDR_F_* : #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start, csum_offset */ #define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */ TCP got dropped as it had the VIRTIO_NET_HDR_F_DATA_VALID flag set. The flags that are relevant here are the VIRTIO_NET_HDR_GSO_* flags stored in hdr->hdr.gso_type. Thus, the fix is just check that none of the gso_type flags have been set. Fixes: bb91accf2733 ("virtio-net: XDP support for small buffers") Signed-off-by: Jesper Dangaard Brouer Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 0ca91942a884..10c8fc46b588 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -558,7 +558,7 @@ static struct sk_buff *receive_small(struct net_device *dev, void *orig_data; u32 act; - if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags)) + if (unlikely(hdr->hdr.gso_type)) goto err_xdp; if (unlikely(xdp_headroom < virtnet_get_headroom(vi))) { -- cgit v1.2.3 From 11b7d897ccc1fb5a3d3f9eb1e6b4574671e5dd7d Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 20 Feb 2018 14:32:15 +0100 Subject: virtio_net: fix memory leak in XDP_REDIRECT XDP_REDIRECT calling xdp_do_redirect() can fail for multiple reasons (which can be inspected by tracepoints). The current semantics is that on failure the driver calling xdp_do_redirect() must handle freeing or recycling the page associated with this frame. This can be seen as an optimization, as drivers usually have an optimized XDP_DROP code path for frame recycling in place already. The virtio_net driver didn't handle when xdp_do_redirect() failed. This caused a memory leak as the page refcnt wasn't decremented on failures. The function __virtnet_xdp_xmit() did handle one type of failure, when the xmit queue virtqueue_add_outbuf() is full, which "hides" releasing a refcnt on the page. Instead the function __virtnet_xdp_xmit() must follow API of xdp_do_redirect(), which on errors leave it up to the caller to free the page, of the failed send operation. Fixes: 186b3c998c50 ("virtio-net: support XDP_REDIRECT") Signed-off-by: Jesper Dangaard Brouer Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 10c8fc46b588..1e0e0fce3ab2 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -443,12 +443,8 @@ static bool __virtnet_xdp_xmit(struct virtnet_info *vi, sg_init_one(sq->sg, xdp->data, xdp->data_end - xdp->data); err = virtqueue_add_outbuf(sq->vq, sq->sg, 1, xdp->data, GFP_ATOMIC); - if (unlikely(err)) { - struct page *page = virt_to_head_page(xdp->data); - - put_page(page); - return false; - } + if (unlikely(err)) + return false; /* Caller handle free/refcnt */ return true; } @@ -546,8 +542,11 @@ static struct sk_buff *receive_small(struct net_device *dev, unsigned int buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); struct page *page = virt_to_head_page(buf); - unsigned int delta = 0, err; + unsigned int delta = 0; struct page *xdp_page; + bool sent; + int err; + len -= vi->hdr_len; rcu_read_lock(); @@ -596,16 +595,19 @@ static struct sk_buff *receive_small(struct net_device *dev, delta = orig_data - xdp.data; break; case XDP_TX: - if (unlikely(!__virtnet_xdp_xmit(vi, &xdp))) + sent = __virtnet_xdp_xmit(vi, &xdp); + if (unlikely(!sent)) { trace_xdp_exception(vi->dev, xdp_prog, act); - else - *xdp_xmit = true; + goto err_xdp; + } + *xdp_xmit = true; rcu_read_unlock(); goto xdp_xmit; case XDP_REDIRECT: err = xdp_do_redirect(dev, &xdp, xdp_prog); - if (!err) - *xdp_xmit = true; + if (err) + goto err_xdp; + *xdp_xmit = true; rcu_read_unlock(); goto xdp_xmit; default: @@ -677,6 +679,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, struct bpf_prog *xdp_prog; unsigned int truesize; unsigned int headroom = mergeable_ctx_to_headroom(ctx); + bool sent; head_skb = NULL; @@ -745,10 +748,14 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, } break; case XDP_TX: - if (unlikely(!__virtnet_xdp_xmit(vi, &xdp))) + sent = __virtnet_xdp_xmit(vi, &xdp); + if (unlikely(!sent)) { trace_xdp_exception(vi->dev, xdp_prog, act); - else - *xdp_xmit = true; + if (unlikely(xdp_page != page)) + put_page(xdp_page); + goto err_xdp; + } + *xdp_xmit = true; if (unlikely(xdp_page != page)) goto err_xdp; rcu_read_unlock(); -- cgit v1.2.3 From 8dcc5b0ab0ec9a2efb3362d380272546b8b2ee26 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 20 Feb 2018 14:32:20 +0100 Subject: virtio_net: fix ndo_xdp_xmit crash towards dev not ready for XDP When a driver implements the ndo_xdp_xmit() function, there is (currently) no generic way to determine whether it is safe to call. It is e.g. unsafe to call the drivers ndo_xdp_xmit, if it have not allocated the needed XDP TX queues yet. This is the case for virtio_net, which first allocates the XDP TX queues once an XDP/bpf prog is attached (in virtnet_xdp_set()). Thus, a crash will occur for virtio_net when redirecting to another virtio_net device's ndo_xdp_xmit, which have not attached a XDP prog. The sample xdp_redirect_map tries to attach a dummy XDP prog to take this into account, but it can also easily fail if the virtio_net (or actually underlying vhost driver) have not allocated enough extra queues for the device. Allocating more queue this is currently a manual config. Hint for libvirt XML add: The solution in this patch is to check that the device have loaded an XDP/bpf prog before proceeding. This is similar to the check performed in driver ixgbe. Signed-off-by: Jesper Dangaard Brouer Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 1e0e0fce3ab2..9bb9e562b893 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -452,8 +452,18 @@ static bool __virtnet_xdp_xmit(struct virtnet_info *vi, static int virtnet_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp) { struct virtnet_info *vi = netdev_priv(dev); - bool sent = __virtnet_xdp_xmit(vi, xdp); + struct receive_queue *rq = vi->rq; + struct bpf_prog *xdp_prog; + bool sent; + + /* Only allow ndo_xdp_xmit if XDP is loaded on dev, as this + * indicate XDP resources have been successfully allocated. + */ + xdp_prog = rcu_dereference(rq->xdp_prog); + if (!xdp_prog) + return -ENXIO; + sent = __virtnet_xdp_xmit(vi, xdp); if (!sent) return -ENOSPC; return 0; -- cgit v1.2.3 From cfd092f2db8b4b6727e1c03ef68a7842e1023573 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Tue, 20 Feb 2018 15:22:05 -0600 Subject: amd-xgbe: Restore PCI interrupt enablement setting on resume After resuming from suspend, the PCI device support must re-enable the interrupt setting so that interrupts are actually delivered. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index 3e5833cf1fab..eb23f9ba1a9a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -426,6 +426,8 @@ static int xgbe_pci_resume(struct pci_dev *pdev) struct net_device *netdev = pdata->netdev; int ret = 0; + XP_IOWRITE(pdata, XP_INT_EN, 0x1fffff); + pdata->lpm_ctrl &= ~MDIO_CTRL1_LPOWER; XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl); -- cgit v1.2.3 From 7ba716698cc53f8d5367766c93c538c7da6c68ce Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Wed, 21 Feb 2018 14:45:39 -0800 Subject: mm, swap, frontswap: fix THP swap if frontswap enabled It was reported by Sergey Senozhatsky that if THP (Transparent Huge Page) and frontswap (via zswap) are both enabled, when memory goes low so that swap is triggered, segfault and memory corruption will occur in random user space applications as follow, kernel: urxvt[338]: segfault at 20 ip 00007fc08889ae0d sp 00007ffc73a7fc40 error 6 in libc-2.26.so[7fc08881a000+1ae000] #0 0x00007fc08889ae0d _int_malloc (libc.so.6) #1 0x00007fc08889c2f3 malloc (libc.so.6) #2 0x0000560e6004bff7 _Z14rxvt_wcstoutf8PKwi (urxvt) #3 0x0000560e6005e75c n/a (urxvt) #4 0x0000560e6007d9f1 _ZN16rxvt_perl_interp6invokeEP9rxvt_term9hook_typez (urxvt) #5 0x0000560e6003d988 _ZN9rxvt_term9cmd_parseEv (urxvt) #6 0x0000560e60042804 _ZN9rxvt_term6pty_cbERN2ev2ioEi (urxvt) #7 0x0000560e6005c10f _Z17ev_invoke_pendingv (urxvt) #8 0x0000560e6005cb55 ev_run (urxvt) #9 0x0000560e6003b9b9 main (urxvt) #10 0x00007fc08883af4a __libc_start_main (libc.so.6) #11 0x0000560e6003f9da _start (urxvt) After bisection, it was found the first bad commit is bd4c82c22c36 ("mm, THP, swap: delay splitting THP after swapped out"). The root cause is as follows: When the pages are written to swap device during swapping out in swap_writepage(), zswap (fontswap) is tried to compress the pages to improve performance. But zswap (frontswap) will treat THP as a normal page, so only the head page is saved. After swapping in, tail pages will not be restored to their original contents, causing memory corruption in the applications. This is fixed by refusing to save page in the frontswap store functions if the page is a THP. So that the THP will be swapped out to swap device. Another choice is to split THP if frontswap is enabled. But it is found that the frontswap enabling isn't flexible. For example, if CONFIG_ZSWAP=y (cannot be module), frontswap will be enabled even if zswap itself isn't enabled. Frontswap has multiple backends, to make it easy for one backend to enable THP support, the THP checking is put in backend frontswap store functions instead of the general interfaces. Link: http://lkml.kernel.org/r/20180209084947.22749-1-ying.huang@intel.com Fixes: bd4c82c22c367e068 ("mm, THP, swap: delay splitting THP after swapped out") Signed-off-by: "Huang, Ying" Reported-by: Sergey Senozhatsky Tested-by: Sergey Senozhatsky Suggested-by: Minchan Kim [put THP checking in backend] Cc: Konrad Rzeszutek Wilk Cc: Dan Streetman Cc: Seth Jennings Cc: Tetsuo Handa Cc: Shaohua Li Cc: Michal Hocko Cc: Johannes Weiner Cc: Mel Gorman Cc: Shakeel Butt Cc: Boris Ostrovsky Cc: Juergen Gross Cc: [4.14] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/xen/tmem.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c index bf13d1ec51f3..04e7b3b29bac 100644 --- a/drivers/xen/tmem.c +++ b/drivers/xen/tmem.c @@ -284,6 +284,10 @@ static int tmem_frontswap_store(unsigned type, pgoff_t offset, int pool = tmem_frontswap_poolid; int ret; + /* THP isn't supported */ + if (PageTransHuge(page)) + return -1; + if (pool < 0) return -1; if (ind64 != ind) -- cgit v1.2.3 From 7801c545e706674aeed40256eb806ad37b18ad71 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sun, 7 Jan 2018 14:49:05 +0100 Subject: soc: imx: gpc: de-register power domains only if initialized If power domain information are missing in the device tree, no power domains get initialized. However, imx_gpc_remove tries to remove power domains always in the old DT binding case. Only remove power domains when imx_gpc_probe initialized them in first place. Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver") Signed-off-by: Stefan Agner Reviewed-by: Lucas Stach Reviewed-by: Fabio Estevam Signed-off-by: Shawn Guo --- drivers/soc/imx/gpc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index 53f7275d6cbd..62bb724726d9 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c @@ -470,13 +470,21 @@ static int imx_gpc_probe(struct platform_device *pdev) static int imx_gpc_remove(struct platform_device *pdev) { + struct device_node *pgc_node; int ret; + pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc"); + + /* bail out if DT too old and doesn't provide the necessary info */ + if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") && + !pgc_node) + return 0; + /* * If the old DT binding is used the toplevel driver needs to * de-register the power domains */ - if (!of_get_child_by_name(pdev->dev.of_node, "pgc")) { + if (!pgc_node) { of_genpd_del_provider(pdev->dev.of_node); ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base); -- cgit v1.2.3 From a275b315334dea3c2151094765387ede421aac92 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 15 Jan 2018 13:21:48 -0200 Subject: clk: imx51-imx53: Fix UART4/5 registration on i.MX50 and i.MX53 Since commit 59dc3d8c8673 ("clk: imx51: uart4, uart5 gates only exist on imx50, imx53") the following warnings are seen on i.MX53: [ 2.776190] ------------[ cut here ]------------ [ 2.780948] WARNING: CPU: 0 PID: 1 at ../drivers/clk/clk.c:811 clk_core_disable+0xc4/0xe0 [ 2.789145] Modules linked in: [ 2.792236] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc7-next-20180115 #1 [ 2.799735] Hardware name: Freescale i.MX53 (Device Tree Support) [ 2.805845] Backtrace: [ 2.808329] [] (dump_backtrace) from [] (show_stack+0x18/0x1c) [ 2.815919] r7:00000000 r6:60000093 r5:00000000 r4:c10798d4 [ 2.821607] [] (show_stack) from [] (dump_stack+0xb4/0xe8) [ 2.828854] [] (dump_stack) from [] (__warn+0xf0/0x11c) [ 2.835837] r9:00000000 r8:0000032b r7:00000009 r6:c0d429f8 r5:00000000 r4:00000000 [ 2.843601] [] (__warn) from [] (warn_slowpath_null+0x44/0x50) [ 2.851191] r8:c1008908 r7:c0e08874 r6:c04bfac8 r5:0000032b r4:c0d429f8 [ 2.857913] [] (warn_slowpath_null) from [] (clk_core_disable+0xc4/0xe0) [ 2.866369] r6:dc02bb00 r5:dc02a980 r4:dc02a980 [ 2.871011] [] (clk_core_disable) from [] (clk_core_disable_lock+0x20/0x2c) [ 2.879726] r5:dc02a980 r4:80000013 [ 2.883323] [] (clk_core_disable_lock) from [] (clk_disable+0x24/0x28) [ 2.891604] r5:c0f6b3e4 r4:0000001c [ 2.895209] [] (clk_disable) from [] (imx_clk_disable_uart+0x50/0x68) [ 2.903412] [] (imx_clk_disable_uart) from [] (do_one_initcall+0x50/0x19c) [ 2.912043] r7:c0e08874 r6:c0f63854 r5:c0f233bc r4:ffffe000 [ 2.917726] [] (do_one_initcall) from [] (kernel_init_freeable+0x118/0x1d0) [ 2.926447] r9:c0f63858 r8:000000f0 r7:c0e08874 r6:c0f63854 r5:c107b500 r4:c0f75260 [ 2.934220] [] (kernel_init_freeable) from [] (kernel_init+0x10/0x118) [ 2.942506] r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c0a4a5e0 [ 2.950351] r4:00000000 [ 2.952908] [] (kernel_init) from [] (ret_from_fork+0x14/0x20) [ 2.960496] Exception stack(0xdc05dfb0 to 0xdc05dff8) [ 2.965569] dfa0: 00000000 00000000 00000000 00000000 [ 2.973768] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 2.981965] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 [ 2.988596] r5:c0a4a5e0 r4:00000000 [ 2.992188] ---[ end trace 346e26f708876edd ]--- [ 2.997420] ------------[ cut here ]------------ In order to fix the problem UART4/5 registration needs to happen only on i.MX50 and i.MX53. So let mx51_clocks_init() register only UART1-3 and mx50_clocks_init()/mx53_clocks_init register all the UART1-5 ports. Fixes: 59dc3d8c8673 ("clk: imx51: uart4, uart5 gates only exist on imx50, imx53") Signed-off-by: Fabio Estevam Reviewed-by: Philipp Zabel Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx51-imx53.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx51-imx53.c b/drivers/clk/imx/clk-imx51-imx53.c index c864992e6983..caa8bd40692c 100644 --- a/drivers/clk/imx/clk-imx51-imx53.c +++ b/drivers/clk/imx/clk-imx51-imx53.c @@ -131,7 +131,17 @@ static const char *ieee1588_sels[] = { "pll3_sw", "pll4_sw", "dummy" /* usbphy2_ static struct clk *clk[IMX5_CLK_END]; static struct clk_onecell_data clk_data; -static struct clk ** const uart_clks[] __initconst = { +static struct clk ** const uart_clks_mx51[] __initconst = { + &clk[IMX5_CLK_UART1_IPG_GATE], + &clk[IMX5_CLK_UART1_PER_GATE], + &clk[IMX5_CLK_UART2_IPG_GATE], + &clk[IMX5_CLK_UART2_PER_GATE], + &clk[IMX5_CLK_UART3_IPG_GATE], + &clk[IMX5_CLK_UART3_PER_GATE], + NULL +}; + +static struct clk ** const uart_clks_mx50_mx53[] __initconst = { &clk[IMX5_CLK_UART1_IPG_GATE], &clk[IMX5_CLK_UART1_PER_GATE], &clk[IMX5_CLK_UART2_IPG_GATE], @@ -321,8 +331,6 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk_prepare_enable(clk[IMX5_CLK_TMAX1]); clk_prepare_enable(clk[IMX5_CLK_TMAX2]); /* esdhc2, fec */ clk_prepare_enable(clk[IMX5_CLK_TMAX3]); /* esdhc1, esdhc4 */ - - imx_register_uart_clocks(uart_clks); } static void __init mx50_clocks_init(struct device_node *np) @@ -388,6 +396,8 @@ static void __init mx50_clocks_init(struct device_node *np) r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000); clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r); + + imx_register_uart_clocks(uart_clks_mx50_mx53); } CLK_OF_DECLARE(imx50_ccm, "fsl,imx50-ccm", mx50_clocks_init); @@ -477,6 +487,8 @@ static void __init mx51_clocks_init(struct device_node *np) val = readl(MXC_CCM_CLPCR); val |= 1 << 23; writel(val, MXC_CCM_CLPCR); + + imx_register_uart_clocks(uart_clks_mx51); } CLK_OF_DECLARE(imx51_ccm, "fsl,imx51-ccm", mx51_clocks_init); @@ -606,5 +618,7 @@ static void __init mx53_clocks_init(struct device_node *np) r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000); clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r); + + imx_register_uart_clocks(uart_clks_mx50_mx53); } CLK_OF_DECLARE(imx53_ccm, "fsl,imx53-ccm", mx53_clocks_init); -- cgit v1.2.3 From 9cfad4a5f4f795715c8657fb7dc22574a6046327 Mon Sep 17 00:00:00 2001 From: "Michael Kelley (EOSG)" Date: Wed, 24 Jan 2018 22:14:08 +0000 Subject: scsi: storvsc: Spread interrupts when picking a channel for I/O requests Update the algorithm in storvsc_do_io to look for a channel starting with the current CPU + 1 and wrap around (within the current NUMA node). This spreads VMbus interrupts more evenly across CPUs. Previous code always started with first CPU in the current NUMA node, skewing the interrupt load to that CPU. Signed-off-by: Michael Kelley Reviewed-by: Long Li Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 8eadb30115aa..620510787763 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1310,7 +1310,8 @@ static int storvsc_do_io(struct hv_device *device, */ cpumask_and(&alloced_mask, &stor_device->alloced_cpus, cpumask_of_node(cpu_to_node(q_num))); - for_each_cpu(tgt_cpu, &alloced_mask) { + for_each_cpu_wrap(tgt_cpu, &alloced_mask, + outgoing_channel->target_cpu + 1) { if (tgt_cpu != outgoing_channel->target_cpu) { outgoing_channel = stor_device->stor_chns[tgt_cpu]; -- cgit v1.2.3 From 9ff549ffb4fb4cc9a4b24d1de9dc3e68287797c4 Mon Sep 17 00:00:00 2001 From: Mauricio Faria de Oliveira Date: Fri, 16 Feb 2018 20:39:57 -0200 Subject: scsi: mpt3sas: fix oops in error handlers after shutdown/unload This patch adds checks for 'ioc->remove_host' in the SCSI error handlers, so not to access pointers/resources potentially freed in the PCI shutdown/module unload path. The error handlers may be invoked after shutdown/unload, depending on other components. This problem was observed with kexec on a system with a mpt3sas based adapter and an infiniband adapter which takes long enough to shutdown: The mpt3sas driver finished shutting down / disabled interrupt handling, thus some commands have not finished and timed out. Since the system was still running (waiting for the infiniband adapter to shutdown), the scsi error handler for task abort of mpt3sas was invoked, and hit an oops -- either in scsih_abort() because 'ioc->scsi_lookup' was NULL without commit dbec4c9040ed ("scsi: mpt3sas: lockless command submission"), or later up in scsih_host_reset() (with or without that commit), because it eventually called mpt3sas_base_get_iocstate(). After the above commit, the oops in scsih_abort() does not occur anymore (_scsih_scsi_lookup_find_by_scmd() is no longer called), but that commit is too big and out of the scope of linux-stable, where this patch might help, so still go for the changes. Also, this might help to prevent similar errors in the future, in case code changes and possibly tries to access freed stuff. Note the fix in scsih_host_reset() is still important anyway. Signed-off-by: Mauricio Faria de Oliveira Acked-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 74fca184dba9..5ab3caffa08b 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -2835,7 +2835,8 @@ scsih_abort(struct scsi_cmnd *scmd) _scsih_tm_display_info(ioc, scmd); sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { + if (!sas_device_priv_data || !sas_device_priv_data->sas_target || + ioc->remove_host) { sdev_printk(KERN_INFO, scmd->device, "device been deleted! scmd(%p)\n", scmd); scmd->result = DID_NO_CONNECT << 16; @@ -2898,7 +2899,8 @@ scsih_dev_reset(struct scsi_cmnd *scmd) _scsih_tm_display_info(ioc, scmd); sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { + if (!sas_device_priv_data || !sas_device_priv_data->sas_target || + ioc->remove_host) { sdev_printk(KERN_INFO, scmd->device, "device been deleted! scmd(%p)\n", scmd); scmd->result = DID_NO_CONNECT << 16; @@ -2961,7 +2963,8 @@ scsih_target_reset(struct scsi_cmnd *scmd) _scsih_tm_display_info(ioc, scmd); sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { + if (!sas_device_priv_data || !sas_device_priv_data->sas_target || + ioc->remove_host) { starget_printk(KERN_INFO, starget, "target been deleted! scmd(%p)\n", scmd); scmd->result = DID_NO_CONNECT << 16; @@ -3019,7 +3022,7 @@ scsih_host_reset(struct scsi_cmnd *scmd) ioc->name, scmd); scsi_print_command(scmd); - if (ioc->is_driver_loading) { + if (ioc->is_driver_loading || ioc->remove_host) { pr_info(MPT3SAS_FMT "Blocking the host reset\n", ioc->name); r = FAILED; -- cgit v1.2.3 From c666d3be99c000bb889a33353e9be0fa5808d3de Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 16 Feb 2018 20:39:58 -0200 Subject: scsi: mpt3sas: wait for and flush running commands on shutdown/unload This patch finishes all outstanding SCSI IO commands (but not other commands, e.g., task management) in the shutdown and unload paths. It first waits for the commands to complete (this is done after setting 'ioc->remove_host = 1 ', which prevents new commands to be queued) then it flushes commands that might still be running. This avoids triggering error handling (e.g., abort command) for all commands possibly completed by the adapter after interrupts disabled. [mauricfo: introduced something in commit message.] Signed-off-by: Sreekanth Reddy Tested-by: Mauricio Faria de Oliveira Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 8 ++++---- drivers/scsi/mpt3sas/mpt3sas_base.h | 3 +++ drivers/scsi/mpt3sas/mpt3sas_scsih.c | 10 +++++++++- 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 59a87ca328d3..0aafbfd1b746 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -6297,14 +6297,14 @@ _base_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) } /** - * _wait_for_commands_to_complete - reset controller + * mpt3sas_wait_for_commands_to_complete - reset controller * @ioc: Pointer to MPT_ADAPTER structure * * This function is waiting 10s for all pending commands to complete * prior to putting controller in reset. */ -static void -_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc) +void +mpt3sas_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc) { u32 ioc_state; @@ -6377,7 +6377,7 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, is_fault = 1; } _base_reset_handler(ioc, MPT3_IOC_PRE_RESET); - _wait_for_commands_to_complete(ioc); + mpt3sas_wait_for_commands_to_complete(ioc); _base_mask_interrupts(ioc); r = _base_make_ioc_ready(ioc, type); if (r) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 789bc421424b..99ccf83b8c51 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -1433,6 +1433,9 @@ void mpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, int mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc); +void +mpt3sas_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc); + /* scsih shared API */ struct scsi_cmnd *mpt3sas_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc, diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 5ab3caffa08b..c2ea13c7e37e 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -4456,7 +4456,7 @@ _scsih_flush_running_cmds(struct MPT3SAS_ADAPTER *ioc) st = scsi_cmd_priv(scmd); mpt3sas_base_clear_st(ioc, st); scsi_dma_unmap(scmd); - if (ioc->pci_error_recovery) + if (ioc->pci_error_recovery || ioc->remove_host) scmd->result = DID_NO_CONNECT << 16; else scmd->result = DID_RESET << 16; @@ -9742,6 +9742,10 @@ static void scsih_remove(struct pci_dev *pdev) unsigned long flags; ioc->remove_host = 1; + + mpt3sas_wait_for_commands_to_complete(ioc); + _scsih_flush_running_cmds(ioc); + _scsih_fw_event_cleanup_queue(ioc); spin_lock_irqsave(&ioc->fw_event_lock, flags); @@ -9818,6 +9822,10 @@ scsih_shutdown(struct pci_dev *pdev) unsigned long flags; ioc->remove_host = 1; + + mpt3sas_wait_for_commands_to_complete(ioc); + _scsih_flush_running_cmds(ioc); + _scsih_fw_event_cleanup_queue(ioc); spin_lock_irqsave(&ioc->fw_event_lock, flags); -- cgit v1.2.3 From 5a1e59533380a3fd04593e4ab2d4633ebf7745c1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 22 Feb 2018 07:24:08 -0800 Subject: nvme-fabrics: don't check for non-NULL module in nvmf_register_transport THIS_MODULE evaluates to NULL when used from code built into the kernel, thus breaking built-in transport modules. Remove the bogus check. Fixes: 0de5cd36 ("nvme-fabrics: protect against module unload during create_ctrl") Signed-off-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Reviewed-by: Johannes Thumshirn Signed-off-by: Keith Busch --- drivers/nvme/host/fabrics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 5dd4ceefed8f..a1c58e35075e 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -493,7 +493,7 @@ EXPORT_SYMBOL_GPL(nvmf_should_reconnect); */ int nvmf_register_transport(struct nvmf_transport_ops *ops) { - if (!ops->create_ctrl || !ops->module) + if (!ops->create_ctrl) return -EINVAL; down_write(&nvmf_transports_rwsem); -- cgit v1.2.3 From 0d30992395b1ed0e006960de1651b44cd51be791 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 22 Feb 2018 07:24:09 -0800 Subject: nvme-rdma: use blk_rq_payload_bytes instead of blk_rq_bytes blk_rq_bytes does the wrong thing for special payloads like discards and might cause the driver to not set up a SGL. Signed-off-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Reviewed-by: Johannes Thumshirn Signed-off-by: Keith Busch --- drivers/nvme/host/rdma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 2bc059f7d73c..acc9eb21c242 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -1051,7 +1051,7 @@ static void nvme_rdma_unmap_data(struct nvme_rdma_queue *queue, struct nvme_rdma_device *dev = queue->device; struct ib_device *ibdev = dev->dev; - if (!blk_rq_bytes(rq)) + if (!blk_rq_payload_bytes(rq)) return; if (req->mr) { @@ -1166,7 +1166,7 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue, c->common.flags |= NVME_CMD_SGL_METABUF; - if (!blk_rq_bytes(rq)) + if (!blk_rq_payload_bytes(rq)) return nvme_rdma_set_sg_null(c); req->sg_table.sgl = req->first_sgl; -- cgit v1.2.3 From 796b0b8d8dea191d9f64e0be8ab58d8f3586bcde Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 22 Feb 2018 07:24:10 -0800 Subject: nvmet-loop: use blk_rq_payload_bytes for sgl selection blk_rq_bytes does the wrong thing for special payloads like discards and might cause the driver to not set up a SGL. Signed-off-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Reviewed-by: Johannes Thumshirn Signed-off-by: Keith Busch --- drivers/nvme/target/loop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c index 7991ec3a17db..861d1509b22b 100644 --- a/drivers/nvme/target/loop.c +++ b/drivers/nvme/target/loop.c @@ -184,7 +184,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx, return BLK_STS_OK; } - if (blk_rq_bytes(req)) { + if (blk_rq_payload_bytes(req)) { iod->sg_table.sgl = iod->first_sgl; if (sg_alloc_table_chained(&iod->sg_table, blk_rq_nr_phys_segments(req), @@ -193,7 +193,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx, iod->req.sg = iod->sg_table.sgl; iod->req.sg_cnt = blk_rq_map_sg(req->q, req, iod->sg_table.sgl); - iod->req.transfer_len = blk_rq_bytes(req); + iod->req.transfer_len = blk_rq_payload_bytes(req); } blk_mq_start_request(req); -- cgit v1.2.3 From f97a6b6c47d2f329a24f92cc0ca3c6df5727ba73 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 6 Feb 2018 14:59:43 +0100 Subject: s390/cio: fix ccw_device_start_timeout API There are cases a device driver can't start IO because the device is currently in use by cio. In this case the device driver is notified when the device is usable again. Using ccw_device_start_timeout we would set the timeout (and change an existing timeout) before we test for internal usage. Worst case this could lead to an unexpected timer deletion. Fix this by setting the timeout after we test for internal usage. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_ops.c | 72 +++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 1caf6a398760..75ce12a24dc2 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -159,7 +159,7 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) } /** - * ccw_device_start_key() - start a s390 channel program with key + * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key * @cdev: target ccw device * @cpa: logical start address of channel program * @intparm: user specific interruption parameter; will be presented back to @@ -170,10 +170,15 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) * @key: storage key to be used for the I/O * @flags: additional flags; defines the action to be performed for I/O * processing. + * @expires: timeout value in jiffies * * Start a S/390 channel program. When the interrupt arrives, the * IRQ handler is called, either immediately, delayed (dev-end missing, * or sense required) or never (no IRQ handler registered). + * This function notifies the device driver if the channel program has not + * completed during the time specified by @expires. If a timeout occurs, the + * channel program is terminated via xsch, hsch or csch, and the device's + * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). * Returns: * %0, if the operation was successful; * -%EBUSY, if the device is busy, or status pending; @@ -182,9 +187,9 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) * Context: * Interrupts disabled, ccw device lock held */ -int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, __u8 key, - unsigned long flags) +int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, __u8 key, + unsigned long flags, int expires) { struct subchannel *sch; int ret; @@ -224,6 +229,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, switch (ret) { case 0: cdev->private->intparm = intparm; + if (expires) + ccw_device_set_timeout(cdev, expires); break; case -EACCES: case -ENODEV: @@ -234,7 +241,7 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, } /** - * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key + * ccw_device_start_key() - start a s390 channel program with key * @cdev: target ccw device * @cpa: logical start address of channel program * @intparm: user specific interruption parameter; will be presented back to @@ -245,15 +252,10 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, * @key: storage key to be used for the I/O * @flags: additional flags; defines the action to be performed for I/O * processing. - * @expires: timeout value in jiffies * * Start a S/390 channel program. When the interrupt arrives, the * IRQ handler is called, either immediately, delayed (dev-end missing, * or sense required) or never (no IRQ handler registered). - * This function notifies the device driver if the channel program has not - * completed during the time specified by @expires. If a timeout occurs, the - * channel program is terminated via xsch, hsch or csch, and the device's - * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). * Returns: * %0, if the operation was successful; * -%EBUSY, if the device is busy, or status pending; @@ -262,19 +264,12 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, * Context: * Interrupts disabled, ccw device lock held */ -int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, __u8 key, - unsigned long flags, int expires) +int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, __u8 key, + unsigned long flags) { - int ret; - - if (!cdev) - return -ENODEV; - ccw_device_set_timeout(cdev, expires); - ret = ccw_device_start_key(cdev, cpa, intparm, lpm, key, flags); - if (ret != 0) - ccw_device_set_timeout(cdev, 0); - return ret; + return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm, key, + flags, 0); } /** @@ -489,18 +484,20 @@ void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id) EXPORT_SYMBOL(ccw_device_get_id); /** - * ccw_device_tm_start_key() - perform start function + * ccw_device_tm_start_timeout_key() - perform start function * @cdev: ccw device on which to perform the start function * @tcw: transport-command word to be started * @intparm: user defined parameter to be passed to the interrupt handler * @lpm: mask of paths to use * @key: storage key to use for storage access + * @expires: time span in jiffies after which to abort request * * Start the tcw on the given ccw device. Return zero on success, non-zero * otherwise. */ -int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm, u8 key) +int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, + unsigned long intparm, u8 lpm, u8 key, + int expires) { struct subchannel *sch; int rc; @@ -527,37 +524,32 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, return -EACCES; } rc = cio_tm_start_key(sch, tcw, lpm, key); - if (rc == 0) + if (rc == 0) { cdev->private->intparm = intparm; + if (expires) + ccw_device_set_timeout(cdev, expires); + } return rc; } -EXPORT_SYMBOL(ccw_device_tm_start_key); +EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); /** - * ccw_device_tm_start_timeout_key() - perform start function + * ccw_device_tm_start_key() - perform start function * @cdev: ccw device on which to perform the start function * @tcw: transport-command word to be started * @intparm: user defined parameter to be passed to the interrupt handler * @lpm: mask of paths to use * @key: storage key to use for storage access - * @expires: time span in jiffies after which to abort request * * Start the tcw on the given ccw device. Return zero on success, non-zero * otherwise. */ -int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm, u8 key, - int expires) +int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, + unsigned long intparm, u8 lpm, u8 key) { - int ret; - - ccw_device_set_timeout(cdev, expires); - ret = ccw_device_tm_start_key(cdev, tcw, intparm, lpm, key); - if (ret != 0) - ccw_device_set_timeout(cdev, 0); - return ret; + return ccw_device_tm_start_timeout_key(cdev, tcw, intparm, lpm, key, 0); } -EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); +EXPORT_SYMBOL(ccw_device_tm_start_key); /** * ccw_device_tm_start() - perform start function -- cgit v1.2.3 From 770b55c995d171f026a9efb85e71e3b1ea47b93d Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 7 Feb 2018 13:18:19 +0100 Subject: s390/cio: fix return code after missing interrupt When a timeout occurs for users of ccw_device_start_timeout we will stop the IO and call the drivers int handler with the irb pointer set to ERR_PTR(-ETIMEDOUT). Sometimes however we'd set the irb pointer to ERR_PTR(-EIO) which is not intended. Just set the correct value in all codepaths. Reported-by: Julian Wiedmann Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_fsm.c | 6 ++++-- drivers/s390/cio/io_sch.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 1319122e9d12..384f085698a7 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -795,6 +795,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) ccw_device_set_timeout(cdev, 0); cdev->private->iretry = 255; + cdev->private->async_kill_io_rc = -ETIMEDOUT; ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); @@ -871,7 +872,7 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) /* OK, i/o is dead now. Call interrupt handler. */ if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - ERR_PTR(-EIO)); + ERR_PTR(cdev->private->async_kill_io_rc)); } static void @@ -888,7 +889,7 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) ccw_device_online_verify(cdev, 0); if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - ERR_PTR(-EIO)); + ERR_PTR(cdev->private->async_kill_io_rc)); } void ccw_device_kill_io(struct ccw_device *cdev) @@ -896,6 +897,7 @@ void ccw_device_kill_io(struct ccw_device *cdev) int ret; cdev->private->iretry = 255; + cdev->private->async_kill_io_rc = -EIO; ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index af571d8d6925..90e4e3a7841b 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h @@ -157,6 +157,7 @@ struct ccw_device_private { unsigned long intparm; /* user interruption parameter */ struct qdio_irq *qdio_data; struct irb irb; /* device status */ + int async_kill_io_rc; struct senseid senseid; /* SenseID info */ struct pgid pgid[8]; /* path group IDs per chpid*/ struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ -- cgit v1.2.3 From 410d5e13e7638bc146321671e223d56495fbf3c7 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Mon, 12 Feb 2018 12:01:03 +0100 Subject: s390/cio: clear timer when terminating driver I/O When we terminate driver I/O (because we need to stop using a certain channel path) we also need to ensure that a timer (which may have been set up using ccw_device_start_timeout) is cleared. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_fsm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 384f085698a7..9169af7dbb43 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -896,6 +896,7 @@ void ccw_device_kill_io(struct ccw_device *cdev) { int ret; + ccw_device_set_timeout(cdev, 0); cdev->private->iretry = 255; cdev->private->async_kill_io_rc = -EIO; ret = ccw_device_cancel_halt_clear(cdev); -- cgit v1.2.3 From ed7158bae41044ff696e9aafd5ada46d391a5a2e Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 22 Feb 2018 10:54:55 +0100 Subject: treewide/trivial: Remove ';;$' typo noise On lkml suggestions were made to split up such trivial typo fixes into per subsystem patches: --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -439,7 +439,7 @@ setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height) struct efi_uga_draw_protocol *uga = NULL, *first_uga; efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID; unsigned long nr_ugas; - u32 *handles = (u32 *)uga_handle;; + u32 *handles = (u32 *)uga_handle; efi_status_t status = EFI_INVALID_PARAMETER; int i; This patch is the result of the following script: $ sed -i 's/;;$/;/g' $(git grep -E ';;$' | grep "\.[ch]:" | grep -vwE 'for|ia64' | cut -d: -f1 | sort | uniq) ... followed by manual review to make sure it's all good. Splitting this up is just crazy talk, let's get over with this and just do it. Reported-by: Pavel Machek Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- drivers/clocksource/mips-gic-timer.c | 4 ++-- drivers/clocksource/timer-sun5i.c | 2 +- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 2 +- drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 2 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 2 +- drivers/gpu/drm/scheduler/gpu_scheduler.c | 2 +- drivers/iommu/intel-svm.c | 2 +- drivers/md/raid1.c | 2 +- drivers/soc/imx/gpc.c | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index a04808a21d4e..65e18c86d9b9 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -205,12 +205,12 @@ static int __init gic_clocksource_of_init(struct device_node *node) } else if (of_property_read_u32(node, "clock-frequency", &gic_frequency)) { pr_err("GIC frequency not specified.\n"); - return -EINVAL;; + return -EINVAL; } gic_timer_irq = irq_of_parse_and_map(node, 0); if (!gic_timer_irq) { pr_err("GIC timer IRQ not specified.\n"); - return -EINVAL;; + return -EINVAL; } ret = __gic_clocksource_init(); diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index 2a3fe83ec337..3b56ea3f52af 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -334,7 +334,7 @@ static int __init sun5i_timer_init(struct device_node *node) timer_base = of_io_request_and_map(node, 0, of_node_full_name(node)); if (IS_ERR(timer_base)) { pr_err("Can't map registers\n"); - return PTR_ERR(timer_base);; + return PTR_ERR(timer_base); } irq = irq_of_parse_and_map(node, 0); 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 61e8c3e02d16..33d91e4474ea 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 @@ -718,7 +718,7 @@ static enum link_training_result perform_channel_equalization_sequence( uint32_t retries_ch_eq; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_align_status_updated dpcd_lane_status_updated = {{0}}; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}};; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}}; hw_tr_pattern = get_supported_tp(link); diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 4c3223a4d62b..adb6e7b9280c 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -162,7 +162,7 @@ static int pp_hw_init(void *handle) if(hwmgr->smumgr_funcs->start_smu(pp_handle->hwmgr)) { pr_err("smc start failed\n"); hwmgr->smumgr_funcs->smu_fini(pp_handle->hwmgr); - return -EINVAL;; + return -EINVAL; } if (ret == PP_DPM_DISABLED) goto exit; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 3e9bba4d6624..6d8e3a9a6fc0 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -680,7 +680,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) } else { dev_info(&pdev->dev, "no iommu, fallback to phys contig buffers for scanout\n"); - aspace = NULL;; + aspace = NULL; } pm_runtime_put_sync(&pdev->dev); diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index 2c18996d59c5..0d95888ccc3e 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -461,7 +461,7 @@ void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched, struct drm_sched_jo { struct drm_sched_job *s_job; struct drm_sched_entity *entity, *tmp; - int i;; + int i; spin_lock(&sched->job_list_lock); list_for_each_entry_reverse(s_job, &sched->ring_mirror_list, node) { diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c index 35a408d0ae4f..99bc9bd64b9e 100644 --- a/drivers/iommu/intel-svm.c +++ b/drivers/iommu/intel-svm.c @@ -205,7 +205,7 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d * for example, an "address" value of 0x12345f000 will * flush from 0x123440000 to 0x12347ffff (256KiB). */ unsigned long last = address + ((unsigned long)(pages - 1) << VTD_PAGE_SHIFT); - unsigned long mask = __rounddown_pow_of_two(address ^ last);; + unsigned long mask = __rounddown_pow_of_two(address ^ last); desc.high = QI_DEV_EIOTLB_ADDR((address & ~mask) | (mask - 1)) | QI_DEV_EIOTLB_SIZE; } else { diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index b2eae332e1a2..f978eddc7a21 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1108,7 +1108,7 @@ static void alloc_behind_master_bio(struct r1bio *r1_bio, bio_copy_data(behind_bio, bio); skip_copy: - r1_bio->behind_master_bio = behind_bio;; + r1_bio->behind_master_bio = behind_bio; set_bit(R1BIO_BehindIO, &r1_bio->state); return; diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index 53f7275d6cbd..cfb42f5eccb2 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c @@ -348,7 +348,7 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap, if (i == 1) { domain->supply = devm_regulator_get(dev, "pu"); if (IS_ERR(domain->supply)) - return PTR_ERR(domain->supply);; + return PTR_ERR(domain->supply); ret = imx_pgc_get_clocks(dev, domain); if (ret) -- cgit v1.2.3 From fe32a815f05c8568669a062587435e15f9345764 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 8 Feb 2018 14:54:05 +0100 Subject: i2c: bcm2835: Set up the rising/falling edge delays We were leaving them in the power on state (or the state the firmware had set up for some client, if we were taking over from them). The boot state was 30 core clocks, when we actually want to sample some time after (to make sure that the new input bit has actually arrived). Signed-off-by: Eric Anholt Signed-off-by: Boris Brezillon Signed-off-by: Wolfram Sang Cc: stable@kernel.org --- drivers/i2c/busses/i2c-bcm2835.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index cd07a69e2e93..44deae78913e 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -50,6 +50,9 @@ #define BCM2835_I2C_S_CLKT BIT(9) #define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */ +#define BCM2835_I2C_FEDL_SHIFT 16 +#define BCM2835_I2C_REDL_SHIFT 0 + #define BCM2835_I2C_CDIV_MIN 0x0002 #define BCM2835_I2C_CDIV_MAX 0xFFFE @@ -81,7 +84,7 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg) static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev) { - u32 divider; + u32 divider, redl, fedl; divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk), i2c_dev->bus_clk_rate); @@ -100,6 +103,22 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev) bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider); + /* + * Number of core clocks to wait after falling edge before + * outputting the next data bit. Note that both FEDL and REDL + * can't be greater than CDIV/2. + */ + fedl = max(divider / 16, 1u); + + /* + * Number of core clocks to wait after rising edge before + * sampling the next incoming data bit. + */ + redl = max(divider / 4, 1u); + + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL, + (fedl << BCM2835_I2C_FEDL_SHIFT) | + (redl << BCM2835_I2C_REDL_SHIFT)); return 0; } -- cgit v1.2.3 From c396b9a03e3bb5e95e036bdb0c7d614e0e1a4e3d Mon Sep 17 00:00:00 2001 From: Patryk Kocielnik Date: Fri, 26 Jan 2018 21:19:26 +0100 Subject: i2c: busses: i2c-sirf: Fix spelling: "formular" -> "formula". Fix spelling. Signed-off-by: Patryk Kocielnik [wsa: fixed "Initialization", too] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sirf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c index 2fd8b6d00391..87197ece0f90 100644 --- a/drivers/i2c/busses/i2c-sirf.c +++ b/drivers/i2c/busses/i2c-sirf.c @@ -341,7 +341,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, adap); init_completion(&siic->done); - /* Controller Initalisation */ + /* Controller initialisation */ writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL); while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) @@ -369,7 +369,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) * but they start to affect the speed when clock is set to faster * frequencies. * Through the actual tests, use the different user_div value(which - * in the divider formular 'Fio / (Fi2c * user_div)') to adapt + * in the divider formula 'Fio / (Fi2c * user_div)') to adapt * the different ranges of i2c bus clock frequency, to make the SCL * more accurate. */ -- cgit v1.2.3 From d1fa74520dcdbeae891b30035e6c51aafa35306d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 17 Feb 2018 22:58:43 +0200 Subject: i2c: designware: Consider SCL GPIO optional GPIO library can return -ENOSYS for the failed request. Instead of failing ->probe() in this case override error code to 0. Fixes: ca382f5b38f3 ("i2c: designware: add i2c gpio recovery option") Reported-by: Dominik Brodowski Signed-off-by: Andy Shevchenko Tested-by: Dominik Brodowski Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-master.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 55926ef41ef1..05732531829f 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -644,7 +644,7 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) gpio = devm_gpiod_get(dev->dev, "scl", GPIOD_OUT_HIGH); if (IS_ERR(gpio)) { r = PTR_ERR(gpio); - if (r == -ENOENT) + if (r == -ENOENT || r == -ENOSYS) return 0; return r; } -- cgit v1.2.3 From 8f1f25534fff09f54d75ea8fac4ea8f35fb385d6 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 16 Feb 2018 18:39:32 +0100 Subject: drm/sun4i: backend: Assign the pipes automatically Since we now have a way to enforce the zpos, check for the number of alpha planes, the only missing part is to assign our pipe automatically instead of hardcoding it. The algorithm is quite simple, but requires two iterations over the list of planes. In the first one (which is the same one that we've had to check for alpha, the frontend usage, and so on), we order the planes by their zpos. We can then do a second iteration over that array by ascending zpos starting with the pipe 0. When and if we encounter our alpha plane, we put it and all the other subsequent planes in the second pipe. Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/e9caf21d831438d36a3ccc7cef229c9a7ea7f69f.1518802627.git-series.maxime.ripard@bootlin.com --- drivers/gpu/drm/sun4i/sun4i_backend.c | 40 +++++++++++++++++++++++++++++++++-- drivers/gpu/drm/sun4i/sun4i_layer.c | 6 ------ drivers/gpu/drm/sun4i/sun4i_layer.h | 1 + 3 files changed, 39 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 245b189fc4d8..f387420bda8d 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -275,12 +275,16 @@ int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer, struct drm_plane *plane) { struct drm_plane_state *state = plane->state; + struct sun4i_layer_state *p_state = state_to_sun4i_layer_state(state); unsigned int priority = state->normalized_zpos; + unsigned int pipe = p_state->pipe; - DRM_DEBUG_DRIVER("Setting layer %d's priority to %d\n", layer, priority); - + DRM_DEBUG_DRIVER("Setting layer %d's priority to %d and pipe %d\n", + layer, priority, pipe); regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer), + SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK | SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK, + SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(p_state->pipe) | SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(priority)); return 0; @@ -325,12 +329,15 @@ static void sun4i_backend_atomic_begin(struct sunxi_engine *engine, static int sun4i_backend_atomic_check(struct sunxi_engine *engine, struct drm_crtc_state *crtc_state) { + struct drm_plane_state *plane_states[SUN4I_BACKEND_NUM_LAYERS] = { 0 }; struct drm_atomic_state *state = crtc_state->state; struct drm_device *drm = state->dev; struct drm_plane *plane; unsigned int num_planes = 0; unsigned int num_alpha_planes = 0; unsigned int num_frontend_planes = 0; + unsigned int current_pipe = 0; + unsigned int i; DRM_DEBUG_DRIVER("Starting checking our planes\n"); @@ -361,9 +368,19 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, if (fb->format->has_alpha) num_alpha_planes++; + DRM_DEBUG_DRIVER("Plane zpos is %d\n", + plane_state->normalized_zpos); + + /* Sort our planes by Zpos */ + plane_states[plane_state->normalized_zpos] = plane_state; + num_planes++; } + /* All our planes were disabled, bail out */ + if (!num_planes) + return 0; + /* * The hardware is a bit unusual here. * @@ -400,6 +417,25 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, return -EINVAL; } + /* We can't have an alpha plane at the lowest position */ + if (plane_states[0]->fb->format->has_alpha) + return -EINVAL; + + for (i = 1; i < num_planes; i++) { + struct drm_plane_state *p_state = plane_states[i]; + struct drm_framebuffer *fb = p_state->fb; + struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(p_state); + + /* + * The only alpha position is the lowest plane of the + * second pipe. + */ + if (fb->format->has_alpha) + current_pipe++; + + s_state->pipe = current_pipe; + } + if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) { DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n"); return -EINVAL; diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 19be798e4fac..3e3d554713cb 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -220,12 +220,6 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm, drm_plane_create_zpos_immutable_property(&layer->plane, i); - DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n", - i ? "overlay" : "primary", plane->pipe); - regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i), - SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK, - SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe)); - layer->id = i; planes[i] = &layer->plane; }; diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h index 75b4868ba87c..36b20265bd31 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.h +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h @@ -24,6 +24,7 @@ struct sun4i_layer { struct sun4i_layer_state { struct drm_plane_state state; + unsigned int pipe; bool uses_frontend; }; -- cgit v1.2.3 From 70d2850ee39d3be86b484cd1f15545e0038109ff Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 16 Feb 2018 18:39:33 +0100 Subject: drm/sun4i: Remove the plane description structure The plane description structure was mostly needed to differentiate the formats usable on the primary plane (because of its lowest position), and assign the pipes. Now that both are dynamically checked and assigned, we can remove the static definition. Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/6b09e3698e692c3338f70a5ae1e5a580f9dd08ee.1518802627.git-series.maxime.ripard@bootlin.com --- drivers/gpu/drm/sun4i/sun4i_layer.c | 44 +++++++------------------------------ 1 file changed, 8 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 3e3d554713cb..85cc7e9461b3 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -19,13 +19,6 @@ #include "sun4i_layer.h" #include "sunxi_engine.h" -struct sun4i_plane_desc { - enum drm_plane_type type; - u8 pipe; - const uint32_t *formats; - uint32_t nformats; -}; - static void sun4i_backend_layer_reset(struct drm_plane *plane) { struct sun4i_layer *layer = plane_to_sun4i_layer(plane); @@ -133,14 +126,7 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = { .update_plane = drm_atomic_helper_update_plane, }; -static const uint32_t sun4i_backend_layer_formats_primary[] = { - DRM_FORMAT_ARGB8888, - DRM_FORMAT_RGB888, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, -}; - -static const uint32_t sun4i_backend_layer_formats_overlay[] = { +static const uint32_t sun4i_backend_layer_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_ARGB4444, DRM_FORMAT_ARGB1555, @@ -151,24 +137,9 @@ static const uint32_t sun4i_backend_layer_formats_overlay[] = { DRM_FORMAT_XRGB8888, }; -static const struct sun4i_plane_desc sun4i_backend_planes[] = { - { - .type = DRM_PLANE_TYPE_PRIMARY, - .pipe = 0, - .formats = sun4i_backend_layer_formats_primary, - .nformats = ARRAY_SIZE(sun4i_backend_layer_formats_primary), - }, - { - .type = DRM_PLANE_TYPE_OVERLAY, - .pipe = 1, - .formats = sun4i_backend_layer_formats_overlay, - .nformats = ARRAY_SIZE(sun4i_backend_layer_formats_overlay), - }, -}; - static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, struct sun4i_backend *backend, - const struct sun4i_plane_desc *plane) + enum drm_plane_type type) { struct sun4i_layer *layer; int ret; @@ -180,8 +151,9 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, /* possible crtcs are set later */ ret = drm_universal_plane_init(drm, &layer->plane, 0, &sun4i_backend_layer_funcs, - plane->formats, plane->nformats, - NULL, plane->type, NULL); + sun4i_backend_layer_formats, + ARRAY_SIZE(sun4i_backend_layer_formats), + NULL, type, NULL); if (ret) { dev_err(drm->dev, "Couldn't initialize layer\n"); return ERR_PTR(ret); @@ -207,11 +179,11 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm, if (!planes) return ERR_PTR(-ENOMEM); - for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) { - const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i]; + for (i = 0; i < SUN4I_BACKEND_NUM_LAYERS; i++) { + enum drm_plane_type type = i ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY; struct sun4i_layer *layer; - layer = sun4i_layer_init_one(drm, backend, plane); + layer = sun4i_layer_init_one(drm, backend, type); if (IS_ERR(layer)) { dev_err(drm->dev, "Couldn't initialize %s plane\n", i ? "overlay" : "primary"); -- cgit v1.2.3 From ded4f346ac168e45b9d25a08a069915699bce1df Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 16 Feb 2018 18:39:34 +0100 Subject: drm/sun4i: backend: Make zpos configurable Now that we have everything in place, we can make zpos configurable now. Change the zpos property from an immutable one to a regular. Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/0ab187956855db86972d936e6751181649e0d035.1518802627.git-series.maxime.ripard@bootlin.com --- drivers/gpu/drm/sun4i/sun4i_layer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 85cc7e9461b3..33ad377569ec 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -163,6 +163,9 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, &sun4i_backend_layer_helper_funcs); layer->backend = backend; + drm_plane_create_zpos_property(&layer->plane, 0, 0, + SUN4I_BACKEND_NUM_LAYERS - 1); + return layer; } @@ -190,8 +193,6 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm, return ERR_CAST(layer); }; - drm_plane_create_zpos_immutable_property(&layer->plane, i); - layer->id = i; planes[i] = &layer->plane; }; -- cgit v1.2.3 From 35152d1159dbb0277b18ae664dfb5b11c27fdefa Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 16 Feb 2018 18:39:36 +0100 Subject: drm/sun4i: backend: Remove ARGB spoofing We've had some code for quite some time to prevent the alpha bug from happening on the lowest primary plane. Since we now check for this in our atomic_check, we can simply remove it. Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/965180afd8169ccaa848f061d16a2c1a9ec4d289.1518802627.git-series.maxime.ripard@bootlin.com --- drivers/gpu/drm/sun4i/sun4i_backend.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index f387420bda8d..092ade4ff6a5 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -92,13 +92,8 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend, SUN4I_BACKEND_MODCTL_LAY_EN(layer), val); } -static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane, - u32 format, u32 *mode) +static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode) { - if (plane && (plane->type == DRM_PLANE_TYPE_PRIMARY) && - (format == DRM_FORMAT_ARGB8888)) - format = DRM_FORMAT_XRGB8888; - switch (format) { case DRM_FORMAT_ARGB8888: *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB8888; @@ -191,8 +186,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n", interlaced ? "on" : "off"); - ret = sun4i_backend_drm_format_to_layer(plane, fb->format->format, - &val); + ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val); if (ret) { DRM_DEBUG_DRIVER("Invalid format\n"); return ret; @@ -211,7 +205,7 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend, u32 val; int ret; - ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val); + ret = sun4i_backend_drm_format_to_layer(fmt, &val); if (ret) { DRM_DEBUG_DRIVER("Invalid format\n"); return ret; -- cgit v1.2.3 From 4751cf733a1170876dd5ac46f225f5a25f59a67f Mon Sep 17 00:00:00 2001 From: Oleksandr Andrushchenko Date: Thu, 22 Feb 2018 08:09:19 +0200 Subject: drm/simple_kms_helper: Fix NULL pointer dereference with no active CRTC It is possible that drm_simple_kms_plane_atomic_check called with no CRTC set, e.g. when user-space application sets CRTC_ID/FB_ID to 0 before doing any actual drawing. This leads to NULL pointer dereference because in this case new CRTC state is NULL and must be checked before accessing. Signed-off-by: Oleksandr Andrushchenko Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/1519279759-7803-1-git-send-email-andr2000@gmail.com --- drivers/gpu/drm/drm_simple_kms_helper.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 6c327fdbaaee..2d324a5515f9 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -112,12 +112,6 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, pipe = container_of(plane, struct drm_simple_display_pipe, plane); crtc_state = drm_atomic_get_new_crtc_state(plane_state->state, &pipe->crtc); - if (!crtc_state->enable) - return 0; /* nothing to check when disabling or disabled */ - - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, &clip, @@ -128,7 +122,9 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, return ret; if (!plane_state->visible) - return -EINVAL; + return 0; + + drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2); if (!pipe->funcs || !pipe->funcs->check) return 0; -- cgit v1.2.3 From 588717061002778158f7e4772b3dfc645612983d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Feb 2018 12:47:51 +0100 Subject: drm: fix drm_get_max_iomem type mismatch When comparing two variables with min()/max(), they should be the same type: drivers/gpu/drm/drm_memory.c: In function 'drm_get_max_iomem': include/linux/kernel.h:821:16: error: comparison of distinct pointer types lacks a cast [-Werror] (void) (&max1 == &max2); This makes the local variable in drm_get_max_iomem make the type from resource->end. Fixes: 82626363a217 ("drm: add func to get max iomem address v2") Signed-off-by: Arnd Bergmann Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20180222114804.1394300-1-arnd@arndb.de --- drivers/gpu/drm/drm_memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c index 7ca500b8c399..3c54044214db 100644 --- a/drivers/gpu/drm/drm_memory.c +++ b/drivers/gpu/drm/drm_memory.c @@ -153,7 +153,7 @@ EXPORT_SYMBOL(drm_legacy_ioremapfree); u64 drm_get_max_iomem(void) { struct resource *tmp; - u64 max_iomem = 0; + resource_size_t max_iomem = 0; for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) { max_iomem = max(max_iomem, tmp->end); -- cgit v1.2.3 From ac86cba96e2a439883d452772013049f54df2042 Mon Sep 17 00:00:00 2001 From: Oleksandr Andrushchenko Date: Mon, 12 Feb 2018 10:52:51 +0200 Subject: drm/simple_kms_helper: Add {enable|disable}_vblank callback support If simple_kms_helper based driver needs to work with vblanks, then it has to provide drm_driver.{enable|disable}_vblank callbacks, because drm_simple_kms_helper.drm_crtc_funcs does not provide any. At the same time drm_driver.{enable|disable}_vblank callbacks are marked as deprecated and shouldn't be used by new drivers. Fix this by extending drm_simple_kms_helper.drm_crtc_funcs to provide the missing callbacks. Signed-off-by: Oleksandr Andrushchenko Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/1518425574-32671-2-git-send-email-andr2000@gmail.com --- drivers/gpu/drm/drm_simple_kms_helper.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 2d324a5515f9..6808f732f285 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -92,6 +92,28 @@ static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = { .atomic_disable = drm_simple_kms_crtc_disable, }; +static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc) +{ + struct drm_simple_display_pipe *pipe; + + pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); + if (!pipe->funcs || !pipe->funcs->enable_vblank) + return 0; + + return pipe->funcs->enable_vblank(pipe); +} + +static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc) +{ + struct drm_simple_display_pipe *pipe; + + pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); + if (!pipe->funcs || !pipe->funcs->disable_vblank) + return; + + pipe->funcs->disable_vblank(pipe); +} + static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = { .reset = drm_atomic_helper_crtc_reset, .destroy = drm_crtc_cleanup, @@ -99,6 +121,8 @@ static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = { .page_flip = drm_atomic_helper_page_flip, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = drm_simple_kms_crtc_enable_vblank, + .disable_vblank = drm_simple_kms_crtc_disable_vblank, }; static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, -- cgit v1.2.3 From 989c48e6c2d1bfca604cf2d9e7e026e0a19d856c Mon Sep 17 00:00:00 2001 From: Oleksandr Andrushchenko Date: Mon, 12 Feb 2018 10:52:52 +0200 Subject: drm/mxsfb: Do not use deprecated drm_driver.{enable|disable)_vblank Do not use deprecated drm_driver.{enable|disable)_vblank callbacks, but use drm_simple_kms_helpe's pipe callbacks instead. Signed-off-by: Oleksandr Andrushchenko Cc: Marek Vasut Reviewed-by: Marek Vasut Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/1518425574-32671-3-git-send-email-andr2000@gmail.com --- drivers/gpu/drm/mxsfb/mxsfb_drv.c | 54 ++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 1207ffe36250..5cae8db9dcd4 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -131,11 +131,37 @@ static int mxsfb_pipe_prepare_fb(struct drm_simple_display_pipe *pipe, return drm_gem_fb_prepare_fb(&pipe->plane, plane_state); } +static int mxsfb_pipe_enable_vblank(struct drm_simple_display_pipe *pipe) +{ + struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); + + /* Clear and enable VBLANK IRQ */ + mxsfb_enable_axi_clk(mxsfb); + writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); + writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET); + mxsfb_disable_axi_clk(mxsfb); + + return 0; +} + +static void mxsfb_pipe_disable_vblank(struct drm_simple_display_pipe *pipe) +{ + struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); + + /* Disable and clear VBLANK IRQ */ + mxsfb_enable_axi_clk(mxsfb); + writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR); + writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); + mxsfb_disable_axi_clk(mxsfb); +} + static struct drm_simple_display_pipe_funcs mxsfb_funcs = { .enable = mxsfb_pipe_enable, .disable = mxsfb_pipe_disable, .update = mxsfb_pipe_update, .prepare_fb = mxsfb_pipe_prepare_fb, + .enable_vblank = mxsfb_pipe_enable_vblank, + .disable_vblank = mxsfb_pipe_disable_vblank, }; static int mxsfb_load(struct drm_device *drm, unsigned long flags) @@ -274,33 +300,11 @@ static void mxsfb_lastclose(struct drm_device *drm) drm_fbdev_cma_restore_mode(mxsfb->fbdev); } -static int mxsfb_enable_vblank(struct drm_device *drm, unsigned int crtc) -{ - struct mxsfb_drm_private *mxsfb = drm->dev_private; - - /* Clear and enable VBLANK IRQ */ - mxsfb_enable_axi_clk(mxsfb); - writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); - writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET); - mxsfb_disable_axi_clk(mxsfb); - - return 0; -} - -static void mxsfb_disable_vblank(struct drm_device *drm, unsigned int crtc) +static void mxsfb_irq_preinstall(struct drm_device *drm) { struct mxsfb_drm_private *mxsfb = drm->dev_private; - /* Disable and clear VBLANK IRQ */ - mxsfb_enable_axi_clk(mxsfb); - writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR); - writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); - mxsfb_disable_axi_clk(mxsfb); -} - -static void mxsfb_irq_preinstall(struct drm_device *drm) -{ - mxsfb_disable_vblank(drm, 0); + mxsfb_pipe_disable_vblank(&mxsfb->pipe); } static irqreturn_t mxsfb_irq_handler(int irq, void *data) @@ -333,8 +337,6 @@ static struct drm_driver mxsfb_driver = { .irq_handler = mxsfb_irq_handler, .irq_preinstall = mxsfb_irq_preinstall, .irq_uninstall = mxsfb_irq_preinstall, - .enable_vblank = mxsfb_enable_vblank, - .disable_vblank = mxsfb_disable_vblank, .gem_free_object_unlocked = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, .dumb_create = drm_gem_cma_dumb_create, -- cgit v1.2.3 From df91972fe32ee5054cef8851169c4dff83793cd3 Mon Sep 17 00:00:00 2001 From: Oleksandr Andrushchenko Date: Mon, 12 Feb 2018 10:52:53 +0200 Subject: drm/tve200: Do not use deprecated drm_driver.{enable|disable)_vblank Do not use deprecated drm_driver.{enable|disable)_vblank callbacks, but use drm_simple_kms_helpe's pipe callbacks instead. Signed-off-by: Oleksandr Andrushchenko Cc: Linus Walleij Reviewed-by: Linus Walleij Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/1518425574-32671-4-git-send-email-andr2000@gmail.com --- drivers/gpu/drm/tve200/tve200_display.c | 10 ++++++++-- drivers/gpu/drm/tve200/tve200_drm.h | 2 -- drivers/gpu/drm/tve200/tve200_drv.c | 3 --- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/tve200/tve200_display.c b/drivers/gpu/drm/tve200/tve200_display.c index 2c668bd6d997..db397fcb345a 100644 --- a/drivers/gpu/drm/tve200/tve200_display.c +++ b/drivers/gpu/drm/tve200/tve200_display.c @@ -273,16 +273,20 @@ static void tve200_display_update(struct drm_simple_display_pipe *pipe, } } -int tve200_enable_vblank(struct drm_device *drm, unsigned int crtc) +static int tve200_display_enable_vblank(struct drm_simple_display_pipe *pipe) { + struct drm_crtc *crtc = &pipe->crtc; + struct drm_device *drm = crtc->dev; struct tve200_drm_dev_private *priv = drm->dev_private; writel(TVE200_INT_V_STATUS, priv->regs + TVE200_INT_EN); return 0; } -void tve200_disable_vblank(struct drm_device *drm, unsigned int crtc) +static void tve200_display_disable_vblank(struct drm_simple_display_pipe *pipe) { + struct drm_crtc *crtc = &pipe->crtc; + struct drm_device *drm = crtc->dev; struct tve200_drm_dev_private *priv = drm->dev_private; writel(0, priv->regs + TVE200_INT_EN); @@ -300,6 +304,8 @@ static const struct drm_simple_display_pipe_funcs tve200_display_funcs = { .disable = tve200_display_disable, .update = tve200_display_update, .prepare_fb = tve200_display_prepare_fb, + .enable_vblank = tve200_display_enable_vblank, + .disable_vblank = tve200_display_disable_vblank, }; int tve200_display_init(struct drm_device *drm) diff --git a/drivers/gpu/drm/tve200/tve200_drm.h b/drivers/gpu/drm/tve200/tve200_drm.h index 5c270055bd58..1ba4380f489b 100644 --- a/drivers/gpu/drm/tve200/tve200_drm.h +++ b/drivers/gpu/drm/tve200/tve200_drm.h @@ -113,8 +113,6 @@ struct tve200_drm_dev_private { container_of(x, struct tve200_drm_connector, connector) int tve200_display_init(struct drm_device *dev); -int tve200_enable_vblank(struct drm_device *drm, unsigned int crtc); -void tve200_disable_vblank(struct drm_device *drm, unsigned int crtc); irqreturn_t tve200_irq(int irq, void *data); int tve200_connector_init(struct drm_device *dev); int tve200_encoder_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c index 44911d921864..ac344ddb23bc 100644 --- a/drivers/gpu/drm/tve200/tve200_drv.c +++ b/drivers/gpu/drm/tve200/tve200_drv.c @@ -162,9 +162,6 @@ static struct drm_driver tve200_drm_driver = { .gem_free_object_unlocked = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, - .enable_vblank = tve200_enable_vblank, - .disable_vblank = tve200_disable_vblank, - .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_import = drm_gem_prime_import, -- cgit v1.2.3 From 6c7d091008d0d095adb3f65d667a234d372f4472 Mon Sep 17 00:00:00 2001 From: Oleksandr Andrushchenko Date: Mon, 12 Feb 2018 10:52:54 +0200 Subject: drm/pl111: Do not use deprecated drm_driver.{enable|disable)_vblank Do not use deprecated drm_driver.{enable|disable)_vblank callbacks, but use drm_simple_kms_helpe's pipe callbacks instead. Signed-off-by: Oleksandr Andrushchenko Cc: Eric Anholt Reviewed-by: Eric Anholt Tested-by: Eric Anholt Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/1518425574-32671-5-git-send-email-andr2000@gmail.com --- drivers/gpu/drm/pl111/pl111_display.c | 15 ++++++++++++--- drivers/gpu/drm/pl111/pl111_drm.h | 2 -- drivers/gpu/drm/pl111/pl111_drv.c | 5 ----- 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index d75923896609..5b8368c76734 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c @@ -321,8 +321,10 @@ static void pl111_display_update(struct drm_simple_display_pipe *pipe, } } -int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc) +static int pl111_display_enable_vblank(struct drm_simple_display_pipe *pipe) { + struct drm_crtc *crtc = &pipe->crtc; + struct drm_device *drm = crtc->dev; struct pl111_drm_dev_private *priv = drm->dev_private; writel(CLCD_IRQ_NEXTBASE_UPDATE, priv->regs + priv->ienb); @@ -330,8 +332,10 @@ int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc) return 0; } -void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc) +static void pl111_display_disable_vblank(struct drm_simple_display_pipe *pipe) { + struct drm_crtc *crtc = &pipe->crtc; + struct drm_device *drm = crtc->dev; struct pl111_drm_dev_private *priv = drm->dev_private; writel(0, priv->regs + priv->ienb); @@ -343,7 +347,7 @@ static int pl111_display_prepare_fb(struct drm_simple_display_pipe *pipe, return drm_gem_fb_prepare_fb(&pipe->plane, plane_state); } -static const struct drm_simple_display_pipe_funcs pl111_display_funcs = { +static struct drm_simple_display_pipe_funcs pl111_display_funcs = { .check = pl111_display_check, .enable = pl111_display_enable, .disable = pl111_display_disable, @@ -502,6 +506,11 @@ int pl111_display_init(struct drm_device *drm) if (ret) return ret; + if (!priv->variant->broken_vblank) { + pl111_display_funcs.enable_vblank = pl111_display_enable_vblank; + pl111_display_funcs.disable_vblank = pl111_display_disable_vblank; + } + ret = drm_simple_display_pipe_init(drm, &priv->pipe, &pl111_display_funcs, priv->variant->formats, diff --git a/drivers/gpu/drm/pl111/pl111_drm.h b/drivers/gpu/drm/pl111/pl111_drm.h index 6d0e450e51b1..8e252b561e2c 100644 --- a/drivers/gpu/drm/pl111/pl111_drm.h +++ b/drivers/gpu/drm/pl111/pl111_drm.h @@ -79,8 +79,6 @@ struct pl111_drm_dev_private { }; int pl111_display_init(struct drm_device *dev); -int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc); -void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc); irqreturn_t pl111_irq(int irq, void *data); int pl111_debugfs_init(struct drm_minor *minor); diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index 1231905150d0..a7a3a49956c5 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -249,11 +249,6 @@ static int pl111_amba_probe(struct amba_device *amba_dev, if (!priv) return -ENOMEM; - if (!variant->broken_vblank) { - pl111_drm_driver.enable_vblank = pl111_enable_vblank; - pl111_drm_driver.disable_vblank = pl111_disable_vblank; - } - drm = drm_dev_alloc(&pl111_drm_driver, dev); if (IS_ERR(drm)) return PTR_ERR(drm); -- cgit v1.2.3 From 88e80c62671ceecdbb77c902731ec95a4bfa62f9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 20 Feb 2018 21:42:26 -0800 Subject: smsc75xx: fix smsc75xx_set_features() If an attempt is made to disable RX checksums, USB adapter is changed but netdev->features is not, because smsc75xx_set_features() returns a non zero value. This throws errors from netdev_rx_csum_fault() : : hw csum failure Signed-off-by: Eric Dumazet Cc: Steve Glendinning Signed-off-by: David S. Miller --- drivers/net/usb/smsc75xx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index d0a113743195..7a6a1fe79309 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -954,10 +954,11 @@ static int smsc75xx_set_features(struct net_device *netdev, /* it's racing here! */ ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); - if (ret < 0) + if (ret < 0) { netdev_warn(dev->net, "Error writing RFE_CTL\n"); - - return ret; + return ret; + } + return 0; } static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm) -- cgit v1.2.3 From 83090e7d35caaabc8daa65fd698275951455bbec Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 22 Feb 2018 09:24:59 +1100 Subject: net/smc9194: Remove bogus CONFIG_MAC reference AFAIK the only version of smc9194.c with Mac support is the one in the linux-mac68k CVS repo, which never made it to the mainline. Despite that, from v2.3.45, arch/m68k/config.in listed CONFIG_SMC9194 under CONFIG_MAC. This mistake got carried over into Kconfig in v2.5.55. (See pre-git era "[PATCH] add m68k dependencies to net driver config".) Signed-off-by: Finn Thain Signed-off-by: David S. Miller --- drivers/net/ethernet/smsc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig index 63aca9f847e1..4c2f612e4414 100644 --- a/drivers/net/ethernet/smsc/Kconfig +++ b/drivers/net/ethernet/smsc/Kconfig @@ -20,7 +20,7 @@ if NET_VENDOR_SMSC config SMC9194 tristate "SMC 9194 support" - depends on (ISA || MAC && BROKEN) + depends on ISA select CRC32 ---help--- This is support for the SMC9xxx based Ethernet cards. Choose this -- cgit v1.2.3 From a2c0f039bbd0f9ebf375176d05b056e3f3b5c4f7 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 21 Feb 2018 18:18:30 -0600 Subject: ibmvnic: Fix early release of login buffer The login buffer is released before the driver can perform sanity checks between resources the driver requested and what firmware will provide. Don't release the login buffer until the sanity check is performed. Fixes: 34f0f4e3f488 ("ibmvnic: Fix login buffer memory leaks") Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 1495cb99f924..1b3cc8bb0705 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -3760,7 +3760,6 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq, dma_unmap_single(dev, adapter->login_buf_token, adapter->login_buf_sz, DMA_BIDIRECTIONAL); - release_login_buffer(adapter); dma_unmap_single(dev, adapter->login_rsp_buf_token, adapter->login_rsp_buf_sz, DMA_BIDIRECTIONAL); @@ -3791,6 +3790,7 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq, ibmvnic_remove(adapter->vdev); return -EIO; } + release_login_buffer(adapter); complete(&adapter->init_done); return 0; -- cgit v1.2.3 From 370c10522e96bf1b2e7fd9e906dbe8fb5be895d2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 22 Feb 2018 12:11:55 +0300 Subject: net: aquantia: Fix error handling in aq_pci_probe() We should check "self->aq_hw" for allocation failure, and also we should free it on the error paths. Fixes: 23ee07ad3c2f ("net: aquantia: Cleanup pci functions module") Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index 22889fc158f2..87c4308b52a7 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -226,6 +226,10 @@ static int aq_pci_probe(struct pci_dev *pdev, goto err_ioremap; self->aq_hw = kzalloc(sizeof(*self->aq_hw), GFP_KERNEL); + if (!self->aq_hw) { + err = -ENOMEM; + goto err_ioremap; + } self->aq_hw->aq_nic_cfg = aq_nic_get_cfg(self); for (bar = 0; bar < 4; ++bar) { @@ -235,19 +239,19 @@ static int aq_pci_probe(struct pci_dev *pdev, mmio_pa = pci_resource_start(pdev, bar); if (mmio_pa == 0U) { err = -EIO; - goto err_ioremap; + goto err_free_aq_hw; } reg_sz = pci_resource_len(pdev, bar); if ((reg_sz <= 24 /*ATL_REGS_SIZE*/)) { err = -EIO; - goto err_ioremap; + goto err_free_aq_hw; } self->aq_hw->mmio = ioremap_nocache(mmio_pa, reg_sz); if (!self->aq_hw->mmio) { err = -EIO; - goto err_ioremap; + goto err_free_aq_hw; } break; } @@ -255,7 +259,7 @@ static int aq_pci_probe(struct pci_dev *pdev, if (bar == 4) { err = -EIO; - goto err_ioremap; + goto err_free_aq_hw; } numvecs = min((u8)AQ_CFG_VECS_DEF, @@ -290,6 +294,8 @@ err_register: aq_pci_free_irq_vectors(self); err_hwinit: iounmap(self->aq_hw->mmio); +err_free_aq_hw: + kfree(self->aq_hw); err_ioremap: free_netdev(ndev); err_pci_func: -- cgit v1.2.3 From fd9b503dec9b533afa49ac105ce65f87419b5528 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 11 Feb 2018 11:38:40 +0100 Subject: drm/panel: Fix ARM Versatile panel clocks These clocks are in kHz not in Hz, oops. Fix it so my new bandwidth calculations patch starts working with these panels. Reviewed-by: Eric Anholt Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20180211103840.18764-1-linus.walleij@linaro.org --- drivers/gpu/drm/panel/panel-arm-versatile.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c index 3930b4925b15..b428c4678106 100644 --- a/drivers/gpu/drm/panel/panel-arm-versatile.c +++ b/drivers/gpu/drm/panel/panel-arm-versatile.c @@ -132,7 +132,7 @@ static const struct versatile_panel_type versatile_panels[] = { .width_mm = 79, .height_mm = 54, .mode = { - .clock = 10000000, + .clock = 10000, .hdisplay = 320, .hsync_start = 320 + 6, .hsync_end = 320 + 6 + 6, @@ -156,7 +156,7 @@ static const struct versatile_panel_type versatile_panels[] = { .width_mm = 171, .height_mm = 130, .mode = { - .clock = 25000000, + .clock = 25000, .hdisplay = 640, .hsync_start = 640 + 24, .hsync_end = 640 + 24 + 96, @@ -179,7 +179,7 @@ static const struct versatile_panel_type versatile_panels[] = { .width_mm = 34, .height_mm = 45, .mode = { - .clock = 625000000, + .clock = 62500, .hdisplay = 176, .hsync_start = 176 + 2, .hsync_end = 176 + 2 + 3, @@ -203,7 +203,7 @@ static const struct versatile_panel_type versatile_panels[] = { .width_mm = 37, .height_mm = 50, .mode = { - .clock = 5400000, + .clock = 5400, .hdisplay = 240, .hsync_start = 240 + 10, .hsync_end = 240 + 10 + 10, -- cgit v1.2.3 From 2c83029cda55a5e7665c7c6326909427d6a01350 Mon Sep 17 00:00:00 2001 From: Ben Crocker Date: Thu, 22 Feb 2018 17:52:19 -0500 Subject: drm/radeon: insist on 32-bit DMA for Cedar on PPC64/PPC64LE In radeon_device_init, set the need_dma32 flag for Cedar chips (e.g. FirePro 2270). This fixes, or at least works around, a bug on PowerPC exposed by last year's commits 8e3f1b1d8255105f31556aacf8aeb6071b00d469 (Russell Currey) and 253fd51e2f533552ae35a0c661705da6c4842c1b (Alistair Popple) which enabled the 64-bit DMA iommu bypass. This caused the device to freeze, in some cases unrecoverably, and is the subject of several bug reports internal to Red Hat. Signed-off-by: Ben Crocker Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_device.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 8d3e3d2e0090..7828a5e10629 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1365,6 +1365,10 @@ int radeon_device_init(struct radeon_device *rdev, if ((rdev->flags & RADEON_IS_PCI) && (rdev->family <= CHIP_RS740)) rdev->need_dma32 = true; +#ifdef CONFIG_PPC64 + if (rdev->family == CHIP_CEDAR) + rdev->need_dma32 = true; +#endif dma_bits = rdev->need_dma32 ? 32 : 40; r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits)); -- cgit v1.2.3 From 879659bb87a87a7a23b190e211d33bdd6763c746 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Wed, 31 Jan 2018 09:05:08 +0100 Subject: drm/stm: check pitch and size calculations even if !CONFIG_MMU In all cases we have to check pitch and size calculations to speed up data transfer. Fixes: 21f815bf773c ("drm/stm: drv: Improve data transfers") Signed-off-by: Benjamin Gaignard Tested-by: Philippe Cornu Reviewed-by: Philippe Cornu Link: https://patchwork.freedesktop.org/patch/msgid/20180131080508.14356-1-benjamin.gaignard@linaro.org --- drivers/gpu/drm/stm/drv.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index 8bc7e8418b8d..9ab00a87f7cc 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c @@ -35,7 +35,6 @@ static int stm_gem_cma_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { -#ifdef CONFIG_MMU unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); /* @@ -44,7 +43,6 @@ static int stm_gem_cma_dumb_create(struct drm_file *file, */ args->pitch = roundup(min_pitch, 128); args->height = roundup(args->height, 4); -#endif return drm_gem_cma_dumb_create_internal(file, dev, args); } -- cgit v1.2.3 From 80dfd71c5ac28542911bd009f3565895e2c94380 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 23 Feb 2018 10:29:46 +0200 Subject: media: videobuf2: Add VIDEOBUF2_V4L2 Kconfig option for VB2 V4L2 part Videobuf2 is now separate from V4L2 and can be now built without it, at least in principle --- enabling videobuf2 in kernel configuration attempts to compile videobuf2-v4l2.c but that will fail if CONFIG_VIDEO_V4L2 isn't enabled. Solve this by adding a separate Kconfig option for videobuf2-v4l2 and make it a separate module as well. This means that drivers now need to choose both the appropriate videobuf2 memory type (VIDEOBUF2_{VMALLOC,DMA_CONTIG,DMA_SG}) and VIDEOBUF2_V4L2 if they need both. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/Kconfig | 3 +++ drivers/media/common/videobuf2/Makefile | 3 ++- drivers/media/v4l2-core/Kconfig | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/common/videobuf2/Kconfig b/drivers/media/common/videobuf2/Kconfig index 5df05250de94..17c32ea58395 100644 --- a/drivers/media/common/videobuf2/Kconfig +++ b/drivers/media/common/videobuf2/Kconfig @@ -3,6 +3,9 @@ config VIDEOBUF2_CORE select DMA_SHARED_BUFFER tristate +config VIDEOBUF2_V4L2 + tristate + config VIDEOBUF2_MEMOPS tristate select FRAME_VECTOR diff --git a/drivers/media/common/videobuf2/Makefile b/drivers/media/common/videobuf2/Makefile index 19de5ccda20b..7e27bdd44dcc 100644 --- a/drivers/media/common/videobuf2/Makefile +++ b/drivers/media/common/videobuf2/Makefile @@ -1,5 +1,6 @@ -obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o videobuf2-v4l2.o +obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o +obj-$(CONFIG_VIDEOBUF2_V4L2) += videobuf2-v4l2.o obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index bf52fbd07aed..8e37e7c5e0f7 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -7,6 +7,7 @@ config VIDEO_V4L2 tristate depends on (I2C || I2C=n) && VIDEO_DEV select RATIONAL + select VIDEOBUF2_V4L2 if VIDEOBUF2_CORE default (I2C || I2C=n) && VIDEO_DEV config VIDEO_ADV_DEBUG -- cgit v1.2.3 From e77c31ed60d1bbf4879b19309f848e0d8f6df504 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Feb 2018 04:49:30 -0500 Subject: media: videobuf2: fix build issues with vb2-trace There was a trouble with vb2-trace: instead of being part of VB2 core, it was stored at V4L2 videodev. That was wrong, as it doesn't actually belong to V4L2 core. Now that vb2 is not part of v4l2-core, its trace functions should be moved altogether. So, move it to its rightful place: at videobuf2-core. That fixes those errors: drivers/media/common/videobuf2/videobuf2-core.o: In function `__read_once_size': ./include/linux/compiler.h:183: undefined reference to `__tracepoint_vb2_buf_queue' ./include/linux/compiler.h:183: undefined reference to `__tracepoint_vb2_buf_queue' ./include/linux/compiler.h:183: undefined reference to `__tracepoint_vb2_buf_done' ./include/linux/compiler.h:183: undefined reference to `__tracepoint_vb2_buf_done' ./include/linux/compiler.h:183: undefined reference to `__tracepoint_vb2_qbuf' ./include/linux/compiler.h:183: undefined reference to `__tracepoint_vb2_qbuf' ./include/linux/compiler.h:183: undefined reference to `__tracepoint_vb2_dqbuf' ./include/linux/compiler.h:183: undefined reference to `__tracepoint_vb2_dqbuf' drivers/media/common/videobuf2/videobuf2-core.o:(__jump_table+0x10): undefined reference to `__tracepoint_vb2_buf_queue' drivers/media/common/videobuf2/videobuf2-core.o:(__jump_table+0x28): undefined reference to `__tracepoint_vb2_buf_done' drivers/media/common/videobuf2/videobuf2-core.o:(__jump_table+0x40): undefined reference to `__tracepoint_vb2_qbuf' drivers/media/common/videobuf2/videobuf2-core.o:(__jump_table+0x58): undefined reference to `__tracepoint_vb2_dqbuf' Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/Makefile | 3 +++ drivers/media/common/videobuf2/vb2-trace.c | 10 ++++++++++ drivers/media/v4l2-core/Makefile | 3 +-- drivers/media/v4l2-core/vb2-trace.c | 10 ---------- 4 files changed, 14 insertions(+), 12 deletions(-) create mode 100644 drivers/media/common/videobuf2/vb2-trace.c delete mode 100644 drivers/media/v4l2-core/vb2-trace.c (limited to 'drivers') diff --git a/drivers/media/common/videobuf2/Makefile b/drivers/media/common/videobuf2/Makefile index 7e27bdd44dcc..067badb1aaa7 100644 --- a/drivers/media/common/videobuf2/Makefile +++ b/drivers/media/common/videobuf2/Makefile @@ -6,3 +6,6 @@ obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o obj-$(CONFIG_VIDEOBUF2_DVB) += videobuf2-dvb.o +ifeq ($(CONFIG_TRACEPOINTS),y) + obj-$(CONFIG_VIDEOBUF2_CORE) += vb2-trace.o +endif diff --git a/drivers/media/common/videobuf2/vb2-trace.c b/drivers/media/common/videobuf2/vb2-trace.c new file mode 100644 index 000000000000..4c0f39d271f0 --- /dev/null +++ b/drivers/media/common/videobuf2/vb2-trace.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +#define CREATE_TRACE_POINTS +#include + +EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_buf_done); +EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_buf_queue); +EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_dqbuf); +EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_qbuf); diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index 80de2cb9c476..7df54582e956 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -13,7 +13,7 @@ ifeq ($(CONFIG_COMPAT),y) endif obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o ifeq ($(CONFIG_TRACEPOINTS),y) - videodev-objs += vb2-trace.o v4l2-trace.o + videodev-objs += v4l2-trace.o endif videodev-$(CONFIG_MEDIA_CONTROLLER) += v4l2-mc.o @@ -35,4 +35,3 @@ obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o ccflags-y += -I$(srctree)/drivers/media/dvb-frontends ccflags-y += -I$(srctree)/drivers/media/tuners - diff --git a/drivers/media/v4l2-core/vb2-trace.c b/drivers/media/v4l2-core/vb2-trace.c deleted file mode 100644 index 4c0f39d271f0..000000000000 --- a/drivers/media/v4l2-core/vb2-trace.c +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include - -#define CREATE_TRACE_POINTS -#include - -EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_buf_done); -EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_buf_queue); -EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_dqbuf); -EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_qbuf); -- cgit v1.2.3 From ec5b100462543aee1f3e139e168699fd3b05cdc6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Jan 2018 05:31:30 -0500 Subject: media: dvb: fix DVB_MMAP symbol name CONFIG_DVB_MMAP was misspelled either as CONFIG_DVB_MMSP or DVB_MMAP, so it had no effect at all. This fixes that, to make it possible to build it again. Fixes: 4021053ed52d ("media: dvb-core: make DVB mmap API optional") Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/Makefile | 2 +- drivers/media/dvb-core/dmxdev.c | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile index 3a105d82019a..62b028ded9f7 100644 --- a/drivers/media/dvb-core/Makefile +++ b/drivers/media/dvb-core/Makefile @@ -4,7 +4,7 @@ # dvb-net-$(CONFIG_DVB_NET) := dvb_net.o -dvb-vb2-$(CONFIG_DVB_MMSP) := dvb_vb2.o +dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \ dvb_ca_en50221.o dvb_frontend.o \ diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 6d53af00190e..c3054101c234 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -128,7 +128,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; struct dmx_frontend *front; -#ifndef DVB_MMAP +#ifndef CONFIG_DVB_MMAP bool need_ringbuffer = false; #else const bool need_ringbuffer = true; @@ -144,7 +144,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) return -ENODEV; } -#ifndef DVB_MMAP +#ifndef CONFIG_DVB_MMAP if ((file->f_flags & O_ACCMODE) == O_RDONLY) need_ringbuffer = true; #else @@ -200,7 +200,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; -#ifndef DVB_MMAP +#ifndef CONFIG_DVB_MMAP bool need_ringbuffer = false; #else const bool need_ringbuffer = true; @@ -213,7 +213,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) dmxdev->demux->connect_frontend(dmxdev->demux, dmxdev->dvr_orig_fe); } -#ifndef DVB_MMAP +#ifndef CONFIG_DVB_MMAP if ((file->f_flags & O_ACCMODE) == O_RDONLY) need_ringbuffer = true; #endif @@ -426,7 +426,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, { struct dmxdev_filter *dmxdevfilter = feed->priv; struct dvb_ringbuffer *buffer; -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP struct dvb_vb2_ctx *ctx; #endif int ret; @@ -440,12 +440,12 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, if (dmxdevfilter->params.pes.output == DMX_OUT_TAP || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) { buffer = &dmxdevfilter->buffer; -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP ctx = &dmxdevfilter->vb2_ctx; #endif } else { buffer = &dmxdevfilter->dev->dvr_buffer; -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP ctx = &dmxdevfilter->dev->dvr_vb2_ctx; #endif } @@ -1111,7 +1111,7 @@ static int dvb_demux_do_ioctl(struct file *file, mutex_unlock(&dmxdevfilter->mutex); break; -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP case DMX_REQBUFS: if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { mutex_unlock(&dmxdev->mutex); @@ -1199,7 +1199,7 @@ static __poll_t dvb_demux_poll(struct file *file, poll_table *wait) return mask; } -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma) { struct dmxdev_filter *dmxdevfilter = file->private_data; @@ -1249,7 +1249,7 @@ static const struct file_operations dvb_demux_fops = { .release = dvb_demux_release, .poll = dvb_demux_poll, .llseek = default_llseek, -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP .mmap = dvb_demux_mmap, #endif }; @@ -1280,7 +1280,7 @@ static int dvb_dvr_do_ioctl(struct file *file, ret = dvb_dvr_set_buffer_size(dmxdev, arg); break; -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP case DMX_REQBUFS: ret = dvb_vb2_reqbufs(&dmxdev->dvr_vb2_ctx, parg); break; @@ -1322,7 +1322,7 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; __poll_t mask = 0; -#ifndef DVB_MMAP +#ifndef CONFIG_DVB_MMAP bool need_ringbuffer = false; #else const bool need_ringbuffer = true; @@ -1337,7 +1337,7 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) poll_wait(file, &dmxdev->dvr_buffer.queue, wait); -#ifndef DVB_MMAP +#ifndef CONFIG_DVB_MMAP if ((file->f_flags & O_ACCMODE) == O_RDONLY) need_ringbuffer = true; #endif @@ -1353,7 +1353,7 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) return mask; } -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma) { struct dvb_device *dvbdev = file->private_data; @@ -1381,7 +1381,7 @@ static const struct file_operations dvb_dvr_fops = { .release = dvb_dvr_release, .poll = dvb_dvr_poll, .llseek = default_llseek, -#ifdef DVB_MMAP +#ifdef CONFIG_DVB_MMAP .mmap = dvb_dvr_mmap, #endif }; -- cgit v1.2.3 From 85e60bd746b71fd8aca4f7e6803f9a5207f53a30 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Jan 2018 05:31:31 -0500 Subject: media: dvb: fix DVB_MMAP dependency Enabling CONFIG_DVB_MMAP without CONFIG_VIDEOBUF2_VMALLOC results in a link error: drivers/media/dvb-core/dvb_vb2.o: In function `_stop_streaming': dvb_vb2.c:(.text+0x894): undefined reference to `vb2_buffer_done' drivers/media/dvb-core/dvb_vb2.o: In function `dvb_vb2_init': dvb_vb2.c:(.text+0xbec): undefined reference to `vb2_vmalloc_memops' dvb_vb2.c:(.text+0xc4c): undefined reference to `vb2_core_queue_init' drivers/media/dvb-core/dvb_vb2.o: In function `dvb_vb2_release': dvb_vb2.c:(.text+0xe14): undefined reference to `vb2_core_queue_release' drivers/media/dvb-core/dvb_vb2.o: In function `dvb_vb2_stream_on': dvb_vb2.c:(.text+0xeb8): undefined reference to `vb2_core_streamon' drivers/media/dvb-core/dvb_vb2.o: In function `dvb_vb2_stream_off': dvb_vb2.c:(.text+0xfe8): undefined reference to `vb2_core_streamoff' drivers/media/dvb-core/dvb_vb2.o: In function `dvb_vb2_fill_buffer': dvb_vb2.c:(.text+0x13ec): undefined reference to `vb2_plane_vaddr' dvb_vb2.c:(.text+0x149c): undefined reference to `vb2_buffer_done' This adds a 'select' statement for it, plus a dependency that ensures that videobuf2 in turn works, as it in turn depends on VIDEO_V4L2 to link, and that must not be a module if videobuf2 is built-in. Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 145e12bfb819..372c074bb1b9 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -147,6 +147,8 @@ config DVB_CORE config DVB_MMAP bool "Enable DVB memory-mapped API (EXPERIMENTAL)" depends on DVB_CORE + depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE + select VIDEOBUF2_VMALLOC default n help This option enables DVB experimental memory-mapped API, with -- cgit v1.2.3 From 0066c764e7cc18784e5edcdeb9831cdefdf4c344 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Jan 2018 05:31:32 -0500 Subject: media: au0828: add VIDEO_V4L2 dependency After the move of videobuf2 into the common directory, selecting the au0828 driver with CONFIG_V4L2 disabled started causing a link failure, as we now attempt to build videobuf2 but it still requires v4l2: ERROR: "v4l2_event_pending" [drivers/media/common/videobuf/videobuf2-v4l2.ko] undefined! ERROR: "v4l2_fh_release" [drivers/media/common/videobuf/videobuf2-v4l2.ko] undefined! ERROR: "video_devdata" [drivers/media/common/videobuf/videobuf2-v4l2.ko] undefined! ERROR: "__tracepoint_vb2_buf_done" [drivers/media/common/videobuf/videobuf2-core.ko] undefined! ERROR: "__tracepoint_vb2_dqbuf" [drivers/media/common/videobuf/videobuf2-core.ko] undefined! ERROR: "v4l_vb2q_enable_media_source" [drivers/media/common/videobuf/videobuf2-core.ko] undefined! This adds the same dependency in au0828 that the other users of videobuf2 have. Fixes: 03fbdb2fc2b8 ("media: move videobuf2 to drivers/media/common") Fixes: 05439b1a3693 ("[media] media: au0828 - convert to use videobuf2") Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig index 70521e0b4c53..bfaa806633df 100644 --- a/drivers/media/usb/au0828/Kconfig +++ b/drivers/media/usb/au0828/Kconfig @@ -1,7 +1,7 @@ config VIDEO_AU0828 tristate "Auvitek AU0828 support" - depends on I2C && INPUT && DVB_CORE && USB + depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2 select I2C_ALGOBIT select VIDEO_TVEEPROM select VIDEOBUF2_VMALLOC -- cgit v1.2.3 From b9c97c67fd19262c002d94ced2bfb513083e161e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 10 Feb 2018 06:14:10 -0500 Subject: media: m88ds3103: don't call a non-initalized function If m88d3103 chip ID is not recognized, the device is not initialized. However, it returns from probe without any error, causing this OOPS: [ 7.689289] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 7.689297] pgd = 7b0bd7a7 [ 7.689302] [00000000] *pgd=00000000 [ 7.689318] Internal error: Oops: 80000005 [#1] SMP ARM [ 7.689322] Modules linked in: dvb_usb_dvbsky(+) m88ds3103 dvb_usb_v2 dvb_core videobuf2_vmalloc videobuf2_memops videobuf2_core crc32_arm_ce videodev media [ 7.689358] CPU: 3 PID: 197 Comm: systemd-udevd Not tainted 4.15.0-mcc+ #23 [ 7.689361] Hardware name: BCM2835 [ 7.689367] PC is at 0x0 [ 7.689382] LR is at m88ds3103_attach+0x194/0x1d0 [m88ds3103] [ 7.689386] pc : [<00000000>] lr : [] psr: 60000013 [ 7.689391] sp : ed8e5c20 ip : ed8c1e00 fp : ed8945c0 [ 7.689395] r10: ed894000 r9 : ed894378 r8 : eda736c0 [ 7.689400] r7 : ed894070 r6 : ed8e5c44 r5 : bf0bb040 r4 : eda77600 [ 7.689405] r3 : 00000000 r2 : 00000000 r1 : 00000000 r0 : eda77600 [ 7.689412] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 7.689417] Control: 10c5383d Table: 2d8e806a DAC: 00000051 [ 7.689423] Process systemd-udevd (pid: 197, stack limit = 0xe9dbfb63) [ 7.689428] Stack: (0xed8e5c20 to 0xed8e6000) [ 7.689439] 5c20: ed853a80 eda73640 ed894000 ed8942c0 ed853a80 bf0b9e98 ed894070 bf0b9f10 [ 7.689449] 5c40: 00000000 00000000 bf08c17c c08dfc50 00000000 00000000 00000000 00000000 [ 7.689459] 5c60: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 7.689468] 5c80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 7.689479] 5ca0: 00000000 00000000 ed8945c0 ed8942c0 ed894000 ed894830 bf0b9e98 00000000 [ 7.689490] 5cc0: ed894378 bf0a3cb4 bf0bc3b0 0000533b ed920540 00000000 00000034 bf0a6434 [ 7.689500] 5ce0: ee952070 ed826600 bf0a7038 bf0a2dd8 00000001 bf0a6768 bf0a2f90 ed8943c0 [ 7.689511] 5d00: 00000000 c08eca68 ed826620 ed826620 00000000 ee952070 bf0bc034 ee952000 [ 7.689521] 5d20: ed826600 bf0bb080 ffffffed c0aa9e9c c0aa9dac ed826620 c16edf6c c168c2c8 [ 7.689531] 5d40: c16edf70 00000000 bf0bc034 0000000d 00000000 c08e268c bf0bb080 ed826600 [ 7.689541] 5d60: bf0bc034 ed826654 ed826620 bf0bc034 c164c8bc 00000000 00000001 00000000 [ 7.689553] 5d80: 00000028 c08e2948 00000000 bf0bc034 c08e2848 c08e0778 ee9f0a58 ed88bab4 [ 7.689563] 5da0: bf0bc034 ed90ba80 c168c1f0 c08e1934 bf0bb3bc c17045ac bf0bc034 c164c8bc [ 7.689574] 5dc0: bf0bc034 bf0bb3bc ed91f564 c08e34ec bf0bc000 c164c8bc bf0bc034 c0aa8dc4 [ 7.689584] 5de0: ffffe000 00000000 bf0bf000 ed91f600 ed91f564 c03021e4 00000001 00000000 [ 7.689595] 5e00: c166e040 8040003f ed853a80 bf0bc448 00000000 c1678174 ed853a80 f0f22000 [ 7.689605] 5e20: f0f21fff 8040003f 014000c0 ed91e700 ed91e700 c16d8e68 00000001 ed91e6c0 [ 7.689615] 5e40: bf0bc400 00000001 bf0bc400 ed91f564 00000001 00000000 00000028 c03c9a24 [ 7.689625] 5e60: 00000001 c03c8c94 ed8e5f50 ed8e5f50 00000001 bf0bc400 ed91f540 c03c8cb0 [ 7.689637] 5e80: bf0bc40c 00007fff bf0bc400 c03c60b0 00000000 bf0bc448 00000028 c0e09684 [ 7.689647] 5ea0: 00000002 bf0bc530 c1234bf8 bf0bc5dc bf0bc514 c10ebbe8 ffffe000 bf000000 [ 7.689657] 5ec0: 00011538 00000000 ed8e5f48 00000000 00000000 00000000 00000000 00000000 [ 7.689666] 5ee0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 7.689676] 5f00: 00000000 00000000 7fffffff 00000000 00000013 b6e55a18 0000017b c0309104 [ 7.689686] 5f20: ed8e4000 00000000 00510af0 c03c9430 7fffffff 00000000 00000003 00000000 [ 7.689697] 5f40: 00000000 f0f0f000 00011538 00000000 f0f107b0 f0f0f000 00011538 f0f1fdb8 [ 7.689707] 5f60: f0f1fbe8 f0f1b974 00004000 000041e0 bf0bc3d0 00000001 00000000 000024c4 [ 7.689717] 5f80: 0000002d 0000002e 00000019 00000000 00000010 00000000 16894000 00000000 [ 7.689727] 5fa0: 00000000 c0308f20 16894000 00000000 00000013 b6e55a18 00000000 b6e5652c [ 7.689737] 5fc0: 16894000 00000000 00000000 0000017b 00020000 00508110 00000000 00510af0 [ 7.689748] 5fe0: bef68948 bef68938 b6e4d3d0 b6d32590 60000010 00000013 00000000 00000000 [ 7.689790] [] (m88ds3103_attach [m88ds3103]) from [] (dvbsky_s960c_attach+0x78/0x280 [dvb_usb_dvbsky]) [ 7.689821] [] (dvbsky_s960c_attach [dvb_usb_dvbsky]) from [] (dvb_usbv2_probe+0xa3c/0x1024 [dvb_usb_v2]) [ 7.689849] [] (dvb_usbv2_probe [dvb_usb_v2]) from [] (usb_probe_interface+0xf0/0x2a8) [ 7.689869] [] (usb_probe_interface) from [] (driver_probe_device+0x2f8/0x4b4) [ 7.689881] [] (driver_probe_device) from [] (__driver_attach+0x100/0x11c) [ 7.689895] [] (__driver_attach) from [] (bus_for_each_dev+0x4c/0x9c) [ 7.689909] [] (bus_for_each_dev) from [] (bus_add_driver+0x1c0/0x264) [ 7.689919] [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [ 7.689931] [] (driver_register) from [] (usb_register_driver+0x70/0x134) [ 7.689946] [] (usb_register_driver) from [] (do_one_initcall+0x44/0x168) [ 7.689963] [] (do_one_initcall) from [] (do_init_module+0x64/0x1f4) [ 7.689979] [] (do_init_module) from [] (load_module+0x20a0/0x25c8) [ 7.689993] [] (load_module) from [] (SyS_finit_module+0xb4/0xec) [ 7.690007] [] (SyS_finit_module) from [] (ret_fast_syscall+0x0/0x54) [ 7.690018] Code: bad PC value This may happen on normal circumstances, if, for some reason, the demod hangs and start returning an invalid chip ID: [ 10.394395] m88ds3103 3-0068: Unknown device. Chip_id=00 So, change the logic to cause probe to fail with -ENODEV, preventing the OOPS. Detected while testing DVB MMAP patches on Raspberry Pi 3 with DVBSky S960CI. Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/m88ds3103.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index 50bce68ffd66..65d157fe76d1 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -1262,11 +1262,12 @@ static int m88ds3103_select(struct i2c_mux_core *muxc, u32 chan) * New users must use I2C client binding directly! */ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, - struct i2c_adapter *i2c, struct i2c_adapter **tuner_i2c_adapter) + struct i2c_adapter *i2c, + struct i2c_adapter **tuner_i2c_adapter) { struct i2c_client *client; struct i2c_board_info board_info; - struct m88ds3103_platform_data pdata; + struct m88ds3103_platform_data pdata = {}; pdata.clk = cfg->clock; pdata.i2c_wr_max = cfg->i2c_wr_max; @@ -1409,6 +1410,8 @@ static int m88ds3103_probe(struct i2c_client *client, case M88DS3103_CHIP_ID: break; default: + ret = -ENODEV; + dev_err(&client->dev, "Unknown device. Chip_id=%02x\n", dev->chip_id); goto err_kfree; } -- cgit v1.2.3 From a145f64c6107d3aa5a7cec9f8977d04ac2a896c9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 11 Feb 2018 05:44:21 -0500 Subject: media: dmxdev: fix error code for invalid ioctls Returning -EINVAL when an ioctl is not implemented is a very bad idea, as it is hard to distinguish from other error contitions that an ioctl could lead. Replace it by its right error code: -ENOTTY. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dmxdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index c3054101c234..d87b69b86a59 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1160,7 +1160,7 @@ static int dvb_demux_do_ioctl(struct file *file, break; #endif default: - ret = -EINVAL; + ret = -ENOTTY; break; } mutex_unlock(&dmxdev->mutex); -- cgit v1.2.3 From 0b23498aacc658e4d0f6b240f0b905908695a132 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 9 Feb 2018 10:44:49 -0500 Subject: media: dmxdev: Fix the logic that enables DMA mmap support Some conditions required for DVB mmap support to work are reversed. Also, the logic is not too clear. So, improve the logic, making it easier to be handled. PS.: I'm pretty sure that I fixed it while testing, but, somehow, the change got lost. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dmxdev.c | 75 +++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index d87b69b86a59..09c2626b5bf9 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -128,11 +128,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; struct dmx_frontend *front; -#ifndef CONFIG_DVB_MMAP bool need_ringbuffer = false; -#else - const bool need_ringbuffer = true; -#endif dprintk("%s\n", __func__); @@ -144,17 +140,31 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) return -ENODEV; } -#ifndef CONFIG_DVB_MMAP + dmxdev->may_do_mmap = 0; + + /* + * The logic here is a little tricky due to the ifdef. + * + * The ringbuffer is used for both read and mmap. + * + * It is not needed, however, on two situations: + * - Write devices (access with O_WRONLY); + * - For duplex device nodes, opened with O_RDWR. + */ + if ((file->f_flags & O_ACCMODE) == O_RDONLY) need_ringbuffer = true; -#else - if ((file->f_flags & O_ACCMODE) == O_RDWR) { + else if ((file->f_flags & O_ACCMODE) == O_RDWR) { if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { +#ifdef CONFIG_DVB_MMAP + dmxdev->may_do_mmap = 1; + need_ringbuffer = true; +#else mutex_unlock(&dmxdev->mutex); return -EOPNOTSUPP; +#endif } } -#endif if (need_ringbuffer) { void *mem; @@ -169,8 +179,9 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) return -ENOMEM; } dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); - dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr", - file->f_flags & O_NONBLOCK); + if (dmxdev->may_do_mmap) + dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr", + file->f_flags & O_NONBLOCK); dvbdev->readers--; } @@ -200,11 +211,6 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; -#ifndef CONFIG_DVB_MMAP - bool need_ringbuffer = false; -#else - const bool need_ringbuffer = true; -#endif mutex_lock(&dmxdev->mutex); @@ -213,15 +219,14 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) dmxdev->demux->connect_frontend(dmxdev->demux, dmxdev->dvr_orig_fe); } -#ifndef CONFIG_DVB_MMAP - if ((file->f_flags & O_ACCMODE) == O_RDONLY) - need_ringbuffer = true; -#endif - if (need_ringbuffer) { - if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) - dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx); - dvb_vb2_release(&dmxdev->dvr_vb2_ctx); + if (((file->f_flags & O_ACCMODE) == O_RDONLY) || + dmxdev->may_do_mmap) { + if (dmxdev->may_do_mmap) { + if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) + dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx); + dvb_vb2_release(&dmxdev->dvr_vb2_ctx); + } dvbdev->readers++; if (dmxdev->dvr_buffer.data) { void *mem = dmxdev->dvr_buffer.data; @@ -802,6 +807,12 @@ static int dvb_demux_open(struct inode *inode, struct file *file) mutex_init(&dmxdevfilter->mutex); file->private_data = dmxdevfilter; +#ifdef CONFIG_DVB_MMAP + dmxdev->may_do_mmap = 1; +#else + dmxdev->may_do_mmap = 0; +#endif + dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter", file->f_flags & O_NONBLOCK); @@ -1206,6 +1217,9 @@ static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma) struct dmxdev *dmxdev = dmxdevfilter->dev; int ret; + if (!dmxdev->may_do_mmap) + return -EOPNOTSUPP; + if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; @@ -1322,11 +1336,6 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; __poll_t mask = 0; -#ifndef CONFIG_DVB_MMAP - bool need_ringbuffer = false; -#else - const bool need_ringbuffer = true; -#endif dprintk("%s\n", __func__); @@ -1337,11 +1346,8 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) poll_wait(file, &dmxdev->dvr_buffer.queue, wait); -#ifndef CONFIG_DVB_MMAP - if ((file->f_flags & O_ACCMODE) == O_RDONLY) - need_ringbuffer = true; -#endif - if (need_ringbuffer) { + if (((file->f_flags & O_ACCMODE) == O_RDONLY) || + dmxdev->may_do_mmap) { if (dmxdev->dvr_buffer.error) mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR); @@ -1360,6 +1366,9 @@ static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma) struct dmxdev *dmxdev = dvbdev->priv; int ret; + if (!dmxdev->may_do_mmap) + return -EOPNOTSUPP; + if (dmxdev->exit) return -ENODEV; -- cgit v1.2.3 From bf8486709ac7fad99e4040dea73fe466c57a4ae1 Mon Sep 17 00:00:00 2001 From: Anna Karbownik Date: Thu, 22 Feb 2018 16:18:13 +0100 Subject: EDAC, sb_edac: Fix out of bound writes during DIMM configuration on KNL Commit 3286d3eb906c ("EDAC, sb_edac: Drop NUM_CHANNELS from 8 back to 4") decreased NUM_CHANNELS from 8 to 4, but this is not enough for Knights Landing which supports up to 6 channels. This caused out-of-bounds writes to pvt->mirror_mode and pvt->tolm variables which don't pay critical role on KNL code path, so the memory corruption wasn't causing any visible driver failures. The easiest way of fixing it is to change NUM_CHANNELS to 6. Do that. An alternative solution would be to restructure the KNL part of the driver to 2MC/3channel representation. Reported-by: Dan Carpenter Signed-off-by: Anna Karbownik Cc: Mauro Carvalho Chehab Cc: Tony Luck Cc: jim.m.snow@intel.com Cc: krzysztof.paliswiat@intel.com Cc: lukasz.odzioba@intel.com Cc: qiuxu.zhuo@intel.com Cc: linux-edac Cc: Fixes: 3286d3eb906c ("EDAC, sb_edac: Drop NUM_CHANNELS from 8 back to 4") Link: http://lkml.kernel.org/r/1519312693-4789-1-git-send-email-anna.karbownik@intel.com [ Massage commit message. ] Signed-off-by: Borislav Petkov --- drivers/edac/sb_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index f34430f99fd8..872100215ca0 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -279,7 +279,7 @@ static const u32 correrrthrsld[] = { * sbridge structs */ -#define NUM_CHANNELS 4 /* Max channels per MC */ +#define NUM_CHANNELS 6 /* Max channels per MC */ #define MAX_DIMMS 3 /* Max DIMMS per channel */ #define KNL_MAX_CHAS 38 /* KNL max num. of Cache Home Agents */ #define KNL_MAX_CHANNELS 6 /* KNL max num. of PCI channels */ -- cgit v1.2.3 From c20bb155c2c5acb775f68be5d84fe679687c3c1e Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Sat, 3 Feb 2018 14:11:23 -0500 Subject: drm/nouveau: prefer XBGR2101010 for addfb ioctl Nouveau only exposes support for XBGR2101010. Prior to the atomic conversion, drm would pass in the wrong format in the framebuffer, but it was always ignored -- both userspace (xf86-video-nouveau) and the kernel driver agreed on the layout, so the fact that the format was wrong didn't matter. With the atomic conversion, nouveau all of a sudden started caring about the exact format, and so the previously-working code in xf86-video-nouveau no longer functioned since the (internally-assigned) format from the addfb ioctl was wrong. This change adds infrastructure to allow a drm driver to specify that it prefers the XBGR format variant for the addfb ioctl, and makes nouveau's nv50 display driver set it. (Prior gens had no support for 30bpp at all.) Signed-off-by: Ilia Mirkin Cc: stable@vger.kernel.org # v4.10+ Acked-by: Ben Skeggs Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180203191123.31507-1-imirkin@alum.mit.edu --- drivers/gpu/drm/drm_framebuffer.c | 4 ++++ drivers/gpu/drm/nouveau/nv50_display.c | 1 + 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 5a13ff29f4f0..c0530a1af5e3 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -121,6 +121,10 @@ int drm_mode_addfb(struct drm_device *dev, r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); r.handles[0] = or->handle; + if (r.pixel_format == DRM_FORMAT_XRGB2101010 && + dev->driver->driver_features & DRIVER_PREFER_XBGR_30BPP) + r.pixel_format = DRM_FORMAT_XBGR2101010; + ret = drm_mode_addfb2(dev, &r, file_priv); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index dd8d4352ed99..caddce88d2d8 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -4477,6 +4477,7 @@ nv50_display_create(struct drm_device *dev) nouveau_display(dev)->fini = nv50_display_fini; disp->disp = &nouveau_display(dev)->disp; dev->mode_config.funcs = &nv50_disp_func; + dev->driver->driver_features |= DRIVER_PREFER_XBGR_30BPP; if (nouveau_atomic) dev->driver->driver_features |= DRIVER_ATOMIC; -- cgit v1.2.3 From 4e14bf4236490306004782813b8b4494b18f5e60 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Thu, 22 Feb 2018 18:20:30 +0300 Subject: macvlan: fix use-after-free in macvlan_common_newlink() The following use-after-free was reported by KASan when running LTP macvtap01 test on 4.16-rc2: [10642.528443] BUG: KASAN: use-after-free in macvlan_common_newlink+0x12ef/0x14a0 [macvlan] [10642.626607] Read of size 8 at addr ffff880ba49f2100 by task ip/18450 ... [10642.963873] Call Trace: [10642.994352] dump_stack+0x5c/0x7c [10643.035325] print_address_description+0x75/0x290 [10643.092938] kasan_report+0x28d/0x390 [10643.137971] ? macvlan_common_newlink+0x12ef/0x14a0 [macvlan] [10643.207963] macvlan_common_newlink+0x12ef/0x14a0 [macvlan] [10643.275978] macvtap_newlink+0x171/0x260 [macvtap] [10643.334532] rtnl_newlink+0xd4f/0x1300 ... [10646.256176] Allocated by task 18450: [10646.299964] kasan_kmalloc+0xa6/0xd0 [10646.343746] kmem_cache_alloc_trace+0xf1/0x210 [10646.397826] macvlan_common_newlink+0x6de/0x14a0 [macvlan] [10646.464386] macvtap_newlink+0x171/0x260 [macvtap] [10646.522728] rtnl_newlink+0xd4f/0x1300 ... [10647.022028] Freed by task 18450: [10647.061549] __kasan_slab_free+0x138/0x180 [10647.111468] kfree+0x9e/0x1c0 [10647.147869] macvlan_port_destroy+0x3db/0x650 [macvlan] [10647.211411] rollback_registered_many+0x5b9/0xb10 [10647.268715] rollback_registered+0xd9/0x190 [10647.319675] register_netdevice+0x8eb/0xc70 [10647.370635] macvlan_common_newlink+0xe58/0x14a0 [macvlan] [10647.437195] macvtap_newlink+0x171/0x260 [macvtap] Commit d02fd6e7d293 ("macvlan: Fix one possible double free") handles the case when register_netdevice() invokes ndo_uninit() on error and as a result free the port. But 'macvlan_port_get_rtnl(dev))' check (returns dev->rx_handler_data), which was added by this commit in order to prevent double free, is not quite correct: * for macvlan it always returns NULL because 'lowerdev' is the one that was used to register rx handler (port) in macvlan_port_create() as well as to unregister it in macvlan_port_destroy(). * for macvtap it always returns a valid pointer because macvtap registers its own rx handler before macvlan_common_newlink(). Fixes: d02fd6e7d293 ("macvlan: Fix one possible double free") Signed-off-by: Alexey Kodanev Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index a0f2be81d52e..8fc02d9db3d0 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1451,7 +1451,7 @@ destroy_macvlan_port: /* the macvlan port may be freed by macvlan_uninit when fail to register. * so we destroy the macvlan port only when it's valid. */ - if (create && macvlan_port_get_rtnl(dev)) + if (create && macvlan_port_get_rtnl(lowerdev)) macvlan_port_destroy(port->dev); return err; } -- cgit v1.2.3 From fdbeb96258141d911ca8ba98931b9024038b84e0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 9 Feb 2018 07:30:46 -0500 Subject: media: dvb: update buffer mmaped flags and frame counter Now that we have support for a buffer counter and for error flags, update them at DMX_DQBUF. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dmxdev.c | 24 ++++--- drivers/media/dvb-core/dvb_demux.c | 112 +++++++++++++++++++++----------- drivers/media/dvb-core/dvb_net.c | 5 +- drivers/media/dvb-core/dvb_vb2.c | 31 ++++++--- drivers/media/pci/ttpci/av7110.c | 5 +- drivers/media/pci/ttpci/av7110_av.c | 6 +- drivers/media/usb/ttusb-dec/ttusb_dec.c | 10 +-- 7 files changed, 124 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 09c2626b5bf9..61a750fae465 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -385,7 +385,8 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, - struct dmx_section_filter *filter) + struct dmx_section_filter *filter, + u32 *buffer_flags) { struct dmxdev_filter *dmxdevfilter = filter->priv; int ret; @@ -404,10 +405,12 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, dprintk("section callback %*ph\n", 6, buffer1); if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) { ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx, - buffer1, buffer1_len); + buffer1, buffer1_len, + buffer_flags); if (ret == buffer1_len) ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx, - buffer2, buffer2_len); + buffer2, buffer2_len, + buffer_flags); } else { ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len); @@ -427,7 +430,8 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, - struct dmx_ts_feed *feed) + struct dmx_ts_feed *feed, + u32 *buffer_flags) { struct dmxdev_filter *dmxdevfilter = feed->priv; struct dvb_ringbuffer *buffer; @@ -456,9 +460,11 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, } if (dvb_vb2_is_streaming(ctx)) { - ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len); + ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len, + buffer_flags); if (ret == buffer1_len) - ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len); + ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len, + buffer_flags); } else { if (buffer->error) { spin_unlock(&dmxdevfilter->dev->lock); @@ -1218,7 +1224,7 @@ static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma) int ret; if (!dmxdev->may_do_mmap) - return -EOPNOTSUPP; + return -ENOTTY; if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; @@ -1318,7 +1324,7 @@ static int dvb_dvr_do_ioctl(struct file *file, break; #endif default: - ret = -EINVAL; + ret = -ENOTTY; break; } mutex_unlock(&dmxdev->mutex); @@ -1367,7 +1373,7 @@ static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma) int ret; if (!dmxdev->may_do_mmap) - return -EOPNOTSUPP; + return -ENOTTY; if (dmxdev->exit) return -ENODEV; diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 210eed0269b0..f45091246bdc 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -55,6 +55,17 @@ MODULE_PARM_DESC(dvb_demux_feed_err_pkts, dprintk(x); \ } while (0) +#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG +# define dprintk_sect_loss(x...) dprintk(x) +#else +# define dprintk_sect_loss(x...) +#endif + +#define set_buf_flags(__feed, __flag) \ + do { \ + (__feed)->buffer_flags |= (__flag); \ + } while (0) + /****************************************************************************** * static inlined helper functions ******************************************************************************/ @@ -104,31 +115,30 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, { int count = payload(buf); int p; -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG int ccok; u8 cc; -#endif if (count == 0) return -1; p = 188 - count; -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG cc = buf[3] & 0x0f; ccok = ((feed->cc + 1) & 0x0f) == cc; feed->cc = cc; - if (!ccok) - dprintk("missed packet: %d instead of %d!\n", - cc, (feed->cc + 1) & 0x0f); -#endif + if (!ccok) { + set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("missed packet: %d instead of %d!\n", + cc, (feed->cc + 1) & 0x0f); + } if (buf[1] & 0x40) // PUSI ? feed->peslen = 0xfffa; feed->peslen += count; - return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts); + return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, + &feed->buffer_flags); } static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, @@ -150,7 +160,7 @@ static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, return 0; return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen, - NULL, 0, &f->filter); + NULL, 0, &f->filter, &feed->buffer_flags); } static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) @@ -169,8 +179,10 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) if (sec->check_crc) { section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0); if (section_syntax_indicator && - demux->check_crc32(feed, sec->secbuf, sec->seclen)) + demux->check_crc32(feed, sec->secbuf, sec->seclen)) { + set_buf_flags(feed, DMX_BUFFER_FLAG_HAD_CRC32_DISCARD); return -1; + } } do { @@ -187,7 +199,6 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) { struct dmx_section_feed *sec = &feed->feed.sec; -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG if (sec->secbufp < sec->tsfeedp) { int n = sec->tsfeedp - sec->secbufp; @@ -197,12 +208,13 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) * but just first and last. */ if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { - dprintk("section ts padding loss: %d/%d\n", - n, sec->tsfeedp); - dprintk("pad data: %*ph\n", n, sec->secbuf); + set_buf_flags(feed, + DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("section ts padding loss: %d/%d\n", + n, sec->tsfeedp); + dprintk_sect_loss("pad data: %*ph\n", n, sec->secbuf); } } -#endif sec->tsfeedp = sec->secbufp = sec->seclen = 0; sec->secbuf = sec->secbuf_base; @@ -237,11 +249,10 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, return 0; if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG - dprintk("section buffer full loss: %d/%d\n", - sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, - DMX_MAX_SECFEED_SIZE); -#endif + set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("section buffer full loss: %d/%d\n", + sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, + DMX_MAX_SECFEED_SIZE); len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp; } @@ -269,12 +280,13 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, sec->seclen = seclen; sec->crc_val = ~0; /* dump [secbuf .. secbuf+seclen) */ - if (feed->pusi_seen) + if (feed->pusi_seen) { dvb_dmx_swfilter_section_feed(feed); -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG - else - dprintk("pusi not seen, discarding section data\n"); -#endif + } else { + set_buf_flags(feed, + DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("pusi not seen, discarding section data\n"); + } sec->secbufp += seclen; /* secbufp and secbuf moving together is */ sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ } @@ -307,18 +319,22 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, } if (!ccok || dc_i) { -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG - if (dc_i) - dprintk("%d frame with disconnect indicator\n", + if (dc_i) { + set_buf_flags(feed, + DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR); + dprintk_sect_loss("%d frame with disconnect indicator\n", cc); - else - dprintk("discontinuity: %d instead of %d. %d bytes lost\n", + } else { + set_buf_flags(feed, + DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("discontinuity: %d instead of %d. %d bytes lost\n", cc, (feed->cc + 1) & 0x0f, count + 4); + } /* - * those bytes under sume circumstances will again be reported + * those bytes under some circumstances will again be reported * in the following dvb_dmx_swfilter_section_new */ -#endif + /* * Discontinuity detected. Reset pusi_seen to * stop feeding of suspicious data until next PUSI=1 arrives @@ -326,6 +342,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, * FIXME: does it make sense if the MPEG-TS is the one * reporting discontinuity? */ + feed->pusi_seen = false; dvb_dmx_swfilter_section_new(feed); } @@ -345,11 +362,11 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, dvb_dmx_swfilter_section_new(feed); dvb_dmx_swfilter_section_copy_dump(feed, after, after_len); + } else if (count > 0) { + set_buf_flags(feed, + DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("PUSI=1 but %d bytes lost\n", count); } -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG - else if (count > 0) - dprintk("PUSI=1 but %d bytes lost\n", count); -#endif } else { /* PUSI=0 (is not set), no section boundary */ dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count); @@ -369,7 +386,8 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, if (feed->ts_type & TS_PAYLOAD_ONLY) dvb_dmx_swfilter_payload(feed, buf); else - feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); + feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, + &feed->buffer_flags); } /* Used only on full-featured devices */ if (feed->ts_type & TS_DECODER) @@ -430,6 +448,11 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) } if (buf[1] & 0x80) { + list_for_each_entry(feed, &demux->feed_list, list_head) { + if ((feed->pid != pid) && (feed->pid != 0x2000)) + continue; + set_buf_flags(feed, DMX_BUFFER_FLAG_TEI); + } dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n", pid, buf[1]); /* data in this packet can't be trusted - drop it unless @@ -445,6 +468,13 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) (demux->cnt_storage[pid] + 1) & 0xf; if ((buf[3] & 0xf) != demux->cnt_storage[pid]) { + list_for_each_entry(feed, &demux->feed_list, list_head) { + if ((feed->pid != pid) && (feed->pid != 0x2000)) + continue; + set_buf_flags(feed, + DMX_BUFFER_PKT_COUNTER_MISMATCH); + } + dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n", pid, demux->cnt_storage[pid], buf[3] & 0xf); @@ -466,7 +496,8 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) if (feed->pid == pid) dvb_dmx_swfilter_packet_type(feed, buf); else if (feed->pid == 0x2000) - feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); + feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, + &feed->buffer_flags); } } @@ -585,7 +616,8 @@ void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count) spin_lock_irqsave(&demux->lock, flags); - demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts); + demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, + &demux->feed->buffer_flags); spin_unlock_irqrestore(&demux->lock, flags); } @@ -785,6 +817,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, feed->demux = demux; feed->pid = 0xffff; feed->peslen = 0xfffa; + feed->buffer_flags = 0; (*ts_feed) = &feed->feed.ts; (*ts_feed)->parent = dmx; @@ -1042,6 +1075,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, dvbdmxfeed->cb.sec = callback; dvbdmxfeed->demux = dvbdmx; dvbdmxfeed->pid = 0xffff; + dvbdmxfeed->buffer_flags = 0; dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; dvbdmxfeed->feed.sec.tsfeedp = 0; diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index b6c7eec863b9..ba39f9942e1d 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -883,7 +883,8 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, - struct dmx_ts_feed *feed) + struct dmx_ts_feed *feed, + u32 *buffer_flags) { struct net_device *dev = feed->priv; @@ -992,7 +993,7 @@ static void dvb_net_sec(struct net_device *dev, static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, - struct dmx_section_filter *filter) + struct dmx_section_filter *filter, u32 *buffer_flags) { struct net_device *dev = filter->priv; diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c index 763145d74e83..b811adf88afa 100644 --- a/drivers/media/dvb-core/dvb_vb2.c +++ b/drivers/media/dvb-core/dvb_vb2.c @@ -256,7 +256,8 @@ int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx) } int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx, - const unsigned char *src, int len) + const unsigned char *src, int len, + enum dmx_buffer_flags *buffer_flags) { unsigned long flags = 0; void *vbuf = NULL; @@ -264,15 +265,17 @@ int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx, unsigned char *psrc = (unsigned char *)src; int ll = 0; - dprintk(3, "[%s] %d bytes are rcvd\n", ctx->name, len); - if (!src) { - dprintk(3, "[%s]:NULL pointer src\n", ctx->name); - /**normal case: This func is called twice from demux driver - * once with valid src pointer, second time with NULL pointer - */ + /* + * normal case: This func is called twice from demux driver + * one with valid src pointer, second time with NULL pointer + */ + if (!src || !len) return 0; - } spin_lock_irqsave(&ctx->slock, flags); + if (buffer_flags && *buffer_flags) { + ctx->flags |= *buffer_flags; + *buffer_flags = 0; + } while (todo) { if (!ctx->buf) { if (list_empty(&ctx->dvb_q)) { @@ -395,6 +398,7 @@ int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b) int dvb_vb2_dqbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b) { + unsigned long flags; int ret; ret = vb2_core_dqbuf(&ctx->vb_q, &b->index, b, ctx->nonblocking); @@ -402,7 +406,16 @@ int dvb_vb2_dqbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b) dprintk(1, "[%s] errno=%d\n", ctx->name, ret); return ret; } - dprintk(5, "[%s] index=%d\n", ctx->name, b->index); + + spin_lock_irqsave(&ctx->slock, flags); + b->count = ctx->count++; + b->flags = ctx->flags; + ctx->flags = 0; + spin_unlock_irqrestore(&ctx->slock, flags); + + dprintk(5, "[%s] index=%d, count=%d, flags=%d\n", + ctx->name, b->index, ctx->count, b->flags); + return 0; } diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index dc8e577b2f74..d6816effb878 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -324,14 +324,15 @@ static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len, } return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len, buffer2, buffer2_len, - &dvbdmxfilter->filter); + &dvbdmxfilter->filter, NULL); case DMX_TYPE_TS: if (!(dvbdmxfilter->feed->ts_type & TS_PACKET)) return 0; if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY) return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len, buffer2, buffer2_len, - &dvbdmxfilter->feed->feed.ts); + &dvbdmxfilter->feed->feed.ts, + NULL); else av7110_p2t_write(buffer1, buffer1_len, dvbdmxfilter->feed->pid, diff --git a/drivers/media/pci/ttpci/av7110_av.c b/drivers/media/pci/ttpci/av7110_av.c index 4daba76ec240..ef1bc17cdc4d 100644 --- a/drivers/media/pci/ttpci/av7110_av.c +++ b/drivers/media/pci/ttpci/av7110_av.c @@ -99,7 +99,7 @@ int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len) buf[4] = buf[5] = 0; if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) return dvbdmxfeed->cb.ts(buf, len, NULL, 0, - &dvbdmxfeed->feed.ts); + &dvbdmxfeed->feed.ts, NULL); else return dvb_filter_pes2ts(p2t, buf, len, 1); } @@ -109,7 +109,7 @@ static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data) struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv; dvbdmxfeed->cb.ts(data, 188, NULL, 0, - &dvbdmxfeed->feed.ts); + &dvbdmxfeed->feed.ts, NULL); return 0; } @@ -814,7 +814,7 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, memcpy(obuf + l, buf + c, TS_SIZE - l); c = length; } - feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts); + feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, NULL); pes_start = 0; } } diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index a8900f5571f7..44ca66cb9b8f 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -428,7 +428,7 @@ static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) struct ttusb_dec *dec = priv; dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, - &dec->audio_filter->feed->feed.ts); + &dec->audio_filter->feed->feed.ts, NULL); return 0; } @@ -438,7 +438,7 @@ static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data) struct ttusb_dec *dec = priv; dec->video_filter->feed->cb.ts(data, 188, NULL, 0, - &dec->video_filter->feed->feed.ts); + &dec->video_filter->feed->feed.ts, NULL); return 0; } @@ -490,7 +490,7 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) if (output_pva) { dec->video_filter->feed->cb.ts(pva, length, NULL, 0, - &dec->video_filter->feed->feed.ts); + &dec->video_filter->feed->feed.ts, NULL); return; } @@ -551,7 +551,7 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) case 0x02: /* MainAudioStream */ if (output_pva) { dec->audio_filter->feed->cb.ts(pva, length, NULL, 0, - &dec->audio_filter->feed->feed.ts); + &dec->audio_filter->feed->feed.ts, NULL); return; } @@ -589,7 +589,7 @@ static void ttusb_dec_process_filter(struct ttusb_dec *dec, u8 *packet, if (filter) filter->feed->cb.sec(&packet[2], length - 2, NULL, 0, - &filter->filter); + &filter->filter, NULL); } static void ttusb_dec_process_packet(struct ttusb_dec *dec) -- cgit v1.2.3 From 3dd6b560dc5d59e7cb6dbda6e85dc9af7925fcf8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 19 Feb 2018 13:23:39 -0500 Subject: media: Don't let tvp5150_get_vbi() go out of vbi_ram_default array As pointed by Dan, possible values for bits[3:0] of te Line Mode Registers can range from 0x0 to 0xf, but the check logic allow values ranging from 0x0 to 0xe. As static arrays are initialized with zero, using a value without an explicit initializer at the array won't cause any harm. Reported-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 88 +++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 3c1851984b90..2476d812f669 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -505,80 +505,77 @@ static struct i2c_vbi_ram_value vbi_ram_default[] = /* FIXME: Current api doesn't handle all VBI types, those not yet supported are placed under #if 0 */ #if 0 - {0x010, /* Teletext, SECAM, WST System A */ + [0] = {0x010, /* Teletext, SECAM, WST System A */ {V4L2_SLICED_TELETEXT_SECAM,6,23,1}, { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } }, #endif - {0x030, /* Teletext, PAL, WST System B */ + [1] = {0x030, /* Teletext, PAL, WST System B */ {V4L2_SLICED_TELETEXT_B,6,22,1}, { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } }, #if 0 - {0x050, /* Teletext, PAL, WST System C */ + [2] = {0x050, /* Teletext, PAL, WST System C */ {V4L2_SLICED_TELETEXT_PAL_C,6,22,1}, { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } }, - {0x070, /* Teletext, NTSC, WST System B */ + [3] = {0x070, /* Teletext, NTSC, WST System B */ {V4L2_SLICED_TELETEXT_NTSC_B,10,21,1}, { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } }, - {0x090, /* Tetetext, NTSC NABTS System C */ + [4] = {0x090, /* Tetetext, NTSC NABTS System C */ {V4L2_SLICED_TELETEXT_NTSC_C,10,21,1}, { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 } }, - {0x0b0, /* Teletext, NTSC-J, NABTS System D */ + [5] = {0x0b0, /* Teletext, NTSC-J, NABTS System D */ {V4L2_SLICED_TELETEXT_NTSC_D,10,21,1}, { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } }, - {0x0d0, /* Closed Caption, PAL/SECAM */ + [6] = {0x0d0, /* Closed Caption, PAL/SECAM */ {V4L2_SLICED_CAPTION_625,22,22,1}, { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } }, #endif - {0x0f0, /* Closed Caption, NTSC */ + [7] = {0x0f0, /* Closed Caption, NTSC */ {V4L2_SLICED_CAPTION_525,21,21,1}, { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } }, - {0x110, /* Wide Screen Signal, PAL/SECAM */ + [8] = {0x110, /* Wide Screen Signal, PAL/SECAM */ {V4L2_SLICED_WSS_625,23,23,1}, { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } }, #if 0 - {0x130, /* Wide Screen Signal, NTSC C */ + [9] = {0x130, /* Wide Screen Signal, NTSC C */ {V4L2_SLICED_WSS_525,20,20,1}, { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 } }, - {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ + [10] = {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ {V4l2_SLICED_VITC_625,6,22,0}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } }, - {0x170, /* Vertical Interval Timecode (VITC), NTSC */ + [11] = {0x170, /* Vertical Interval Timecode (VITC), NTSC */ {V4l2_SLICED_VITC_525,10,20,0}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } }, #endif - {0x190, /* Video Program System (VPS), PAL */ + [12] = {0x190, /* Video Program System (VPS), PAL */ {V4L2_SLICED_VPS,16,16,0}, { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 } }, /* 0x1d0 User programmable */ - - /* End of struct */ - { (u16)-1 } }; static int tvp5150_write_inittab(struct v4l2_subdev *sd, @@ -591,10 +588,10 @@ static int tvp5150_write_inittab(struct v4l2_subdev *sd, return 0; } -static int tvp5150_vdp_init(struct v4l2_subdev *sd, - const struct i2c_vbi_ram_value *regs) +static int tvp5150_vdp_init(struct v4l2_subdev *sd) { unsigned int i; + int j; /* Disable Full Field */ tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); @@ -604,14 +601,17 @@ static int tvp5150_vdp_init(struct v4l2_subdev *sd, tvp5150_write(sd, i, 0xff); /* Load Ram Table */ - while (regs->reg != (u16)-1) { + for (j = 0; j < ARRAY_SIZE(vbi_ram_default); j++) { + const struct i2c_vbi_ram_value *regs = &vbi_ram_default[j]; + + if (!regs->type.vbi_type) + continue; + tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8); tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg); for (i = 0; i < 16; i++) tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]); - - regs++; } return 0; } @@ -620,19 +620,23 @@ static int tvp5150_vdp_init(struct v4l2_subdev *sd, static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_cap *cap) { - const struct i2c_vbi_ram_value *regs = vbi_ram_default; - int line; + int line, i; dev_dbg_lvl(sd->dev, 1, debug, "g_sliced_vbi_cap\n"); memset(cap, 0, sizeof *cap); - while (regs->reg != (u16)-1 ) { - for (line=regs->type.ini_line;line<=regs->type.end_line;line++) { + for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { + const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; + + if (!regs->type.vbi_type) + continue; + + for (line = regs->type.ini_line; + line <= regs->type.end_line; + line++) { cap->service_lines[0][line] |= regs->type.vbi_type; } cap->service_set |= regs->type.vbi_type; - - regs++; } return 0; } @@ -651,14 +655,13 @@ static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, * MSB = field2 */ static int tvp5150_set_vbi(struct v4l2_subdev *sd, - const struct i2c_vbi_ram_value *regs, unsigned int type,u8 flags, int line, const int fields) { struct tvp5150 *decoder = to_tvp5150(sd); v4l2_std_id std = decoder->norm; u8 reg; - int pos = 0; + int i, pos = 0; if (std == V4L2_STD_ALL) { dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n"); @@ -671,19 +674,19 @@ static int tvp5150_set_vbi(struct v4l2_subdev *sd, if (line < 6 || line > 27) return 0; - while (regs->reg != (u16)-1) { + for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { + const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; + + if (!regs->type.vbi_type) + continue; + if ((type & regs->type.vbi_type) && (line >= regs->type.ini_line) && (line <= regs->type.end_line)) break; - - regs++; pos++; } - if (regs->reg == (u16)-1) - return 0; - type = pos | (flags & 0xf0); reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; @@ -696,8 +699,7 @@ static int tvp5150_set_vbi(struct v4l2_subdev *sd, return type; } -static int tvp5150_get_vbi(struct v4l2_subdev *sd, - const struct i2c_vbi_ram_value *regs, int line) +static int tvp5150_get_vbi(struct v4l2_subdev *sd, int line) { struct tvp5150 *decoder = to_tvp5150(sd); v4l2_std_id std = decoder->norm; @@ -726,8 +728,8 @@ static int tvp5150_get_vbi(struct v4l2_subdev *sd, return 0; } pos = ret & 0x0f; - if (pos < 0x0f) - type |= regs[pos].type.vbi_type; + if (pos < ARRAY_SIZE(vbi_ram_default)) + type |= vbi_ram_default[pos].type.vbi_type; } return type; @@ -788,7 +790,7 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val) tvp5150_write_inittab(sd, tvp5150_init_default); /* Initializes VDP registers */ - tvp5150_vdp_init(sd, vbi_ram_default); + tvp5150_vdp_init(sd); /* Selects decoder input */ tvp5150_selmux(sd); @@ -1121,8 +1123,8 @@ static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f for (i = 0; i <= 23; i++) { svbi->service_lines[1][i] = 0; svbi->service_lines[0][i] = - tvp5150_set_vbi(sd, vbi_ram_default, - svbi->service_lines[0][i], 0xf0, i, 3); + tvp5150_set_vbi(sd, svbi->service_lines[0][i], + 0xf0, i, 3); } /* Enables FIFO */ tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1); @@ -1148,7 +1150,7 @@ static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f for (i = 0; i <= 23; i++) { svbi->service_lines[0][i] = - tvp5150_get_vbi(sd, vbi_ram_default, i); + tvp5150_get_vbi(sd, i); mask |= svbi->service_lines[0][i]; } svbi->service_set = mask; -- cgit v1.2.3 From d903ec77118c09f93a610b384d83a6df33a64fe6 Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Thu, 22 Feb 2018 11:05:33 -0800 Subject: gianfar: simplify FCS handling and fix memory leak Previously, buffer descriptors containing only the frame check sequence (FCS) were skipped and not added to the skb. However, the page reference count was still incremented, leading to a memory leak. Fixing this inside gfar_add_rx_frag() is difficult due to reserved memory handling and page reuse. Instead, move the FCS handling to gfar_process_frame() and trim off the FCS before passing the skb up the networking stack. Signed-off-by: Andy Spencer Signed-off-by: Jim Gruen Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 3bdeb295514b..f5c87bd35fa1 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2934,29 +2934,17 @@ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus, { int size = lstatus & BD_LENGTH_MASK; struct page *page = rxb->page; - bool last = !!(lstatus & BD_LFLAG(RXBD_LAST)); - - /* Remove the FCS from the packet length */ - if (last) - size -= ETH_FCS_LEN; if (likely(first)) { skb_put(skb, size); } else { /* the last fragments' length contains the full frame length */ - if (last) + if (lstatus & BD_LFLAG(RXBD_LAST)) size -= skb->len; - /* Add the last fragment if it contains something other than - * the FCS, otherwise drop it and trim off any part of the FCS - * that was already received. - */ - if (size > 0) - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, - rxb->page_offset + RXBUF_ALIGNMENT, - size, GFAR_RXB_TRUESIZE); - else if (size < 0) - pskb_trim(skb, skb->len + size); + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, + rxb->page_offset + RXBUF_ALIGNMENT, + size, GFAR_RXB_TRUESIZE); } /* try reuse page */ @@ -3069,6 +3057,9 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb) if (priv->padding) skb_pull(skb, priv->padding); + /* Trim off the FCS */ + pskb_trim(skb, skb->len - ETH_FCS_LEN); + if (ndev->features & NETIF_F_RXCSUM) gfar_rx_checksum(skb, fcb); -- cgit v1.2.3 From 69d7d95452b8964ccb6bf8a7295016f6c669aa53 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Tue, 13 Feb 2018 12:40:38 -0800 Subject: memory: brcmstb: dpfe: properly mask vendor error bits We were printing the entire 32 bit register rather than just the lower 8 bits. Anything above bit 7 is reserved and may be any random value. Fixes: 2f330caff577 ("memory: brcmstb: Add driver for DPFE") Signed-off-by: Markus Mayer Signed-off-by: Florian Fainelli --- drivers/memory/brcmstb_dpfe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c index 0a7bdbed3a6f..088153760e52 100644 --- a/drivers/memory/brcmstb_dpfe.c +++ b/drivers/memory/brcmstb_dpfe.c @@ -603,7 +603,8 @@ static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr, readl_relaxed(info + DRAM_VENDOR_MR6) & DRAM_VENDOR_MASK, readl_relaxed(info + DRAM_VENDOR_MR7) & DRAM_VENDOR_MASK, readl_relaxed(info + DRAM_VENDOR_MR8) & DRAM_VENDOR_MASK, - readl_relaxed(info + DRAM_VENDOR_ERROR)); + readl_relaxed(info + DRAM_VENDOR_ERROR) & + DRAM_VENDOR_MASK); } static int brcmstb_dpfe_resume(struct platform_device *pdev) -- cgit v1.2.3 From 9f2c4d95e088a44b2b68fedbd4593070b53754a7 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Tue, 13 Feb 2018 12:40:39 -0800 Subject: memory: brcmstb: dpfe: fix type declaration of variable "ret" In some functions, variable "ret" should be ssize_t, so we fix it. Fixes: 2f330caff577 ("memory: brcmstb: Add driver for DPFE") Signed-off-by: Markus Mayer Signed-off-by: Florian Fainelli --- drivers/memory/brcmstb_dpfe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c index 088153760e52..2013a91217a9 100644 --- a/drivers/memory/brcmstb_dpfe.c +++ b/drivers/memory/brcmstb_dpfe.c @@ -507,7 +507,7 @@ static ssize_t show_info(struct device *dev, struct device_attribute *devattr, { u32 response[MSG_FIELD_MAX]; unsigned int info; - int ret; + ssize_t ret; ret = generic_show(DPFE_CMD_GET_INFO, response, dev, buf); if (ret) @@ -531,7 +531,7 @@ static ssize_t show_refresh(struct device *dev, unsigned int offset; u8 refresh, sr_abort, ppre, thermal_offs, tuf; u32 mr4; - int ret; + ssize_t ret; ret = generic_show(DPFE_CMD_GET_REFRESH, response, dev, buf); if (ret) @@ -588,7 +588,7 @@ static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr, struct private_data *priv; void __iomem *info; unsigned int offset; - int ret; + ssize_t ret; ret = generic_show(DPFE_CMD_GET_VENDOR, response, dev, buf); if (ret) -- cgit v1.2.3 From fee5f1ef6cf76f87d9799596d06979c9e6589f2b Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Tue, 13 Feb 2018 12:40:40 -0800 Subject: memory: brcmstb: dpfe: support new way of passing data from the DCPU The DCPU can now send message data in two ways: - via the data RAM, as before (this is now message type 0) - via the message RAM (this is message type 1) In order to support both methods, we check the message type of the response (bits 31:28) and then treat the offset (bits 27:0) accordingly. Signed-off-by: Markus Mayer Signed-off-by: Florian Fainelli --- drivers/memory/brcmstb_dpfe.c | 65 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c index 2013a91217a9..e9c1485c32b9 100644 --- a/drivers/memory/brcmstb_dpfe.c +++ b/drivers/memory/brcmstb_dpfe.c @@ -45,8 +45,16 @@ #define REG_TO_DCPU_MBOX 0x10 #define REG_TO_HOST_MBOX 0x14 +/* Macros to process offsets returned by the DCPU */ +#define DRAM_MSG_ADDR_OFFSET 0x0 +#define DRAM_MSG_TYPE_OFFSET 0x1c +#define DRAM_MSG_ADDR_MASK ((1UL << DRAM_MSG_TYPE_OFFSET) - 1) +#define DRAM_MSG_TYPE_MASK ((1UL << \ + (BITS_PER_LONG - DRAM_MSG_TYPE_OFFSET)) - 1) + /* Message RAM */ -#define DCPU_MSG_RAM(x) (0x100 + (x) * sizeof(u32)) +#define DCPU_MSG_RAM_START 0x100 +#define DCPU_MSG_RAM(x) (DCPU_MSG_RAM_START + (x) * sizeof(u32)) /* DRAM Info Offsets & Masks */ #define DRAM_INFO_INTERVAL 0x0 @@ -255,6 +263,40 @@ static unsigned int get_msg_chksum(const u32 msg[]) return sum; } +static void __iomem *get_msg_ptr(struct private_data *priv, u32 response, + char *buf, ssize_t *size) +{ + unsigned int msg_type; + unsigned int offset; + void __iomem *ptr = NULL; + + msg_type = (response >> DRAM_MSG_TYPE_OFFSET) & DRAM_MSG_TYPE_MASK; + offset = (response >> DRAM_MSG_ADDR_OFFSET) & DRAM_MSG_ADDR_MASK; + + /* + * msg_type == 1: the offset is relative to the message RAM + * msg_type == 0: the offset is relative to the data RAM (this is the + * previous way of passing data) + * msg_type is anything else: there's critical hardware problem + */ + switch (msg_type) { + case 1: + ptr = priv->regs + DCPU_MSG_RAM_START + offset; + break; + case 0: + ptr = priv->dmem + offset; + break; + default: + dev_emerg(priv->dev, "invalid message reply from DCPU: %#x\n", + response); + if (buf && size) + *size = sprintf(buf, + "FATAL: communication error with DCPU\n"); + } + + return ptr; +} + static int __send_command(struct private_data *priv, unsigned int cmd, u32 result[]) { @@ -528,7 +570,6 @@ static ssize_t show_refresh(struct device *dev, u32 response[MSG_FIELD_MAX]; void __iomem *info; struct private_data *priv; - unsigned int offset; u8 refresh, sr_abort, ppre, thermal_offs, tuf; u32 mr4; ssize_t ret; @@ -538,8 +579,10 @@ static ssize_t show_refresh(struct device *dev, return ret; priv = dev_get_drvdata(dev); - offset = response[MSG_ARG0]; - info = priv->dmem + offset; + + info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret); + if (!info) + return ret; mr4 = readl_relaxed(info + DRAM_INFO_MR4) & DRAM_INFO_MR4_MASK; @@ -561,7 +604,6 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr, u32 response[MSG_FIELD_MAX]; struct private_data *priv; void __iomem *info; - unsigned int offset; unsigned long val; int ret; @@ -574,8 +616,10 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr, if (ret) return ret; - offset = response[MSG_ARG0]; - info = priv->dmem + offset; + info = get_msg_ptr(priv, response[MSG_ARG0], NULL, NULL); + if (!info) + return -EIO; + writel_relaxed(val, info + DRAM_INFO_INTERVAL); return count; @@ -587,16 +631,17 @@ static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr, u32 response[MSG_FIELD_MAX]; struct private_data *priv; void __iomem *info; - unsigned int offset; ssize_t ret; ret = generic_show(DPFE_CMD_GET_VENDOR, response, dev, buf); if (ret) return ret; - offset = response[MSG_ARG0]; priv = dev_get_drvdata(dev); - info = priv->dmem + offset; + + info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret); + if (!info) + return ret; return sprintf(buf, "%#x %#x %#x %#x %#x\n", readl_relaxed(info + DRAM_VENDOR_MR5) & DRAM_VENDOR_MASK, -- cgit v1.2.3 From e5699f56bc91a286f006b0728085e0b4e8f5749b Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Mon, 15 Jan 2018 07:32:02 -0600 Subject: crypto: ccp: Fix sparse, use plain integer as NULL pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix sparse warning: Using plain integer as NULL pointer. Replaces assignment of 0 to pointer with NULL assignment. Cc: Paolo Bonzini Cc: Radim Krčmář Cc: Borislav Petkov Cc: Herbert Xu Cc: Gary Hook Cc: Tom Lendacky Cc: linux-crypto@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Brijesh Singh Signed-off-by: Paolo Bonzini --- drivers/crypto/ccp/psp-dev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index fcfa5b1eae61..b3afb6cc9d72 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -211,7 +211,7 @@ static int __sev_platform_shutdown_locked(int *error) { int ret; - ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, 0, error); + ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error); if (ret) return ret; @@ -271,7 +271,7 @@ static int sev_ioctl_do_reset(struct sev_issue_cmd *argp) return rc; } - return __sev_do_cmd_locked(SEV_CMD_FACTORY_RESET, 0, &argp->error); + return __sev_do_cmd_locked(SEV_CMD_FACTORY_RESET, NULL, &argp->error); } static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp) @@ -299,7 +299,7 @@ static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp) return rc; } - return __sev_do_cmd_locked(cmd, 0, &argp->error); + return __sev_do_cmd_locked(cmd, NULL, &argp->error); } static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp) @@ -624,7 +624,7 @@ EXPORT_SYMBOL_GPL(sev_guest_decommission); int sev_guest_df_flush(int *error) { - return sev_do_cmd(SEV_CMD_DF_FLUSH, 0, error); + return sev_do_cmd(SEV_CMD_DF_FLUSH, NULL, error); } EXPORT_SYMBOL_GPL(sev_guest_df_flush); -- cgit v1.2.3 From b91e146c38b003c899710ede6d05fc824675e386 Mon Sep 17 00:00:00 2001 From: Richard Lai Date: Sat, 17 Feb 2018 16:28:24 +0000 Subject: iio: chemical: ccs811: Corrected firmware boot/application mode transition CCS811 has different I2C register maps in boot and application mode. When CCS811 is in boot mode, register APP_START (0xF4) is used to transit the firmware state from boot to application mode. However, APP_START is not a valid register location when CCS811 is in application mode (refer to "CCS811 Bootloader Register Map" and "CCS811 Application Register Map" in CCS811 datasheet). The driver should not attempt to perform a write to APP_START while CCS811 is in application mode, as this is not a valid or documented register location. When prob function is being called, the driver assumes the CCS811 sensor is in boot mode, and attempts to perform a write to APP_START. Although CCS811 powers-up in boot mode, it may have already been transited to application mode by previous instances, e.g. unload and reload device driver by the system, or explicitly by user. Depending on the system design, CCS811 sensor may be permanently connected to system power source rather than power controlled by GPIO, hence it is possible that the sensor is never power reset, thus the firmware could be in either boot or application mode at any given time when driver prob function is being called. This patch checks the STATUS register before attempting to send a write to APP_START. Only if the firmware is not in application mode and has valid firmware application loaded, then it will continue to start transiting the firmware boot to application mode. Signed-off-by: Richard Lai Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/ccs811.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c index fbe2431f5b81..1ea9f5513b02 100644 --- a/drivers/iio/chemical/ccs811.c +++ b/drivers/iio/chemical/ccs811.c @@ -133,6 +133,9 @@ static int ccs811_start_sensor_application(struct i2c_client *client) if (ret < 0) return ret; + if ((ret & CCS811_STATUS_FW_MODE_APPLICATION)) + return 0; + if ((ret & CCS811_STATUS_APP_VALID_MASK) != CCS811_STATUS_APP_VALID_LOADED) return -EIO; -- cgit v1.2.3 From 4e4f9fbc5620a060dc7d3a651cdfb001c1d7c2f9 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Fri, 23 Feb 2018 13:50:55 +0100 Subject: iio: adc: stm32-dfsdm: fix compatible data use Fix use of compatible data: stm32h7 regmap configuration is statically used. Rather use regmap_cfg from compatible data. Fixes: bed73904e76f ("IIO: ADC: add stm32 DFSDM core support") Signed-off-by: Fabrice Gasnier Acked-by: Arnaud Pouliquen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-dfsdm-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index 6290332cfd3f..0635f9390b20 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -274,7 +274,7 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) dfsdm->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dfsdm", dfsdm->base, - &stm32h7_dfsdm_regmap_cfg); + dev_data->regmap_cfg); if (IS_ERR(dfsdm->regmap)) { ret = PTR_ERR(dfsdm->regmap); dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", -- cgit v1.2.3 From c278609bdde9df330b7fe3d61ec1bc1a8cac4a78 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Fri, 23 Feb 2018 13:50:56 +0100 Subject: iio: adc: stm32-dfsdm: fix call to stop channel stm32_dfsdm_stop_channel must be called with channel id, not filter id. Fixes: e2e6771c6462 ("IIO: ADC: add STM32 DFSDM sigma delta ADC support") Signed-off-by: Fabrice Gasnier Acked-by: Arnaud Pouliquen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-dfsdm-adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index daa026d6a94f..0eff8119119c 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -464,7 +464,7 @@ stop_channels: regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), DFSDM_CR1_RCONT_MASK, 0); - stm32_dfsdm_stop_channel(adc->dfsdm, adc->fl_id); + stm32_dfsdm_stop_channel(adc->dfsdm, adc->ch_id); return ret; } -- cgit v1.2.3 From 179858efd94f49945d41919c1d09a8e17c2afa98 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Fri, 23 Feb 2018 13:50:57 +0100 Subject: iio: adc: stm32-dfsdm: fix clock source selection Add missing clock source selection. In case "audio" clock is provided, it's unused currently: "dfsdm" clock is wrongly used by default. Fixes: bed73904e76f ("IIO: ADC: add stm32 DFSDM core support") Signed-off-by: Fabrice Gasnier Acked-by: Arnaud Pouliquen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-dfsdm-core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index 0635f9390b20..e50efdcc41ff 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -83,7 +83,7 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) { struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); struct device *dev = &priv->pdev->dev; - unsigned int clk_div = priv->spi_clk_out_div; + unsigned int clk_div = priv->spi_clk_out_div, clk_src; int ret; if (atomic_inc_return(&priv->n_active_ch) == 1) { @@ -100,6 +100,14 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) } } + /* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */ + clk_src = priv->aclk ? 1 : 0; + ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), + DFSDM_CHCFGR1_CKOUTSRC_MASK, + DFSDM_CHCFGR1_CKOUTSRC(clk_src)); + if (ret < 0) + goto disable_aclk; + /* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */ ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), DFSDM_CHCFGR1_CKOUTDIV_MASK, -- cgit v1.2.3 From 0645af1b6988467b8362aaf44fb4013abb045bee Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Fri, 23 Feb 2018 13:50:58 +0100 Subject: iio: adc: stm32-dfsdm: fix multiple channel initialization When several channels are registered (e.g. via st,adc-channels property): - channels array is wrongly filled in. Only 1st element in array is being initialized with last registered channel. Fix it by passing reference to relevant channel (e.g. array[index]). - only last initialized channel can work properly (e.g. unique 'ch_id' is used). Converting any other channel result in conversion timeout. Fix it by getting rid of 'ch_id', use chan->channel instead. Signed-off-by: Fabrice Gasnier Acked-by: Arnaud Pouliquen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-dfsdm-adc.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 0eff8119119c..01422d11753c 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -54,7 +54,6 @@ struct stm32_dfsdm_adc { struct stm32_dfsdm *dfsdm; const struct stm32_dfsdm_dev_data *dev_data; unsigned int fl_id; - unsigned int ch_id; /* ADC specific */ unsigned int oversamp; @@ -384,7 +383,7 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; - struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[adc->ch_id]; + struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel]; unsigned int sample_freq = adc->sample_freq; unsigned int spi_freq; int ret; @@ -419,18 +418,20 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, return len; } -static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, bool dma) +static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, + const struct iio_chan_spec *chan, + bool dma) { struct regmap *regmap = adc->dfsdm->regmap; int ret; unsigned int dma_en = 0, cont_en = 0; - ret = stm32_dfsdm_start_channel(adc->dfsdm, adc->ch_id); + ret = stm32_dfsdm_start_channel(adc->dfsdm, chan->channel); if (ret < 0) return ret; ret = stm32_dfsdm_filter_configure(adc->dfsdm, adc->fl_id, - adc->ch_id); + chan->channel); if (ret < 0) goto stop_channels; @@ -464,12 +465,13 @@ stop_channels: regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), DFSDM_CR1_RCONT_MASK, 0); - stm32_dfsdm_stop_channel(adc->dfsdm, adc->ch_id); + stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel); return ret; } -static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc) +static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc, + const struct iio_chan_spec *chan) { struct regmap *regmap = adc->dfsdm->regmap; @@ -482,7 +484,7 @@ static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc) regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), DFSDM_CR1_RCONT_MASK, 0); - stm32_dfsdm_stop_channel(adc->dfsdm, adc->ch_id); + stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel); } static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, @@ -609,6 +611,7 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) static int stm32_dfsdm_postenable(struct iio_dev *indio_dev) { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + const struct iio_chan_spec *chan = &indio_dev->channels[0]; int ret; /* Reset adc buffer index */ @@ -618,7 +621,7 @@ static int stm32_dfsdm_postenable(struct iio_dev *indio_dev) if (ret < 0) return ret; - ret = stm32_dfsdm_start_conv(adc, true); + ret = stm32_dfsdm_start_conv(adc, chan, true); if (ret) { dev_err(&indio_dev->dev, "Can't start conversion\n"); goto stop_dfsdm; @@ -635,7 +638,7 @@ static int stm32_dfsdm_postenable(struct iio_dev *indio_dev) return 0; err_stop_conv: - stm32_dfsdm_stop_conv(adc); + stm32_dfsdm_stop_conv(adc, chan); stop_dfsdm: stm32_dfsdm_stop_dfsdm(adc->dfsdm); @@ -645,11 +648,12 @@ stop_dfsdm: static int stm32_dfsdm_predisable(struct iio_dev *indio_dev) { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + const struct iio_chan_spec *chan = &indio_dev->channels[0]; if (adc->dma_chan) dmaengine_terminate_all(adc->dma_chan); - stm32_dfsdm_stop_conv(adc); + stm32_dfsdm_stop_conv(adc, chan); stm32_dfsdm_stop_dfsdm(adc->dfsdm); @@ -730,7 +734,7 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, if (ret < 0) goto stop_dfsdm; - ret = stm32_dfsdm_start_conv(adc, false); + ret = stm32_dfsdm_start_conv(adc, chan, false); if (ret < 0) { regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0)); @@ -751,7 +755,7 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, else ret = IIO_VAL_INT; - stm32_dfsdm_stop_conv(adc); + stm32_dfsdm_stop_conv(adc, chan); stop_dfsdm: stm32_dfsdm_stop_dfsdm(adc->dfsdm); @@ -765,7 +769,7 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; - struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[adc->ch_id]; + struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel]; unsigned int spi_freq = adc->spi_freq; int ret = -EINVAL; @@ -972,7 +976,6 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, } ch->scan_type.realbits = 24; ch->scan_type.storagebits = 32; - adc->ch_id = ch->channel; return stm32_dfsdm_chan_configure(adc->dfsdm, &adc->dfsdm->ch_list[ch->channel]); @@ -1001,7 +1004,7 @@ static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev) } ch->info_mask_separate = BIT(IIO_CHAN_INFO_SAMP_FREQ); - d_ch = &adc->dfsdm->ch_list[adc->ch_id]; + d_ch = &adc->dfsdm->ch_list[ch->channel]; if (d_ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL) adc->spi_freq = adc->dfsdm->spi_master_freq; @@ -1042,8 +1045,8 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) return -ENOMEM; for (chan_idx = 0; chan_idx < num_ch; chan_idx++) { - ch->scan_index = chan_idx; - ret = stm32_dfsdm_adc_chan_init_one(indio_dev, ch); + ch[chan_idx].scan_index = chan_idx; + ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]); if (ret < 0) { dev_err(&indio_dev->dev, "Channels init failed\n"); return ret; -- cgit v1.2.3 From 78dc897b7ee67205423dbbc6b56be49fb18d15b5 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 22 Feb 2018 14:28:59 -0600 Subject: rtlwifi: rtl8723be: Fix loss of signal In commit c713fb071edc ("rtlwifi: rtl8821ae: Fix connection lost problem correctly") a problem in rtl8821ae that caused loss of signal was fixed. That same problem has now been reported for rtl8723be. Accordingly, the ASPM L1 latency has been increased from 0 to 7 to fix the instability. Signed-off-by: Larry Finger Cc: Stable Tested-by: James Cameron Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index f9ccd13c79f9..e7bbbc95cdb1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -1125,7 +1125,8 @@ static void _rtl8723be_enable_aspm_back_door(struct ieee80211_hw *hw) /* Configuration Space offset 0x70f BIT7 is used to control L0S */ tmp8 = _rtl8723be_dbi_read(rtlpriv, 0x70f); - _rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7)); + _rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7) | + ASPM_L1_LATENCY << 3); /* Configuration Space offset 0x719 Bit3 is for L1 * BIT4 is for clock request -- cgit v1.2.3 From de9647efeaa9f4e8b08c002e09757fd9c55ff901 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 22 Feb 2018 13:58:42 -0600 Subject: platform/x86: intel-vbtn: Only activate tablet mode switch on 2-in-1's Some laptops such as the XPS 9360 support the intel-vbtn INT33D6 interface but don't initialize the bit that intel-vbtn uses to represent switching tablet mode. By running this only on real 2-in-1's it shouldn't cause false positives. Fixes: 30323fb6d5 ("Support tablet mode switch") Reported-by: Jeremy Cline Signed-off-by: Mario Limonciello Tested-by: Jeremy Cline Tested-by: Darren Hart (VMware) Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/intel-vbtn.c | 46 ++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index b703d6f5b099..8173307d6bb1 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -97,9 +98,35 @@ out_unknown: dev_dbg(&device->dev, "unknown event index 0x%x\n", event); } -static int intel_vbtn_probe(struct platform_device *device) +static void detect_tablet_mode(struct platform_device *device) { + const char *chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); + struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); + acpi_handle handle = ACPI_HANDLE(&device->dev); struct acpi_buffer vgbs_output = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + int m; + + if (!(chassis_type && strcmp(chassis_type, "31") == 0)) + goto out; + + status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output); + if (ACPI_FAILURE(status)) + goto out; + + obj = vgbs_output.pointer; + if (!(obj && obj->type == ACPI_TYPE_INTEGER)) + goto out; + + m = !(obj->integer.value & TABLET_MODE_FLAG); + input_report_switch(priv->input_dev, SW_TABLET_MODE, m); +out: + kfree(vgbs_output.pointer); +} + +static int intel_vbtn_probe(struct platform_device *device) +{ acpi_handle handle = ACPI_HANDLE(&device->dev); struct intel_vbtn_priv *priv; acpi_status status; @@ -122,22 +149,7 @@ static int intel_vbtn_probe(struct platform_device *device) return err; } - /* - * VGBS being present and returning something means we have - * a tablet mode switch. - */ - status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output); - if (ACPI_SUCCESS(status)) { - union acpi_object *obj = vgbs_output.pointer; - - if (obj && obj->type == ACPI_TYPE_INTEGER) { - int m = !(obj->integer.value & TABLET_MODE_FLAG); - - input_report_switch(priv->input_dev, SW_TABLET_MODE, m); - } - } - - kfree(vgbs_output.pointer); + detect_tablet_mode(device); status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY, -- cgit v1.2.3 From 43a521238aca0e24d50add1db125a61bda2a3527 Mon Sep 17 00:00:00 2001 From: Lidong Zhong Date: Tue, 23 Jan 2018 23:06:12 +0800 Subject: md-cluster: choose correct label when clustered layout is not supported r10conf is already successfully allocated before checking the layout Signed-off-by: Lidong Zhong Reviewed-by: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/raid10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 9e9441fde8b3..93fa947fef22 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -3784,7 +3784,7 @@ static int raid10_run(struct mddev *mddev) if (fc > 1 || fo > 0) { pr_err("only near layout is supported by clustered" " raid10\n"); - goto out; + goto out_free_conf; } } -- cgit v1.2.3 From 8876391e440ba615b10eef729576e111f0315f87 Mon Sep 17 00:00:00 2001 From: BingJing Chang Date: Thu, 22 Feb 2018 13:34:46 +0800 Subject: md: fix a potential deadlock of raid5/raid10 reshape There is a potential deadlock if mount/umount happens when raid5_finish_reshape() tries to grow the size of emulated disk. How the deadlock happens? 1) The raid5 resync thread finished reshape (expanding array). 2) The mount or umount thread holds VFS sb->s_umount lock and tries to write through critical data into raid5 emulated block device. So it waits for raid5 kernel thread handling stripes in order to finish it I/Os. 3) In the routine of raid5 kernel thread, md_check_recovery() will be called first in order to reap the raid5 resync thread. That is, raid5_finish_reshape() will be called. In this function, it will try to update conf and call VFS revalidate_disk() to grow the raid5 emulated block device. It will try to acquire VFS sb->s_umount lock. The raid5 kernel thread cannot continue, so no one can handle mount/ umount I/Os (stripes). Once the write-through I/Os cannot be finished, mount/umount will not release sb->s_umount lock. The deadlock happens. The raid5 kernel thread is an emulated block device. It is responible to handle I/Os (stripes) from upper layers. The emulated block device should not request any I/Os on itself. That is, it should not call VFS layer functions. (If it did, it will try to acquire VFS locks to guarantee the I/Os sequence.) So we have the resync thread to send resync I/O requests and to wait for the results. For solving this potential deadlock, we can put the size growth of the emulated block device as the final step of reshape thread. 2017/12/29: Thanks to Guoqing Jiang , we confirmed that there is the same deadlock issue in raid10. It's reproducible and can be fixed by this patch. For raid10.c, we can remove the similar code to prevent deadlock as well since they has been called before. Reported-by: Alex Wu Reviewed-by: Alex Wu Reviewed-by: Chung-Chiang Cheng Signed-off-by: BingJing Chang Signed-off-by: Shaohua Li --- drivers/md/md.c | 13 +++++++++++++ drivers/md/raid10.c | 8 +------- drivers/md/raid5.c | 8 +------- 3 files changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index ba152dddaaa3..254e44e44668 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8569,6 +8569,19 @@ void md_do_sync(struct md_thread *thread) set_mask_bits(&mddev->sb_flags, 0, BIT(MD_SB_CHANGE_PENDING) | BIT(MD_SB_CHANGE_DEVS)); + if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && + !test_bit(MD_RECOVERY_INTR, &mddev->recovery) && + mddev->delta_disks > 0 && + mddev->pers->finish_reshape && + mddev->pers->size && + mddev->queue) { + mddev_lock_nointr(mddev); + md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0)); + mddev_unlock(mddev); + set_capacity(mddev->gendisk, mddev->array_sectors); + revalidate_disk(mddev->gendisk); + } + spin_lock(&mddev->lock); if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { /* We completed so min/max setting can be forgotten if used. */ diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 93fa947fef22..c5e6c60fc0d4 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -4832,17 +4832,11 @@ static void raid10_finish_reshape(struct mddev *mddev) return; if (mddev->delta_disks > 0) { - sector_t size = raid10_size(mddev, 0, 0); - md_set_array_sectors(mddev, size); if (mddev->recovery_cp > mddev->resync_max_sectors) { mddev->recovery_cp = mddev->resync_max_sectors; set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); } - mddev->resync_max_sectors = size; - if (mddev->queue) { - set_capacity(mddev->gendisk, mddev->array_sectors); - revalidate_disk(mddev->gendisk); - } + mddev->resync_max_sectors = mddev->array_sectors; } else { int d; rcu_read_lock(); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e3b0f799fbfa..b5d2601483e3 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -8000,13 +8000,7 @@ static void raid5_finish_reshape(struct mddev *mddev) if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { - if (mddev->delta_disks > 0) { - md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); - if (mddev->queue) { - set_capacity(mddev->gendisk, mddev->array_sectors); - revalidate_disk(mddev->gendisk); - } - } else { + if (mddev->delta_disks <= 0) { int d; spin_lock_irq(&conf->device_lock); mddev->degraded = raid5_calc_degraded(conf); -- cgit v1.2.3 From 3de59bb9d551428cbdc76a9ea57883f82e350b4d Mon Sep 17 00:00:00 2001 From: Yufen Yu Date: Sat, 24 Feb 2018 12:05:56 +0800 Subject: md/raid1: fix NULL pointer dereference In handle_write_finished(), if r1_bio->bios[m] != NULL, it thinks the corresponding conf->mirrors[m].rdev is also not NULL. But, it is not always true. Even if some io hold replacement rdev(i.e. rdev->nr_pending.count > 0), raid1_remove_disk() can also set the rdev as NULL. That means, bios[m] != NULL, but mirrors[m].rdev is NULL, resulting in NULL pointer dereference in handle_write_finished and sync_request_write. This patch can fix BUGs as follows: BUG: unable to handle kernel NULL pointer dereference at 0000000000000140 IP: [] raid1d+0x2bd/0xfc0 PGD 12ab52067 PUD 12f587067 PMD 0 Oops: 0000 [#1] SMP CPU: 1 PID: 2008 Comm: md3_raid1 Not tainted 4.1.44+ #130 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1.fc26 04/01/2014 Call Trace: ? schedule+0x37/0x90 ? prepare_to_wait_event+0x83/0xf0 md_thread+0x144/0x150 ? wake_atomic_t_function+0x70/0x70 ? md_start_sync+0xf0/0xf0 kthread+0xd8/0xf0 ? kthread_worker_fn+0x160/0x160 ret_from_fork+0x42/0x70 ? kthread_worker_fn+0x160/0x160 BUG: unable to handle kernel NULL pointer dereference at 00000000000000b8 IP: sync_request_write+0x9e/0x980 PGD 800000007c518067 P4D 800000007c518067 PUD 8002b067 PMD 0 Oops: 0000 [#1] SMP PTI CPU: 24 PID: 2549 Comm: md3_raid1 Not tainted 4.15.0+ #118 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1.fc26 04/01/2014 Call Trace: ? sched_clock+0x5/0x10 ? sched_clock_cpu+0xc/0xb0 ? flush_pending_writes+0x3a/0xd0 ? pick_next_task_fair+0x4d5/0x5f0 ? __switch_to+0xa2/0x430 raid1d+0x65a/0x870 ? find_pers+0x70/0x70 ? find_pers+0x70/0x70 ? md_thread+0x11c/0x160 md_thread+0x11c/0x160 ? finish_wait+0x80/0x80 kthread+0x111/0x130 ? kthread_create_worker_on_cpu+0x70/0x70 ? do_syscall_64+0x6f/0x190 ? SyS_exit_group+0x10/0x10 ret_from_fork+0x35/0x40 Reviewed-by: NeilBrown Signed-off-by: Yufen Yu Signed-off-by: Shaohua Li --- drivers/md/raid1.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index f978eddc7a21..fe872dc6712e 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1809,6 +1809,17 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) struct md_rdev *repl = conf->mirrors[conf->raid_disks + number].rdev; freeze_array(conf, 0); + if (atomic_read(&repl->nr_pending)) { + /* It means that some queued IO of retry_list + * hold repl. Thus, we cannot set replacement + * as NULL, avoiding rdev NULL pointer + * dereference in sync_request_write and + * handle_write_finished. + */ + err = -EBUSY; + unfreeze_array(conf); + goto abort; + } clear_bit(Replacement, &repl->flags); p->rdev = repl; conf->mirrors[conf->raid_disks + number].rdev = NULL; -- cgit v1.2.3 From 1fdb926974695d3dbc05a429bafa266fdd16510e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 20 Feb 2018 09:06:18 +0100 Subject: Bluetooth: btusb: Use DMI matching for QCA reset_resume quirking Commit 61f5acea8737 ("Bluetooth: btusb: Restore QCA Rome suspend/resume fix with a "rewritten" version") applied the USB_QUIRK_RESET_RESUME to all QCA USB Bluetooth modules. But it turns out that the resume problems are not caused by the QCA Rome chipset, on most platforms it resumes fine. The resume problems are actually a platform problem (likely the platform cutting all power when suspended). The USB_QUIRK_RESET_RESUME quirk also disables runtime suspend, so by matching on usb-ids, we're causing all boards with these chips to use extra power, to fix resume problems which only happen on some boards. This commit fixes this by applying the quirk based on DMI matching instead of on usb-ids, so that we match the platform and not the chipset. Here is the /sys/kernel/debug/usb/devices for the Bluetooth module: T: Bus=01 Lev=01 Prnt=01 Port=07 Cnt=04 Dev#= 5 Spd=12 MxCh= 0 D: Ver= 2.01 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=e300 Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1514836 Fixes: 61f5acea8737 ("Bluetooth: btusb: Restore QCA Rome suspend/resume..") Cc: stable@vger.kernel.org Cc: Brian Norris Cc: Kai-Heng Feng Reported-and-tested-by: Kevin Fenzi Signed-off-by: Hans de Goede Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 2a55380ad730..60bf04b8f103 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -21,6 +21,7 @@ * */ +#include #include #include #include @@ -379,6 +380,21 @@ static const struct usb_device_id blacklist_table[] = { { } /* Terminating entry */ }; +/* The Bluetooth USB module build into some devices needs to be reset on resume, + * this is a problem with the platform (likely shutting off all power) not with + * the module itself. So we use a DMI list to match known broken platforms. + */ +static const struct dmi_system_id btusb_needs_reset_resume_table[] = { + { + /* Lenovo Yoga 920 (QCA Rome device 0cf3:e300) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920"), + }, + }, + {} +}; + #define BTUSB_MAX_ISOC_FRAMES 10 #define BTUSB_INTR_RUNNING 0 @@ -2945,6 +2961,9 @@ static int btusb_probe(struct usb_interface *intf, hdev->send = btusb_send_frame; hdev->notify = btusb_notify; + if (dmi_check_system(btusb_needs_reset_resume_table)) + interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME; + #ifdef CONFIG_PM err = btusb_config_oob_wake(hdev); if (err) @@ -3031,12 +3050,6 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_QCA_ROME) { data->setup_on_usb = btusb_setup_qca; hdev->set_bdaddr = btusb_set_bdaddr_ath3012; - - /* QCA Rome devices lose their updated firmware over suspend, - * but the USB hub doesn't notice any status change. - * explicitly request a device reset on resume. - */ - interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME; } #ifdef CONFIG_BT_HCIBTUSB_RTL -- cgit v1.2.3 From ab2f336cb7e629de74d8af06bcaf6b15e4230e19 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 25 Feb 2018 15:10:52 +0100 Subject: Bluetooth: hci_bcm: Make shutdown and device wake GPIO optional According to the devicetree binding the shutdown and device wake GPIOs are optional. Since commit 3e81a4ca51a1 ("Bluetooth: hci_bcm: Mandate presence of shutdown and device wake GPIO") this driver won't probe anymore on Raspberry Pi 3 and Zero W (no device wake GPIO connected). So fix this regression by reverting this commit partially. Fixes: 3e81a4ca51a1 ("Bluetooth: hci_bcm: Mandate presence of shutdown and device wake GPIO") Signed-off-by: Stefan Wahren Reviewed-by: Lukas Wunner Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_bcm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 0438a64b8185..6314dfb02969 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -922,12 +922,13 @@ static int bcm_get_resources(struct bcm_device *dev) dev->clk = devm_clk_get(dev->dev, NULL); - dev->device_wakeup = devm_gpiod_get(dev->dev, "device-wakeup", - GPIOD_OUT_LOW); + dev->device_wakeup = devm_gpiod_get_optional(dev->dev, "device-wakeup", + GPIOD_OUT_LOW); if (IS_ERR(dev->device_wakeup)) return PTR_ERR(dev->device_wakeup); - dev->shutdown = devm_gpiod_get(dev->dev, "shutdown", GPIOD_OUT_LOW); + dev->shutdown = devm_gpiod_get_optional(dev->dev, "shutdown", + GPIOD_OUT_LOW); if (IS_ERR(dev->shutdown)) return PTR_ERR(dev->shutdown); -- cgit v1.2.3 From a22f1d801ad4987508b8c1b701c4926f733ac18b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 20 Feb 2018 11:29:03 +0100 Subject: drm/pl111: Remove reverse dependency on DRM_DUMB_VGA_DAC DRM_DUMB_VGA_DAC is a user-visible symbol. Selecting it can cause unmet direct dependencies such as this (on i386, randconfig): warning: (DRM_PL111) selects DRM_DUMB_VGA_DAC which has unmet direct dependencies (HAS_IOMEM && DRM && DRM_BRIDGE && OF) This is because DRM_DUMB_VGA_DAC depends on OF while DRM_PL111 does not. It does indirectly depend on OF via the ARM and ARM64 dependencies, but since it can also be enabled under COMPILE_TEST, randconfig can find a case where DRM_PL111 is selected without pulling in OF and not meeting the dependency for DRM_DUMB_VGA_DAC. Since select is "heavy handed", DRM_DUMB_VGA_DAC is going to be enabled regardless of the above warning and causes the following build error: ../drivers/gpu/drm/bridge/dumb-vga-dac.c: In function 'dumb_vga_probe': ../drivers/gpu/drm/bridge/dumb-vga-dac.c:207:13: error: 'struct drm_bridge' has no member named 'of_node' vga->bridge.of_node = pdev->dev.of_node; See Documentation/kbuild/kconfig-language.txt, "reverse dependencies". Fixes: 49f81d80ab84 ("drm/pl111: Support handling bridge timings") Reported-by: Randy Dunlap Reviewed-by: Eric Anholt Cc: Laurent Pinchart Cc: Archit Taneja Cc: Eric Anholt Signed-off-by: Thierry Reding Signed-off-by: Archit Taneja Link: https://patchwork.freedesktop.org/patch/msgid/20180220102903.27787-1-thierry.reding@gmail.com --- drivers/gpu/drm/pl111/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/pl111/Kconfig b/drivers/gpu/drm/pl111/Kconfig index 82cb3e60ddc8..e5e2abd66491 100644 --- a/drivers/gpu/drm/pl111/Kconfig +++ b/drivers/gpu/drm/pl111/Kconfig @@ -8,7 +8,6 @@ config DRM_PL111 select DRM_GEM_CMA_HELPER select DRM_BRIDGE select DRM_PANEL_BRIDGE - select DRM_DUMB_VGA_DAC select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE help Choose this option for DRM support for the PL111 CLCD controller. -- cgit v1.2.3 From f25a2dfc20e3a3ed8fe6618c331799dd7bd01190 Mon Sep 17 00:00:00 2001 From: Jianchao Wang Date: Thu, 15 Feb 2018 19:13:41 +0800 Subject: nvme-pci: Fix nvme queue cleanup if IRQ setup fails This patch fixes nvme queue cleanup if requesting an IRQ handler for the queue's vector fails. It does this by resetting the cq_vector to the uninitialized value of -1 so it is ignored for a controller reset. Signed-off-by: Jianchao Wang [changelog updates, removed misc whitespace changes] Signed-off-by: Keith Busch --- drivers/nvme/host/pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 6fe7af00a1f4..022b070e60b7 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1452,7 +1452,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) nvmeq->cq_vector = qid - 1; result = adapter_alloc_cq(dev, qid, nvmeq); if (result < 0) - return result; + goto release_vector; result = adapter_alloc_sq(dev, qid, nvmeq); if (result < 0) @@ -1466,9 +1466,12 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) return result; release_sq: + dev->online_queues--; adapter_delete_sq(dev, qid); release_cq: adapter_delete_cq(dev, qid); + release_vector: + nvmeq->cq_vector = -1; return result; } -- cgit v1.2.3 From 80b79e31c4195731464d96716f15716f38a555eb Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Thu, 22 Feb 2018 17:12:17 +0100 Subject: drm/sun4i: Enable the output on the pins (tcon0) I noticed that with 4.16-rc1 LVDS output on A83T based TBS A711 tablet doesn't work (there's output but it's garbled). I compared some older patches for LVDS support with the mainlined ones and this change is missing from mainline Linux. I don't know what the register does exactly and the harcoded register value doesn't inspire much confidence that it will work in a general case, so I'm sending this RFC. This patch fixes the issue on A83T. Signed-off-by: Ondrej Jirman Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180222161217.23904-1-megous@megous.com --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 3c15cf24b503..51740ddb4b32 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -335,6 +335,9 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon, regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, SUN4I_TCON_GCTL_IOMAP_MASK, SUN4I_TCON_GCTL_IOMAP_TCON0); + + /* Enable the output on the pins */ + regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0xe0000000); } static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, -- cgit v1.2.3 From 79d103a565d16b1893d990b2ee5e0fe71767759f Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 21 Feb 2018 10:20:27 +0100 Subject: drm/sun4i: Protect the TCON pixel clocks Both TCON clocks are very sensitive to clock changes, since any change might lead to improper timings. Make sure our rate is never changed. Tested-by: Giulio Benetti Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/d5224d2e81ecf73dc09f234e580ada52c00eaee3.1519204731.git-series.maxime.ripard@bootlin.com --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 51740ddb4b32..b3960118deb9 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -260,7 +260,7 @@ static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon, const struct drm_display_mode *mode) { /* Configure the dot clock */ - clk_set_rate(tcon->dclk, mode->crtc_clock * 1000); + clk_set_rate_exclusive(tcon->dclk, mode->crtc_clock * 1000); /* Set the resolution */ regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG, @@ -421,7 +421,7 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon, WARN_ON(!tcon->quirks->has_channel_1); /* Configure the dot clock */ - clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000); + clk_set_rate_exclusive(tcon->sclk1, mode->crtc_clock * 1000); /* Adjust clock delay */ clk_delay = sun4i_tcon_get_clk_delay(mode, 1); -- cgit v1.2.3 From f287eb9013ccf199cbfa4eabd80c36fedfc15a73 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 26 Feb 2018 11:36:14 +0000 Subject: clocksource/drivers/fsl_ftm_timer: Fix error return checking The error checks on freq for a negative error return always fails because freq is unsigned and can never be negative. Fix this by making freq a signed long. Detected with Coccinelle: drivers/clocksource/fsl_ftm_timer.c:287:5-9: WARNING: Unsigned expression compared with zero: freq <= 0 drivers/clocksource/fsl_ftm_timer.c:291:5-9: WARNING: Unsigned expression compared with zero: freq <= 0 Fixes: 2529c3a33079 ("clocksource: Add Freescale FlexTimer Module (FTM) timer support") Signed-off-by: Colin Ian King Signed-off-by: Thomas Gleixner Cc: Daniel Lezcano Cc: kernel-janitors@vger.kernel.org Link: https://lkml.kernel.org/r/20180226113614.3092-1-colin.king@canonical.com --- drivers/clocksource/fsl_ftm_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c index 3ee7e6fea621..846d18daf893 100644 --- a/drivers/clocksource/fsl_ftm_timer.c +++ b/drivers/clocksource/fsl_ftm_timer.c @@ -281,7 +281,7 @@ static int __init __ftm_clk_init(struct device_node *np, char *cnt_name, static unsigned long __init ftm_clk_init(struct device_node *np) { - unsigned long freq; + long freq; freq = __ftm_clk_init(np, "ftm-evt-counter-en", "ftm-evt"); if (freq <= 0) -- cgit v1.2.3 From 23163a7d4b032489d375099d56571371c0456980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 Dec 2017 21:22:30 +0200 Subject: drm: Check that the plane supports the request format+modifier combo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we only check that the plane supports the pixel format of the fb we're about to feed to it. Extend it to check also the modifier, and more specifically that the combination of the format and modifier is supported. Cc: dri-devel@lists.freedesktop.org Cc: Ben Widawsky Cc: Jason Ekstrand Cc: Daniel Stone Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20171222192231.17981-8-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 10 ++++++---- drivers/gpu/drm/drm_crtc.c | 10 ++++++---- drivers/gpu/drm/drm_crtc_internal.h | 4 ++-- drivers/gpu/drm/drm_plane.c | 33 ++++++++++++++++++++++++++------- 4 files changed, 40 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 46733d534587..3a30ee715752 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -882,12 +882,14 @@ static int drm_atomic_plane_check(struct drm_plane *plane, } /* Check whether this plane supports the fb pixel format. */ - ret = drm_plane_check_pixel_format(plane, state->fb->format->format); + ret = drm_plane_check_pixel_format(plane, state->fb->format->format, + state->fb->modifier); if (ret) { struct drm_format_name_buf format_name; - DRM_DEBUG_ATOMIC("Invalid pixel format %s\n", - drm_get_format_name(state->fb->format->format, - &format_name)); + DRM_DEBUG_ATOMIC("Invalid pixel format %s, modifier 0x%llx\n", + drm_get_format_name(state->fb->format->format, + &format_name), + state->fb->modifier); return ret; } diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 353e24fcde9e..03583887cfec 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -629,12 +629,14 @@ retry: */ if (!crtc->primary->format_default) { ret = drm_plane_check_pixel_format(crtc->primary, - fb->format->format); + fb->format->format, + fb->modifier); if (ret) { struct drm_format_name_buf format_name; - DRM_DEBUG_KMS("Invalid pixel format %s\n", - drm_get_format_name(fb->format->format, - &format_name)); + DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n", + drm_get_format_name(fb->format->format, + &format_name), + fb->modifier); goto out; } } diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index af00f42ba269..860968a64ae7 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -196,8 +196,8 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, /* drm_plane.c */ int drm_plane_register_all(struct drm_device *dev); void drm_plane_unregister_all(struct drm_device *dev); -int drm_plane_check_pixel_format(const struct drm_plane *plane, - u32 format); +int drm_plane_check_pixel_format(struct drm_plane *plane, + u32 format, u64 modifier); /* drm_bridge.c */ void drm_bridge_detach(struct drm_bridge *bridge); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 22b54663b6e7..46fbd019a337 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -549,16 +549,33 @@ int drm_mode_getplane(struct drm_device *dev, void *data, return 0; } -int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) +int drm_plane_check_pixel_format(struct drm_plane *plane, + u32 format, u64 modifier) { unsigned int i; for (i = 0; i < plane->format_count; i++) { if (format == plane->format_types[i]) - return 0; + break; + } + if (i == plane->format_count) + return -EINVAL; + + if (!plane->modifier_count) + return 0; + + for (i = 0; i < plane->modifier_count; i++) { + if (modifier == plane->modifiers[i]) + break; } + if (i == plane->modifier_count) + return -EINVAL; - return -EINVAL; + if (plane->funcs->format_mod_supported && + !plane->funcs->format_mod_supported(plane, format, modifier)) + return -EINVAL; + + return 0; } /* @@ -602,12 +619,14 @@ static int __setplane_internal(struct drm_plane *plane, } /* Check whether this plane supports the fb pixel format. */ - ret = drm_plane_check_pixel_format(plane, fb->format->format); + ret = drm_plane_check_pixel_format(plane, fb->format->format, + fb->modifier); if (ret) { struct drm_format_name_buf format_name; - DRM_DEBUG_KMS("Invalid pixel format %s\n", - drm_get_format_name(fb->format->format, - &format_name)); + DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n", + drm_get_format_name(fb->format->format, + &format_name), + fb->modifier); goto out; } -- cgit v1.2.3 From 9f91280febf718ef5dc089a6be06bb48fcc89729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 Dec 2017 21:22:31 +0200 Subject: drm/i915: Remove the pipe/plane ID checks from skl_check_ccs_aux_surface() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The core now checks that the plane supports the fb's format+modifier combination, so we can drop the related checks from skl_check_ccs_aux_surface(). These checks were specific to SKL/KBL/BXT anyway. Cc: Ben Widawsky Cc: Jason Ekstrand Cc: Daniel Stone Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20171222192231.17981-9-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/intel_display.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 60ba5bb3f34c..3d2929c44804 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3063,9 +3063,6 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state) static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state) { - struct intel_plane *plane = to_intel_plane(plane_state->base.plane); - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - struct intel_crtc *crtc = to_intel_crtc(plane_state->base.crtc); const struct drm_framebuffer *fb = plane_state->base.fb; int src_x = plane_state->base.src.x1 >> 16; int src_y = plane_state->base.src.y1 >> 16; @@ -3075,11 +3072,6 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state) int y = src_y / vsub; u32 offset; - if (!skl_plane_has_ccs(dev_priv, crtc->pipe, plane->id)) { - DRM_DEBUG_KMS("No RC support on %s\n", plane->base.name); - return -EINVAL; - } - if (plane_state->base.rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180)) { DRM_DEBUG_KMS("RC support only with 0/180 degree rotation %x\n", plane_state->base.rotation); -- cgit v1.2.3 From f6d25e1ccf2e72d87bb9d7327847ce5d9e7062ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 26 Feb 2018 16:24:23 +0200 Subject: drm: Include the header with the prototype for drm_get_panel_orientation_quirk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sparse complains: drivers/gpu/drm/drm_panel_orientation_quirks.c:133:5: warning: symbol 'drm_get_panel_orientation_quirk' was not declared. Should it be static? Cc: Hans de Goede Cc: Daniel Vetter Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180226142423.26439-1-ville.syrjala@linux.intel.com Reviewed-by: Hans de Goede --- drivers/gpu/drm/drm_panel_orientation_quirks.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index 1f2af707ce03..902cc1a71e45 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -11,6 +11,7 @@ #include #include #include +#include #ifdef CONFIG_DMI -- cgit v1.2.3 From 68d2059be660944152ba667e43c3b4ec225974bc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 22 Feb 2018 17:22:59 +0000 Subject: xen/pvcalls: fix null pointer dereference on map->sock Currently if map is null then a potential null pointer deference occurs when calling sock_release on map->sock. I believe the actual intention was to call sock_release on sock instead. Fix this. Fixes: 5db4d286a8ef ("xen/pvcalls: implement connect command") Signed-off-by: Colin Ian King Reviewed-by: Juergen Gross Signed-off-by: Juergen Gross --- drivers/xen/pvcalls-back.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c index 156e5aea36db..b1092fbefa63 100644 --- a/drivers/xen/pvcalls-back.c +++ b/drivers/xen/pvcalls-back.c @@ -416,7 +416,7 @@ static int pvcalls_back_connect(struct xenbus_device *dev, sock); if (!map) { ret = -EFAULT; - sock_release(map->sock); + sock_release(sock); } out: -- cgit v1.2.3 From 7dbdd16a79a9d27d7dca0a49029fc8966dcfecc5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 26 Feb 2018 11:30:40 -0500 Subject: media: vb2: Makefile: place vb2-trace together with vb2-core We don't want a separate module for vb2-trace. That fixes this warning: WARNING: modpost: missing MODULE_LICENSE() in drivers/media/common/videobuf2/vb2-trace.o When building as module. While here, add a SPDX header. Reported-by: Stephen Rothwell Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/Makefile | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/videobuf2/Makefile b/drivers/media/common/videobuf2/Makefile index 067badb1aaa7..77bebe8b202f 100644 --- a/drivers/media/common/videobuf2/Makefile +++ b/drivers/media/common/videobuf2/Makefile @@ -1,11 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0 +videobuf2-common-objs := videobuf2-core.o -obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o +ifeq ($(CONFIG_TRACEPOINTS),y) + videobuf2-common-objs += vb2-trace.o +endif + +obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-common.o obj-$(CONFIG_VIDEOBUF2_V4L2) += videobuf2-v4l2.o obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o obj-$(CONFIG_VIDEOBUF2_DVB) += videobuf2-dvb.o -ifeq ($(CONFIG_TRACEPOINTS),y) - obj-$(CONFIG_VIDEOBUF2_CORE) += vb2-trace.o -endif -- cgit v1.2.3 From 3079c22ea815775837a4f389ce2f7e1e7b202e09 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 26 Feb 2018 13:01:38 +0100 Subject: genhd: Rename get_disk() to get_disk_and_module() Rename get_disk() to get_disk_and_module() to make sure what the function does. It's not a great name but at least it is now clear that put_disk() is not it's counterpart. Signed-off-by: Jan Kara Signed-off-by: Jens Axboe --- drivers/block/amiflop.c | 2 +- drivers/block/ataflop.c | 2 +- drivers/block/brd.c | 2 +- drivers/block/floppy.c | 2 +- drivers/block/loop.c | 2 +- drivers/block/swim.c | 2 +- drivers/block/z2ram.c | 2 +- drivers/ide/ide-probe.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index e5aa62fcf5a8..3aaf6af3ec23 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1758,7 +1758,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) if (unit[drive].type->code == FD_NODRIVE) return NULL; *part = 0; - return get_disk(unit[drive].gendisk); + return get_disk_and_module(unit[drive].gendisk); } static int __init amiga_floppy_probe(struct platform_device *pdev) diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 8bc3b9fd8dd2..dfb2c2622e5a 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1917,7 +1917,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS) return NULL; *part = 0; - return get_disk(unit[drive].disk); + return get_disk_and_module(unit[drive].disk); } static int __init atari_floppy_init (void) diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 8028a3a7e7fd..deea78e485da 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -456,7 +456,7 @@ static struct kobject *brd_probe(dev_t dev, int *part, void *data) mutex_lock(&brd_devices_mutex); brd = brd_init_one(MINOR(dev) / max_part, &new); - kobj = brd ? get_disk(brd->brd_disk) : NULL; + kobj = brd ? get_disk_and_module(brd->brd_disk) : NULL; mutex_unlock(&brd_devices_mutex); if (new) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index eae484acfbbc..8ec7235fc93b 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4505,7 +4505,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type)) return NULL; *part = 0; - return get_disk(disks[drive]); + return get_disk_and_module(disks[drive]); } static int __init do_floppy_init(void) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index d5fe720cf149..87855b5123a6 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1922,7 +1922,7 @@ static struct kobject *loop_probe(dev_t dev, int *part, void *data) if (err < 0) kobj = NULL; else - kobj = get_disk(lo->lo_disk); + kobj = get_disk_and_module(lo->lo_disk); mutex_unlock(&loop_index_mutex); *part = 0; diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 84434d3ea19b..64e066eba72e 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -799,7 +799,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) return NULL; *part = 0; - return get_disk(swd->unit[drive].disk); + return get_disk_and_module(swd->unit[drive].disk); } static int swim_add_floppy(struct swim_priv *swd, enum drive_location location) diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 41c95c9b2ab4..8f9130ab5887 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -332,7 +332,7 @@ static const struct block_device_operations z2_fops = static struct kobject *z2_find(dev_t dev, int *part, void *data) { *part = 0; - return get_disk(z2ram_gendisk); + return get_disk_and_module(z2ram_gendisk); } static struct request_queue *z2_queue; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 17fd55af4d92..caa20eb5f26b 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -928,7 +928,7 @@ static int exact_lock(dev_t dev, void *data) { struct gendisk *p = data; - if (!get_disk(p)) + if (!get_disk_and_module(p)) return -1; return 0; } -- cgit v1.2.3 From 0c5661ecc5dd7ce296870a3eb7b62b1b280a5e89 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Fri, 23 Feb 2018 12:39:41 -0800 Subject: ixgbe: fix crash in build_skb Rx code path Add check for build_skb enabled ring in ixgbe_dma_sync_frag(). In that case &skb_shinfo(skb)->frags[0] may not always be set which can lead to a crash. Instead we derive the page offset from skb->data. Fixes: 42073d91a214 ("ixgbe: Have the CPU take ownership of the buffers sooner") CC: stable Reported-by: Ambarish Soman Suggested-by: Alexander Duyck Signed-off-by: Emil Tantilov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 0da5aa2c8aba..9fc063af233c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1888,6 +1888,14 @@ static void ixgbe_dma_sync_frag(struct ixgbe_ring *rx_ring, ixgbe_rx_pg_size(rx_ring), DMA_FROM_DEVICE, IXGBE_RX_DMA_ATTR); + } else if (ring_uses_build_skb(rx_ring)) { + unsigned long offset = (unsigned long)(skb->data) & ~PAGE_MASK; + + dma_sync_single_range_for_cpu(rx_ring->dev, + IXGBE_CB(skb)->dma, + offset, + skb_headlen(skb), + DMA_FROM_DEVICE); } else { struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0]; -- cgit v1.2.3 From f249be4d2c275fe2b98e389f471af75f758e5a59 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 24 Feb 2018 11:32:24 +0800 Subject: Revert "tuntap: add missing xdp flush" This reverts commit 762c330d670e3d4b795cf7a8d761866fdd1eef49. The reason is we try to batch packets for devmap which causes calling xdp_do_flush() in the process context. Simply disabling preemption may not work since process may move among processors which lead xdp_do_flush() to miss some flushes on some processors. So simply revert the patch, a follow-up patch will add the xdp flush correctly. Reported-by: Christoffer Dall Fixes: 762c330d670e ("tuntap: add missing xdp flush") Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index b52258c327d2..2823a4a6f059 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -181,7 +181,6 @@ struct tun_file { struct tun_struct *detached; struct ptr_ring tx_ring; struct xdp_rxq_info xdp_rxq; - int xdp_pending_pkts; }; struct tun_flow_entry { @@ -1662,7 +1661,6 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, case XDP_REDIRECT: get_page(alloc_frag->page); alloc_frag->offset += buflen; - ++tfile->xdp_pending_pkts; err = xdp_do_redirect(tun->dev, &xdp, xdp_prog); if (err) goto err_redirect; @@ -1984,11 +1982,6 @@ static ssize_t tun_chr_write_iter(struct kiocb *iocb, struct iov_iter *from) result = tun_get_user(tun, tfile, NULL, from, file->f_flags & O_NONBLOCK, false); - if (tfile->xdp_pending_pkts) { - tfile->xdp_pending_pkts = 0; - xdp_do_flush_map(); - } - tun_put(tun); return result; } @@ -2325,13 +2318,6 @@ static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) ret = tun_get_user(tun, tfile, m->msg_control, &m->msg_iter, m->msg_flags & MSG_DONTWAIT, m->msg_flags & MSG_MORE); - - if (tfile->xdp_pending_pkts >= NAPI_POLL_WEIGHT || - !(m->msg_flags & MSG_MORE)) { - tfile->xdp_pending_pkts = 0; - xdp_do_flush_map(); - } - tun_put(tun); return ret; } @@ -3163,7 +3149,6 @@ static int tun_chr_open(struct inode *inode, struct file * file) sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); memset(&tfile->tx_ring, 0, sizeof(tfile->tx_ring)); - tfile->xdp_pending_pkts = 0; return 0; } -- cgit v1.2.3 From 23e43f07f896f8578318cfcc9466f1e8b8ab21b6 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 24 Feb 2018 11:32:25 +0800 Subject: tuntap: disable preemption during XDP processing Except for tuntap, all other drivers' XDP was implemented at NAPI poll() routine in a bh. This guarantees all XDP operation were done at the same CPU which is required by e.g BFP_MAP_TYPE_PERCPU_ARRAY. But for tuntap, we do it in process context and we try to protect XDP processing by RCU reader lock. This is insufficient since CONFIG_PREEMPT_RCU can preempt the RCU reader critical section which breaks the assumption that all XDP were processed in the same CPU. Fixing this by simply disabling preemption during XDP processing. Fixes: 761876c857cb ("tap: XDP support") Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 2823a4a6f059..63d39fe67b99 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1642,6 +1642,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, else *skb_xdp = 0; + preempt_disable(); rcu_read_lock(); xdp_prog = rcu_dereference(tun->xdp_prog); if (xdp_prog && !*skb_xdp) { @@ -1665,6 +1666,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, if (err) goto err_redirect; rcu_read_unlock(); + preempt_enable(); return NULL; case XDP_TX: xdp_xmit = true; @@ -1686,6 +1688,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, skb = build_skb(buf, buflen); if (!skb) { rcu_read_unlock(); + preempt_enable(); return ERR_PTR(-ENOMEM); } @@ -1698,10 +1701,12 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, skb->dev = tun->dev; generic_xdp_tx(skb, xdp_prog); rcu_read_unlock(); + preempt_enable(); return NULL; } rcu_read_unlock(); + preempt_enable(); return skb; @@ -1709,6 +1714,7 @@ err_redirect: put_page(alloc_frag->page); err_xdp: rcu_read_unlock(); + preempt_enable(); this_cpu_inc(tun->pcpu_stats->rx_dropped); return NULL; } -- cgit v1.2.3 From 1bb4f2e868a2891ab8bc668b8173d6ccb8c4ce6f Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 24 Feb 2018 11:32:26 +0800 Subject: tuntap: correctly add the missing XDP flush We don't flush batched XDP packets through xdp_do_flush_map(), this will cause packets stall at TX queue. Consider we don't do XDP on NAPI poll(), the only possible fix is to call xdp_do_flush_map() immediately after xdp_do_redirect(). Note, this in fact won't try to batch packets through devmap, we could address in the future. Reported-by: Christoffer Dall Fixes: 761876c857cb ("tap: XDP support") Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 63d39fe67b99..7433bb2e4451 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1663,6 +1663,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, get_page(alloc_frag->page); alloc_frag->offset += buflen; err = xdp_do_redirect(tun->dev, &xdp, xdp_prog); + xdp_do_flush_map(); if (err) goto err_redirect; rcu_read_unlock(); -- cgit v1.2.3 From b6c3bad1ba83af1062a7ff6986d9edc4f3d7fc8e Mon Sep 17 00:00:00 2001 From: Denis Du Date: Sat, 24 Feb 2018 16:51:42 -0500 Subject: hdlc_ppp: carrier detect ok, don't turn off negotiation Sometimes when physical lines have a just good noise to make the protocol handshaking fail, but the carrier detect still good. Then after remove of the noise, nobody will trigger this protocol to be start again to cause the link to never come back. The fix is when the carrier is still on, not terminate the protocol handshaking. Signed-off-by: Denis Du Signed-off-by: David S. Miller --- drivers/net/wan/hdlc_ppp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index afeca6bcdade..ab8b3cbbb205 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -574,7 +574,10 @@ static void ppp_timer(struct timer_list *t) ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0, 0, NULL); proto->restart_counter--; - } else + } else if (netif_carrier_ok(proto->dev)) + ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0, + 0, NULL); + else ppp_cp_event(proto->dev, proto->pid, TO_BAD, 0, 0, 0, NULL); break; -- cgit v1.2.3 From 9d4949b4935831be10534d5432bf611285a572a5 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Mon, 26 Feb 2018 18:50:35 +0200 Subject: dax: ->direct_access does not sleep anymore In Patch: [7a862fb] brd: remove dax support Dan Williams has removed the only might_sleep implementation of ->direct_access. So we no longer need to check for it. CC: Dan Williams Signed-off-by: Boaz Harrosh Signed-off-by: Dan Williams --- drivers/dax/super.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 473af694ad1c..ecdc292aa4e4 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -246,12 +246,6 @@ long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages, { long avail; - /* - * The device driver is allowed to sleep, in order to make the - * memory directly accessible. - */ - might_sleep(); - if (!dax_dev) return -EOPNOTSUPP; -- cgit v1.2.3 From c37406e05d1e541df40b8b81c4bd40753fcaf414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 26 Feb 2018 14:51:13 -0600 Subject: PCI: Allow release of resources that were never assigned MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is entirely possible that the BIOS wasn't able to assign resources to a device. In this case don't crash in pci_release_resource() when we try to resize the resource. Fixes: 8bb705e3e79d ("PCI: Add pci_resize_resource() for resizing BARs") Signed-off-by: Christian König Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko CC: stable@vger.kernel.org # v4.15+ --- drivers/pci/setup-res.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 369d48d6c6f1..365447240d95 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -401,6 +401,10 @@ void pci_release_resource(struct pci_dev *dev, int resno) struct resource *res = dev->resource + resno; pci_info(dev, "BAR %d: releasing %pR\n", resno, res); + + if (!res->parent) + return; + release_resource(res); res->end = resource_size(res) - 1; res->start = 0; -- cgit v1.2.3 From 9326fdf3fbdfbc3c78de001969df8256913d98e7 Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Mon, 26 Feb 2018 13:11:03 +0000 Subject: cpufreq: scpi: invoke frequency-invariance setter function Commit 343a8d17fa8d (cpufreq: scpi: remove arm_big_little dependency) changed the cpufreq driver on juno from arm_big_little to scpi. The scpi set_target function does not call the frequency-invariance setter function arch_set_freq_scale() like the arm_big_little set_target function does. As a result the task scheduler load and utilization signals are not frequency-invariant on this platform anymore. Fix this by adding a call to arch_set_freq_scale() into scpi_cpufreq_set_target(). Fixes: 343a8d17fa8d (cpufreq: scpi: remove arm_big_little dependency) Signed-off-by: Dietmar Eggemann Acked-by: Sudeep Holla Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/scpi-cpufreq.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c index c32a833e1b00..d300a163945f 100644 --- a/drivers/cpufreq/scpi-cpufreq.c +++ b/drivers/cpufreq/scpi-cpufreq.c @@ -51,15 +51,23 @@ static unsigned int scpi_cpufreq_get_rate(unsigned int cpu) static int scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) { + unsigned long freq = policy->freq_table[index].frequency; struct scpi_data *priv = policy->driver_data; - u64 rate = policy->freq_table[index].frequency * 1000; + u64 rate = freq * 1000; int ret; ret = clk_set_rate(priv->clk, rate); - if (!ret && (clk_get_rate(priv->clk) != rate)) - ret = -EIO; - return ret; + if (ret) + return ret; + + if (clk_get_rate(priv->clk) != rate) + return -EIO; + + arch_set_freq_scale(policy->related_cpus, freq, + policy->cpuinfo.max_freq); + + return 0; } static int -- cgit v1.2.3 From 5c8b2623f6b425d48bdd5a66d7f7dc666b219613 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Fri, 23 Feb 2018 15:54:42 +0000 Subject: cpufreq: scpi: Fix incorrect arm_big_little config dependency Commit 343a8d17fa8d (cpufreq: scpi: remove arm_big_little dependency) removed the SCPI cpufreq dependency on arm_big_little cpufreq driver. However the Kconfig entry still depends on ARM_BIG_LITTLE_CPUFREQ which is clearly wrong. This patch removes that unnecessary Kconfig dependency. Fixes: 343a8d17fa8d (cpufreq: scpi: remove arm_big_little dependency) Reported-by: Quentin Perret Acked-by: Viresh Kumar Signed-off-by: Sudeep Holla Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/Kconfig.arm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 3a88e33b0cfe..fb586e09682d 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -44,10 +44,10 @@ config ARM_DT_BL_CPUFREQ config ARM_SCPI_CPUFREQ tristate "SCPI based CPUfreq driver" - depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI + depends on ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI help - This adds the CPUfreq driver support for ARM big.LITTLE platforms - using SCPI protocol for CPU power management. + This adds the CPUfreq driver support for ARM platforms using SCPI + protocol for CPU power management. This driver uses SCPI Message Protocol driver to interact with the firmware providing the CPU DVFS functionality. -- cgit v1.2.3 From 6bb320ca4a4a7b5b3db8c8d7250cc40002046878 Mon Sep 17 00:00:00 2001 From: Jeremy Boone Date: Thu, 8 Feb 2018 12:32:06 -0800 Subject: tpm_tis: fix potential buffer overruns caused by bit glitches on the bus Discrete TPMs are often connected over slow serial buses which, on some platforms, can have glitches causing bit flips. In all the driver _recv() functions, we need to use a u32 to unmarshal the response size, otherwise a bit flip of the 31st bit would cause the expected variable to go negative, which would then try to read a huge amount of data. Also sanity check that the expected amount of data is large enough for the TPM header. Signed-off-by: Jeremy Boone Cc: stable@vger.kernel.org Signed-off-by: James Bottomley Tested-by: Jarkko Sakkinen Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm_tis_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 183a5f54d875..da074e3db19b 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -270,7 +270,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) { struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); int size = 0; - int expected, status; + int status; + u32 expected; if (count < TPM_HEADER_SIZE) { size = -EIO; @@ -285,7 +286,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) } expected = be32_to_cpu(*(__be32 *) (buf + 2)); - if (expected > count) { + if (expected > count || expected < TPM_HEADER_SIZE) { size = -EIO; goto out; } -- cgit v1.2.3 From f9d4d9b5a5ef2f017bc344fb65a58a902517173b Mon Sep 17 00:00:00 2001 From: Jeremy Boone Date: Thu, 8 Feb 2018 12:31:16 -0800 Subject: tpm_i2c_nuvoton: fix potential buffer overruns caused by bit glitches on the bus Discrete TPMs are often connected over slow serial buses which, on some platforms, can have glitches causing bit flips. In all the driver _recv() functions, we need to use a u32 to unmarshal the response size, otherwise a bit flip of the 31st bit would cause the expected variable to go negative, which would then try to read a huge amount of data. Also sanity check that the expected amount of data is large enough for the TPM header. Signed-off-by: Jeremy Boone Cc: stable@vger.kernel.org Signed-off-by: James Bottomley Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm_i2c_nuvoton.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index c6428771841f..caa86b19c76d 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -281,7 +281,11 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) struct device *dev = chip->dev.parent; struct i2c_client *client = to_i2c_client(dev); s32 rc; - int expected, status, burst_count, retries, size = 0; + int status; + int burst_count; + int retries; + int size = 0; + u32 expected; if (count < TPM_HEADER_SIZE) { i2c_nuvoton_ready(chip); /* return to idle */ @@ -323,7 +327,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) * to machine native */ expected = be32_to_cpu(*(__be32 *) (buf + 2)); - if (expected > count) { + if (expected > count || expected < size) { dev_err(dev, "%s() expected > count\n", __func__); size = -EIO; continue; -- cgit v1.2.3 From 9b8cb28d7c62568a5916bdd7ea1c9176d7f8f2ed Mon Sep 17 00:00:00 2001 From: Jeremy Boone Date: Thu, 8 Feb 2018 12:30:01 -0800 Subject: tpm_i2c_infineon: fix potential buffer overruns caused by bit glitches on the bus Discrete TPMs are often connected over slow serial buses which, on some platforms, can have glitches causing bit flips. In all the driver _recv() functions, we need to use a u32 to unmarshal the response size, otherwise a bit flip of the 31st bit would cause the expected variable to go negative, which would then try to read a huge amount of data. Also sanity check that the expected amount of data is large enough for the TPM header. Signed-off-by: Jeremy Boone Cc: stable@vger.kernel.org Signed-off-by: James Bottomley Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm_i2c_infineon.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index c1dd39eaaeeb..6116cd05e228 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -473,7 +473,8 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) { int size = 0; - int expected, status; + int status; + u32 expected; if (count < TPM_HEADER_SIZE) { size = -EIO; @@ -488,7 +489,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) } expected = be32_to_cpu(*(__be32 *)(buf + 2)); - if ((size_t) expected > count) { + if (((size_t) expected > count) || (expected < TPM_HEADER_SIZE)) { size = -EIO; goto out; } -- cgit v1.2.3 From 6d24cd186d9fead3722108dec1b1c993354645ff Mon Sep 17 00:00:00 2001 From: Jeremy Boone Date: Thu, 8 Feb 2018 12:29:09 -0800 Subject: tpm: st33zp24: fix potential buffer overruns caused by bit glitches on the bus Discrete TPMs are often connected over slow serial buses which, on some platforms, can have glitches causing bit flips. In all the driver _recv() functions, we need to use a u32 to unmarshal the response size, otherwise a bit flip of the 31st bit would cause the expected variable to go negative, which would then try to read a huge amount of data. Also sanity check that the expected amount of data is large enough for the TPM header. Signed-off-by: Jeremy Boone Cc: stable@vger.kernel.org Signed-off-by: James Bottomley Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/st33zp24/st33zp24.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index 4d1dc8b46877..f95b9c75175b 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -457,7 +457,7 @@ static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf, size_t count) { int size = 0; - int expected; + u32 expected; if (!chip) return -EBUSY; @@ -474,7 +474,7 @@ static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf, } expected = be32_to_cpu(*(__be32 *)(buf + 2)); - if (expected > count) { + if (expected > count || expected < TPM_HEADER_SIZE) { size = -EIO; goto out; } -- cgit v1.2.3 From 3be23274755ee85771270a23af7691dc9b3a95db Mon Sep 17 00:00:00 2001 From: Jeremy Boone Date: Thu, 8 Feb 2018 12:28:08 -0800 Subject: tpm: fix potential buffer overruns caused by bit glitches on the bus Discrete TPMs are often connected over slow serial buses which, on some platforms, can have glitches causing bit flips. If a bit does flip it could cause an overrun if it's in one of the size parameters, so sanity check that we're not overrunning the provided buffer when doing a memcpy(). Signed-off-by: Jeremy Boone Cc: stable@vger.kernel.org Signed-off-by: James Bottomley Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm-interface.c | 4 ++++ drivers/char/tpm/tpm2-cmd.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 76df4fbcf089..9e80a953d693 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -1190,6 +1190,10 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) break; recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); + if (recd > num_bytes) { + total = -EFAULT; + break; + } rlength = be32_to_cpu(tpm_cmd.header.out.length); if (rlength < offsetof(struct tpm_getrandom_out, rng_data) + diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index c17e75348a99..a700f8f9ead7 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -683,6 +683,10 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, if (!rc) { data_len = be16_to_cpup( (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); + if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE + 1) { + rc = -EFAULT; + goto out; + } rlength = be32_to_cpu(((struct tpm2_cmd *)&buf) ->header.out.length); -- cgit v1.2.3 From 4c27bf3c5b7434ccb9ab962301da661c26b467a4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 25 Feb 2018 19:12:10 -0800 Subject: r8152: fix tx packets accounting r8152 driver handles TSO packets (limited to ~16KB) quite well, but pretends each TSO logical packet is a single packet on the wire. There is also some error since headers are accounted once, but error rate is small enough that we do not care. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 958b2e8b90f6..86f7196f9d91 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1794,7 +1794,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) tx_data += len; agg->skb_len += len; - agg->skb_num++; + agg->skb_num += skb_shinfo(skb)->gso_segs ?: 1; dev_kfree_skb_any(skb); -- cgit v1.2.3 From ec92937056db2ca3acb11929d68b95b6ab421653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 1 Feb 2018 14:52:50 +0100 Subject: drm/ttm: set page mapping during allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To aid debugging set the page mapping during allocation instead of during VM faults. Signed-off-by: Christian König Reviewed-by: Roger He Signed-off-by: Alex Deucher --- drivers/gpu/drm/ttm/ttm_bo_vm.c | 1 - drivers/gpu/drm/ttm/ttm_tt.c | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 610d6714042a..121f017ac7ca 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -257,7 +257,6 @@ static int ttm_bo_vm_fault(struct vm_fault *vmf) } else if (unlikely(!page)) { break; } - page->mapping = vma->vm_file->f_mapping; page->index = drm_vma_node_start(&bo->vma_node) + page_offset; pfn = page_to_pfn(page); diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 39c44e301c72..9fd7115a013a 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -392,12 +392,28 @@ out_err: return ret; } +static void ttm_tt_add_mapping(struct ttm_tt *ttm) +{ + pgoff_t i; + + if (ttm->page_flags & TTM_PAGE_FLAG_SG) + return; + + for (i = 0; i < ttm->num_pages; ++i) + ttm->pages[i]->mapping = ttm->bdev->dev_mapping; +} + int ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx) { + int ret; + if (ttm->state != tt_unpopulated) return 0; - return ttm->bdev->driver->ttm_tt_populate(ttm, ctx); + ret = ttm->bdev->driver->ttm_tt_populate(ttm, ctx); + if (!ret) + ttm_tt_add_mapping(ttm); + return ret; } static void ttm_tt_clear_mapping(struct ttm_tt *ttm) -- cgit v1.2.3 From c02216acf4177c4411d33735c81cad687790fa59 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Feb 2018 16:26:57 +0100 Subject: radeon: hide pointless #warning when compile testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In randconfig testing, we sometimes get this warning: drivers/gpu/drm/radeon/radeon_object.c: In function 'radeon_bo_create': drivers/gpu/drm/radeon/radeon_object.c:242:2: error: #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance thanks to write-combining [-Werror=cpp] #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \ This is rather annoying since almost all other code produces no build-time output unless we have found a real bug. We already fixed this in the amdgpu driver in commit 31bb90f1cd08 ("drm/amdgpu: shut up #warning for compile testing") by adding a CONFIG_COMPILE_TEST check last year and agreed to do the same here, but both Michel and I then forgot about it until I came across the issue again now. For stable kernels, as this is one of very few remaining randconfig warnings in 4.14. Cc: stable@vger.kernel.org Link: https://patchwork.kernel.org/patch/9550009/ Signed-off-by: Arnd Bergmann Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index c38fea37a67d..64ab11d4ea58 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -234,9 +234,10 @@ int radeon_bo_create(struct radeon_device *rdev, * may be slow * See https://bugs.freedesktop.org/show_bug.cgi?id=88758 */ - +#ifndef CONFIG_COMPILE_TEST #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \ thanks to write-combining +#endif if (bo->flags & RADEON_GEM_GTT_WC) DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for " -- cgit v1.2.3 From d330fca11500bebaf7f25b60b7b087bbe8ad0b7f Mon Sep 17 00:00:00 2001 From: Roger He Date: Tue, 6 Feb 2018 11:22:57 +0800 Subject: drm/ttm: use bit flag to replace allow_reserved_eviction in ttm_operation_ctx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for saving memory and more bit flag can be used in future Signed-off-by: Roger He Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 4 ++-- drivers/gpu/drm/ttm/ttm_bo.c | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index eaa3cb0c3ad1..dc34b50e6b29 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -346,8 +346,8 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p, struct ttm_operation_ctx ctx = { .interruptible = true, .no_wait_gpu = false, - .allow_reserved_eviction = false, - .resv = bo->tbo.resv + .resv = bo->tbo.resv, + .flags = 0 }; uint32_t domain; int r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 969de54b62da..c2a4b7215c46 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -341,8 +341,8 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, struct ttm_operation_ctx ctx = { .interruptible = !kernel, .no_wait_gpu = false, - .allow_reserved_eviction = true, - .resv = resv + .resv = resv, + .flags = TTM_OPT_FLAG_ALLOW_RES_EVICT }; struct amdgpu_bo *bo; enum ttm_bo_type type; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index d90b1cf10b27..a907311afe1a 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -730,7 +730,8 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo, *locked = false; if (bo->resv == ctx->resv) { reservation_object_assert_held(bo->resv); - if (ctx->allow_reserved_eviction || !list_empty(&bo->ddestroy)) + if (ctx->flags & TTM_OPT_FLAG_ALLOW_RES_EVICT + || !list_empty(&bo->ddestroy)) ret = true; } else { *locked = reservation_object_trylock(bo->resv); -- cgit v1.2.3 From aa7662b67bf6f56cd0d678da6732e26f1b4bf0ed Mon Sep 17 00:00:00 2001 From: Roger He Date: Wed, 17 Jan 2018 15:07:23 +0800 Subject: drm/ttm: add bit flag TTM_OPT_FLAG_FORCE_ALLOC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit set TTM_OPT_FLAG_FORCE_ALLOC when we are servicing for page fault routine. for ttm_mem_global_reserve if in page fault routine, allow the gtt pages reservation always. because page fault routing already grabbed system memory and the allowance of this exception is harmless. Otherwise, it will trigger OOM killer. will be used later. v2: set the FORCE_ALLOC always v3: minor refine Signed-off-by: Roger He Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/ttm/ttm_bo_vm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 121f017ac7ca..8eba95b3c737 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -226,7 +226,9 @@ static int ttm_bo_vm_fault(struct vm_fault *vmf) } else { struct ttm_operation_ctx ctx = { .interruptible = false, - .no_wait_gpu = false + .no_wait_gpu = false, + .flags = TTM_OPT_FLAG_FORCE_ALLOC + }; ttm = bo->ttm; -- cgit v1.2.3 From 40d5250dbb468ecf1d4a1aa5f5597358e33de95c Mon Sep 17 00:00:00 2001 From: Roger He Date: Tue, 6 Feb 2018 15:00:06 +0800 Subject: drm/ttm: set TTM_OPT_FLAG_FORCE_ALLOC in ttm_bo_force_list_clean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because ttm_bo_force_list_clean() is only called on two occasions: 1. By ttm_bo_evict_mm() during suspend. 2. By ttm_bo_clean_mm() when the driver unloads. On both cases we absolutely don't want any memory allocation failure. Signed-off-by: Roger He Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/ttm/ttm_bo.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index a907311afe1a..2bde37291e3e 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1344,7 +1344,11 @@ EXPORT_SYMBOL(ttm_bo_create); static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev, unsigned mem_type) { - struct ttm_operation_ctx ctx = { false, false }; + struct ttm_operation_ctx ctx = { + .interruptible = false, + .no_wait_gpu = false, + .flags = TTM_OPT_FLAG_FORCE_ALLOC + }; struct ttm_mem_type_manager *man = &bdev->man[mem_type]; struct ttm_bo_global *glob = bdev->glob; struct dma_fence *fence; -- cgit v1.2.3 From 952e5daa2565fc842d90192d2254f3bc1a88920c Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Sun, 11 Feb 2018 12:38:58 +0800 Subject: drm/amd/pp: Fix error handling when smu return failed on Vega10. Clamp the clock index to a valid range when reading it back Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 26 ++++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 1d442a498bf6..4c53dabb102f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -3912,28 +3912,30 @@ static int vega10_read_sensor(struct pp_hwmgr *hwmgr, int idx, switch (idx) { case AMDGPU_PP_SENSOR_GFX_SCLK: - ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentGfxclkIndex); - if (!ret) { - vega10_read_arg_from_smc(hwmgr, &sclk_idx); + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentGfxclkIndex); + vega10_read_arg_from_smc(hwmgr, &sclk_idx); + if (sclk_idx < dpm_table->gfx_table.count) { *((uint32_t *)value) = dpm_table->gfx_table.dpm_levels[sclk_idx].value; *size = 4; + } else { + ret = -EINVAL; } break; case AMDGPU_PP_SENSOR_GFX_MCLK: - ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentUclkIndex); - if (!ret) { - vega10_read_arg_from_smc(hwmgr, &mclk_idx); + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentUclkIndex); + vega10_read_arg_from_smc(hwmgr, &mclk_idx); + if (mclk_idx < dpm_table->mem_table.count) { *((uint32_t *)value) = dpm_table->mem_table.dpm_levels[mclk_idx].value; *size = 4; + } else { + ret = -EINVAL; } break; case AMDGPU_PP_SENSOR_GPU_LOAD: - ret = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetAverageGfxActivity, 0); - if (!ret) { - vega10_read_arg_from_smc(hwmgr, &activity_percent); - *((uint32_t *)value) = activity_percent > 100 ? 100 : activity_percent; - *size = 4; - } + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetAverageGfxActivity, 0); + vega10_read_arg_from_smc(hwmgr, &activity_percent); + *((uint32_t *)value) = activity_percent > 100 ? 100 : activity_percent; + *size = 4; break; case AMDGPU_PP_SENSOR_GPU_TEMP: *((uint32_t *)value) = vega10_thermal_get_temperature(hwmgr); -- cgit v1.2.3 From a02497b73218f10f237d98fb10d34d0baed607a0 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Fri, 9 Feb 2018 16:47:53 +0800 Subject: drm/amd/pp: Fix bug that dpm level was not really locked Lock the dpm levels when we use SW method to modify the dpm tables directly to avoid a possible race with the smu. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 0202841ae639..1d988ef1978e 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -4650,20 +4650,26 @@ static int smu7_set_power_profile_state(struct pp_hwmgr *hwmgr, if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_AUTO) return -EINVAL; - tmp_result = smu7_freeze_sclk_mclk_dpm(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to freeze SCLK MCLK DPM!", - result = tmp_result); + if (smum_is_dpm_running(hwmgr)) { + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel); + + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel); + } tmp_result = smum_populate_requested_graphic_levels(hwmgr, request); PP_ASSERT_WITH_CODE(!tmp_result, "Failed to populate requested graphic levels!", result = tmp_result); - tmp_result = smu7_unfreeze_sclk_mclk_dpm(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to unfreeze SCLK MCLK DPM!", - result = tmp_result); + if (smum_is_dpm_running(hwmgr)) { + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel); + + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel); + } smu7_find_min_clock_masks(hwmgr, &sclk_mask, &mclk_mask, request->min_sclk, request->min_mclk); -- cgit v1.2.3 From 92e71b0676447fff40c1e747b2585a9d11c5fca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 08:35:11 +0100 Subject: drm/amdgpu: use the TTM dummy page instead of allocating one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have a global dummy page in TTM, use that one instead of allocating a new one. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 10 +--------- drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c | 29 +++++++++++++---------------- drivers/gpu/drm/amd/amdgpu/cik_ih.c | 2 +- drivers/gpu/drm/amd/amdgpu/cz_ih.c | 2 +- drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/iceland_ih.c | 2 +- drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c | 2 +- drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c | 2 +- drivers/gpu/drm/amd/amdgpu/tonga_ih.c | 2 +- 13 files changed, 30 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 1ac81be374dd..3e6f27d363e9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -343,14 +343,6 @@ struct amdgpu_ih_funcs { bool amdgpu_get_bios(struct amdgpu_device *adev); bool amdgpu_read_bios(struct amdgpu_device *adev); -/* - * Dummy page - */ -struct amdgpu_dummy_page { - struct page *page; - dma_addr_t addr; -}; - /* * Clocks */ @@ -1505,7 +1497,7 @@ struct amdgpu_device { /* MC */ struct amdgpu_gmc gmc; struct amdgpu_gart gart; - struct amdgpu_dummy_page dummy_page; + dma_addr_t dummy_page_addr; struct amdgpu_vm_manager vm_manager; struct amdgpu_vmhub vmhub[AMDGPU_MAX_VMHUBS]; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index 008eaee57114..137145dd14a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -68,17 +68,15 @@ */ static int amdgpu_gart_dummy_page_init(struct amdgpu_device *adev) { - if (adev->dummy_page.page) + struct page *dummy_page = adev->mman.bdev.glob->dummy_read_page; + + if (adev->dummy_page_addr) return 0; - adev->dummy_page.page = alloc_page(GFP_DMA32 | GFP_KERNEL | __GFP_ZERO); - if (adev->dummy_page.page == NULL) - return -ENOMEM; - adev->dummy_page.addr = pci_map_page(adev->pdev, adev->dummy_page.page, - 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(adev->pdev, adev->dummy_page.addr)) { + adev->dummy_page_addr = pci_map_page(adev->pdev, dummy_page, 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(adev->pdev, adev->dummy_page_addr)) { dev_err(&adev->pdev->dev, "Failed to DMA MAP the dummy page\n"); - __free_page(adev->dummy_page.page); - adev->dummy_page.page = NULL; + adev->dummy_page_addr = 0; return -ENOMEM; } return 0; @@ -93,12 +91,11 @@ static int amdgpu_gart_dummy_page_init(struct amdgpu_device *adev) */ static void amdgpu_gart_dummy_page_fini(struct amdgpu_device *adev) { - if (adev->dummy_page.page == NULL) + if (!adev->dummy_page_addr) return; - pci_unmap_page(adev->pdev, adev->dummy_page.addr, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - __free_page(adev->dummy_page.page); - adev->dummy_page.page = NULL; + pci_unmap_page(adev->pdev, adev->dummy_page_addr, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + adev->dummy_page_addr = 0; } /** @@ -236,7 +233,7 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset, #ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS adev->gart.pages[p] = NULL; #endif - page_base = adev->dummy_page.addr; + page_base = adev->dummy_page_addr; if (!adev->gart.ptr) continue; @@ -347,7 +344,7 @@ int amdgpu_gart_init(struct amdgpu_device *adev) { int r; - if (adev->dummy_page.page) + if (adev->dummy_page_addr) return 0; /* We need PAGE_SIZE >= AMDGPU_GPU_PAGE_SIZE */ diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.c b/drivers/gpu/drm/amd/amdgpu/cik_ih.c index 07c7852180d0..44d10c2172f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.c @@ -111,7 +111,7 @@ static int cik_ih_irq_init(struct amdgpu_device *adev) cik_ih_disable_interrupts(adev); /* setup interrupt control */ - WREG32(mmINTERRUPT_CNTL2, adev->dummy_page.addr >> 8); + WREG32(mmINTERRUPT_CNTL2, adev->dummy_page_addr >> 8); interrupt_cntl = RREG32(mmINTERRUPT_CNTL); /* INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi * INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.c b/drivers/gpu/drm/amd/amdgpu/cz_ih.c index cfd0ad03c938..960c29e17da6 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.c @@ -111,7 +111,7 @@ static int cz_ih_irq_init(struct amdgpu_device *adev) cz_ih_disable_interrupts(adev); /* setup interrupt control */ - WREG32(mmINTERRUPT_CNTL2, adev->dummy_page.addr >> 8); + WREG32(mmINTERRUPT_CNTL2, adev->dummy_page_addr >> 8); interrupt_cntl = RREG32(mmINTERRUPT_CNTL); /* INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi * INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c index 94a07bcbbdda..acfbd2d749cf 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c @@ -92,9 +92,9 @@ static void gfxhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) /* Program "protection fault". */ WREG32_SOC15(GC, 0, mmVM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, - (u32)(adev->dummy_page.addr >> 12)); + (u32)(adev->dummy_page_addr >> 12)); WREG32_SOC15(GC, 0, mmVM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32, - (u32)((u64)adev->dummy_page.addr >> 44)); + (u32)((u64)adev->dummy_page_addr >> 44)); WREG32_FIELD15(GC, 0, VM_L2_PROTECTION_FAULT_CNTL2, ACTIVE_PAGE_MIGRATION_PTE_READ_RETRY, 1); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index 2c0ed9dd0c91..5617cf62c566 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -533,7 +533,7 @@ static int gmc_v6_0_gart_enable(struct amdgpu_device *adev) WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->gmc.gart_end >> 12); WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12); WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, - (u32)(adev->dummy_page.addr >> 12)); + (u32)(adev->dummy_page_addr >> 12)); WREG32(mmVM_CONTEXT0_CNTL2, 0); WREG32(mmVM_CONTEXT0_CNTL, VM_CONTEXT0_CNTL__ENABLE_CONTEXT_MASK | @@ -563,7 +563,7 @@ static int gmc_v6_0_gart_enable(struct amdgpu_device *adev) /* enable context1-15 */ WREG32(mmVM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR, - (u32)(adev->dummy_page.addr >> 12)); + (u32)(adev->dummy_page_addr >> 12)); WREG32(mmVM_CONTEXT1_CNTL2, 4); WREG32(mmVM_CONTEXT1_CNTL, VM_CONTEXT1_CNTL__ENABLE_CONTEXT_MASK | diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 4edd17059868..80054f36e487 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -644,7 +644,7 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev) WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->gmc.gart_end >> 12); WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12); WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, - (u32)(adev->dummy_page.addr >> 12)); + (u32)(adev->dummy_page_addr >> 12)); WREG32(mmVM_CONTEXT0_CNTL2, 0); tmp = RREG32(mmVM_CONTEXT0_CNTL); tmp = REG_SET_FIELD(tmp, VM_CONTEXT0_CNTL, ENABLE_CONTEXT, 1); @@ -674,7 +674,7 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev) /* enable context1-15 */ WREG32(mmVM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR, - (u32)(adev->dummy_page.addr >> 12)); + (u32)(adev->dummy_page_addr >> 12)); WREG32(mmVM_CONTEXT1_CNTL2, 4); tmp = RREG32(mmVM_CONTEXT1_CNTL); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, ENABLE_CONTEXT, 1); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 1e0ad0657e96..724bf1c2596e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -860,7 +860,7 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev) WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->gmc.gart_end >> 12); WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12); WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, - (u32)(adev->dummy_page.addr >> 12)); + (u32)(adev->dummy_page_addr >> 12)); WREG32(mmVM_CONTEXT0_CNTL2, 0); tmp = RREG32(mmVM_CONTEXT0_CNTL); tmp = REG_SET_FIELD(tmp, VM_CONTEXT0_CNTL, ENABLE_CONTEXT, 1); @@ -890,7 +890,7 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev) /* enable context1-15 */ WREG32(mmVM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR, - (u32)(adev->dummy_page.addr >> 12)); + (u32)(adev->dummy_page_addr >> 12)); WREG32(mmVM_CONTEXT1_CNTL2, 4); tmp = RREG32(mmVM_CONTEXT1_CNTL); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, ENABLE_CONTEXT, 1); diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c index 3237a576692d..842c4b677b4d 100644 --- a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c @@ -111,7 +111,7 @@ static int iceland_ih_irq_init(struct amdgpu_device *adev) iceland_ih_disable_interrupts(adev); /* setup interrupt control */ - WREG32(mmINTERRUPT_CNTL2, adev->dummy_page.addr >> 8); + WREG32(mmINTERRUPT_CNTL2, adev->dummy_page_addr >> 8); interrupt_cntl = RREG32(mmINTERRUPT_CNTL); /* INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi * INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c index d0ade9fd9fa9..3dd5816495a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c @@ -103,9 +103,9 @@ static void mmhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) /* Program "protection fault". */ WREG32_SOC15(MMHUB, 0, mmVM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, - (u32)(adev->dummy_page.addr >> 12)); + (u32)(adev->dummy_page_addr >> 12)); WREG32_SOC15(MMHUB, 0, mmVM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32, - (u32)((u64)adev->dummy_page.addr >> 44)); + (u32)((u64)adev->dummy_page_addr >> 44)); tmp = RREG32_SOC15(MMHUB, 0, mmVM_L2_PROTECTION_FAULT_CNTL2); tmp = REG_SET_FIELD(tmp, VM_L2_PROTECTION_FAULT_CNTL2, diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c b/drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c index 2daeef6e9345..1cf34248dff4 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c @@ -133,7 +133,7 @@ static void nbio_v6_1_ih_control(struct amdgpu_device *adev) u32 interrupt_cntl; /* setup interrupt control */ - WREG32_SOC15(NBIO, 0, mmINTERRUPT_CNTL2, adev->dummy_page.addr >> 8); + WREG32_SOC15(NBIO, 0, mmINTERRUPT_CNTL2, adev->dummy_page_addr >> 8); interrupt_cntl = RREG32_SOC15(NBIO, 0, mmINTERRUPT_CNTL); /* INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi * INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c index cd10c76a76e2..df34dc79d444 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c @@ -208,7 +208,7 @@ static void nbio_v7_0_ih_control(struct amdgpu_device *adev) u32 interrupt_cntl; /* setup interrupt control */ - WREG32_SOC15(NBIO, 0, mmINTERRUPT_CNTL2, adev->dummy_page.addr >> 8); + WREG32_SOC15(NBIO, 0, mmINTERRUPT_CNTL2, adev->dummy_page_addr >> 8); interrupt_cntl = RREG32_SOC15(NBIO, 0, mmINTERRUPT_CNTL); /* INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi * INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c index 18435389bae4..52853d8a8fdd 100644 --- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c @@ -107,7 +107,7 @@ static int tonga_ih_irq_init(struct amdgpu_device *adev) tonga_ih_disable_interrupts(adev); /* setup interrupt control */ - WREG32(mmINTERRUPT_CNTL2, adev->dummy_page.addr >> 8); + WREG32(mmINTERRUPT_CNTL2, adev->dummy_page_addr >> 8); interrupt_cntl = RREG32(mmINTERRUPT_CNTL); /* INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi * INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN -- cgit v1.2.3 From eda9a4eb15e89e4d452ae8dbdc7fd6868c79c605 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Thu, 8 Feb 2018 15:57:10 +0800 Subject: drm/amdgpu: Add query vram width in CGS query system info powerplay need vram width to set default mclk optimization settings(uphyst/downhyst/activity threshold) Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c | 3 +++ drivers/gpu/drm/amd/include/cgs_common.h | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index dc3360b16bda..72c9a7e2c373 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -905,6 +905,9 @@ static int amdgpu_cgs_query_system_info(struct cgs_device *cgs_device, case CGS_SYSTEM_INFO_PCIE_BUS_DEVFN: sys_info->value = adev->pdev->devfn; break; + case CGS_SYSTEM_INFO_VRAM_WIDTH: + sys_info->value = adev->gmc.vram_width; + break; default: return -ENODEV; } diff --git a/drivers/gpu/drm/amd/include/cgs_common.h b/drivers/gpu/drm/amd/include/cgs_common.h index f5c73970ab88..98cf4cebff17 100644 --- a/drivers/gpu/drm/amd/include/cgs_common.h +++ b/drivers/gpu/drm/amd/include/cgs_common.h @@ -101,6 +101,7 @@ enum cgs_system_info_id { CGS_SYSTEM_INFO_PCIE_SUB_SYS_ID, CGS_SYSTEM_INFO_PCIE_SUB_SYS_VENDOR_ID, CGS_SYSTEM_INFO_PCIE_BUS_DEVFN, + CGS_SYSTEM_INFO_VRAM_WIDTH, CGS_SYSTEM_INFO_ID_MAXIMUM, }; -- cgit v1.2.3 From 472c89fcd5c2505c7d5d785ea3a78b2e71ff8723 Mon Sep 17 00:00:00 2001 From: Eric Huang Date: Thu, 22 Feb 2018 12:00:35 -0500 Subject: drm/amd/powerplay: fix thermal interrupts on vega10 a bug in programming thermal interrupt register masks out interrupts and driver cannot receive interrupts. Setting 0 to mask bits will fix it. Signed-off-by: Eric Huang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c index 749116329c36..eb6e965ea5d7 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c @@ -409,7 +409,9 @@ static int vega10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1); val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES)); - val = val & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK); + val &= (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK) & + (~THM_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK) & + (~THM_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK); cgs_write_register(hwmgr->device, reg, val); -- cgit v1.2.3 From 3d2fc0813f91a908f5c61ac0d08d89f802030d03 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Thu, 22 Feb 2018 17:39:22 +0800 Subject: drm/amdgpu: Change default value of module parameter amdgpu_pp_feature_mask Currently all pp features are enabled by default except OVERDRIVE Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 88ec9280a67a..85ceed702fb2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -121,7 +121,7 @@ uint amdgpu_pg_mask = 0xffffffff; uint amdgpu_sdma_phase_quantum = 32; char *amdgpu_disable_cu = NULL; char *amdgpu_virtual_display = NULL; -uint amdgpu_pp_feature_mask = 0x3fff; +uint amdgpu_pp_feature_mask = 0xffffbfff; int amdgpu_ngg = 0; int amdgpu_prim_buf_per_se = 0; int amdgpu_pos_buf_per_se = 0; -- cgit v1.2.3 From 3214e02199f0c1c5db6de2fa3eb8240e08f4e17d Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Thu, 22 Feb 2018 17:45:11 +0800 Subject: drm/amd/pp: Add a pp feature mask bit for AutoWattman feature Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 2a59ee8f4acb..77d7f49564c4 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -85,6 +85,7 @@ enum PP_FEATURE_MASK { PP_SOCCLK_DPM_MASK = 0x1000, PP_DCEFCLK_DPM_MASK = 0x2000, PP_OVERDRIVE_MASK = 0x4000, + PP_AUTOWATTMAN_MASK = 0x8000, }; enum PHM_BackEnd_Magic { -- cgit v1.2.3 From 421334a8476fe53b147139e1221cf7b368dd7c6e Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 20 Feb 2018 11:44:50 +0100 Subject: drm/amdgpu: Remove duplicate setting of ->need_swiotlb There's no need to set this before the number of DMA bits has been properly determined. Signed-off-by: Thierry Reding Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 724bf1c2596e..d71d4cb68f9c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -1105,7 +1105,6 @@ static int gmc_v8_0_sw_init(void *handle) */ adev->need_dma32 = false; dma_bits = adev->need_dma32 ? 32 : 40; - adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits); r = pci_set_dma_mask(adev->pdev, DMA_BIT_MASK(dma_bits)); if (r) { adev->need_dma32 = true; -- cgit v1.2.3 From bcb0b981c5571744ac446a6c906aa05a28d21446 Mon Sep 17 00:00:00 2001 From: Ben Crocker Date: Thu, 22 Feb 2018 17:52:19 -0500 Subject: drm/radeon: insist on 32-bit DMA for Cedar on PPC64/PPC64LE In radeon_device_init, set the need_dma32 flag for Cedar chips (e.g. FirePro 2270). This fixes, or at least works around, a bug on PowerPC exposed by last year's commits 8e3f1b1d8255105f31556aacf8aeb6071b00d469 (Russell Currey) and 253fd51e2f533552ae35a0c661705da6c4842c1b (Alistair Popple) which enabled the 64-bit DMA iommu bypass. This caused the device to freeze, in some cases unrecoverably, and is the subject of several bug reports internal to Red Hat. Signed-off-by: Ben Crocker Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_device.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 7f40c6f7c4dd..e415d2c097a7 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1366,6 +1366,10 @@ int radeon_device_init(struct radeon_device *rdev, if ((rdev->flags & RADEON_IS_PCI) && (rdev->family <= CHIP_RS740)) rdev->need_dma32 = true; +#ifdef CONFIG_PPC64 + if (rdev->family == CHIP_CEDAR) + rdev->need_dma32 = true; +#endif dma_bits = rdev->need_dma32 ? 32 : 40; r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits)); -- cgit v1.2.3 From fbb31562186e26ba2d930141286332ef94104cd2 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 22 Feb 2018 08:21:48 +0000 Subject: drm/amd: remove inclusion of non-existing scheduler directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The scheduler directory was removed via commit 1b1f42d8fde4 ("drm: move amd_gpu_scheduler into common location") Remove it from include path. Reviewed-by: Christian König Signed-off-by: Corentin Labbe Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/Makefile | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index be5e5acc3e39..353c937d947d 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -30,7 +30,6 @@ FULL_AMD_DISPLAY_PATH = $(FULL_AMD_PATH)/$(DISPLAY_FOLDER_NAME) ccflags-y := -I$(FULL_AMD_PATH)/include/asic_reg \ -I$(FULL_AMD_PATH)/include \ -I$(FULL_AMD_PATH)/amdgpu \ - -I$(FULL_AMD_PATH)/scheduler \ -I$(FULL_AMD_PATH)/powerplay/inc \ -I$(FULL_AMD_PATH)/acp/include \ -I$(FULL_AMD_DISPLAY_PATH) \ -- cgit v1.2.3 From 103a4b1d48cccb161796eda79a3547ce6616d260 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 22 Feb 2018 08:21:49 +0000 Subject: drm/amd: Remove inclusion of non-existing include directories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fix the following build warnings: CC [M] drivers/gpu/drm/amd/amdgpu/amdgpu_drv.o cc1: warning: ../display/: No such file or directory [-Wmissing-include-dirs] cc1: warning: ../display/include: No such file or directory [-Wmissing-include-dirs] CC [M] drivers/gpu/drm/amd/amdgpu/amdgpu_device.o cc1: warning: ../display/: No such file or directory [-Wmissing-include-dirs] cc1: warning: ../display/include: No such file or directory [-Wmissing-include-dirs] [...] This warning is shown for each file in amdgpu directory, so it spams a lot. Acked-by: Christian König Signed-off-by: Corentin Labbe Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/Makefile | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile index 3d14478913de..a2c5be493555 100644 --- a/drivers/gpu/drm/amd/display/Makefile +++ b/drivers/gpu/drm/amd/display/Makefile @@ -26,8 +26,6 @@ AMDDALPATH = $(RELATIVE_AMD_DISPLAY_PATH) -subdir-ccflags-y += -I$(AMDDALPATH)/ -I$(AMDDALPATH)/include - subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/hw subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/inc -- cgit v1.2.3 From bd58c48c1045728f80e6322636662aee99ab5fcd Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Thu, 22 Feb 2018 16:33:05 +0800 Subject: drm/amd/pp: Remove duplicated vega10_is_smc_ram_running calls Avoid conflicts in reading the same register mmPCIE_INDEX2 with other clients Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c index f6f39d01d227..0f76a54891e5 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c @@ -84,9 +84,6 @@ static uint32_t vega10_wait_for_response(struct pp_hwmgr *hwmgr) { uint32_t reg; - if (!vega10_is_smc_ram_running(hwmgr)) - return -EINVAL; - reg = soc15_get_register_offset(MP1_HWID, 0, mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); @@ -107,9 +104,6 @@ int vega10_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, { uint32_t reg; - if (!vega10_is_smc_ram_running(hwmgr)) - return -EINVAL; - reg = soc15_get_register_offset(MP1_HWID, 0, mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66); cgs_write_register(hwmgr->device, reg, msg); @@ -127,9 +121,6 @@ int vega10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) { uint32_t reg; - if (!vega10_is_smc_ram_running(hwmgr)) - return -EINVAL; - vega10_wait_for_response(hwmgr); reg = soc15_get_register_offset(MP1_HWID, 0, @@ -156,9 +147,6 @@ int vega10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, { uint32_t reg; - if (!vega10_is_smc_ram_running(hwmgr)) - return -EINVAL; - vega10_wait_for_response(hwmgr); reg = soc15_get_register_offset(MP1_HWID, 0, @@ -581,6 +569,9 @@ static int vega10_smu_fini(struct pp_hwmgr *hwmgr) static int vega10_start_smu(struct pp_hwmgr *hwmgr) { + if (!vega10_is_smc_ram_running(hwmgr)) + return -EINVAL; + PP_ASSERT_WITH_CODE(!vega10_verify_smc_interface(hwmgr), "Failed to verify SMC interface!", return -EINVAL); -- cgit v1.2.3 From baeb7721b1a60ab86164ed746db522591c4540cb Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Thu, 22 Feb 2018 16:50:57 +0800 Subject: drm/amd/pp: Add debug info when smu failed on Vega10 When smu msssage failed, print out return value in dmesg. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c index 0f76a54891e5..b4c487fb6a1d 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c @@ -83,13 +83,17 @@ static bool vega10_is_smc_ram_running(struct pp_hwmgr *hwmgr) static uint32_t vega10_wait_for_response(struct pp_hwmgr *hwmgr) { uint32_t reg; + uint32_t ret; reg = soc15_get_register_offset(MP1_HWID, 0, mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); - phm_wait_for_register_unequal(hwmgr, reg, + ret = phm_wait_for_register_unequal(hwmgr, reg, 0, MP1_C2PMSG_90__CONTENT_MASK); + if (ret) + pr_err("No response from smu\n"); + return cgs_read_register(hwmgr->device, reg); } @@ -120,6 +124,7 @@ int vega10_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, int vega10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) { uint32_t reg; + uint32_t ret; vega10_wait_for_response(hwmgr); @@ -129,8 +134,9 @@ int vega10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) vega10_send_msg_to_smc_without_waiting(hwmgr, msg); - if (vega10_wait_for_response(hwmgr) != 1) - pr_err("Failed to send message: 0x%x\n", msg); + ret = vega10_wait_for_response(hwmgr); + if (ret != 1) + pr_err("Failed to send message: 0x%x, ret value: 0x%x\n", msg, ret); return 0; } @@ -146,6 +152,7 @@ int vega10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, uint16_t msg, uint32_t parameter) { uint32_t reg; + uint32_t ret; vega10_wait_for_response(hwmgr); @@ -159,8 +166,9 @@ int vega10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, vega10_send_msg_to_smc_without_waiting(hwmgr, msg); - if (vega10_wait_for_response(hwmgr) != 1) - pr_err("Failed to send message: 0x%x\n", msg); + ret = vega10_wait_for_response(hwmgr); + if (ret != 1) + pr_err("Failed to send message: 0x%x, ret value: 0x%x\n", msg, ret); return 0; } -- cgit v1.2.3 From d246cd53fd6a6bffc9e4dcf045d8031f445353fb Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Thu, 22 Feb 2018 17:20:53 +0800 Subject: drm/amd/pp: Remove dead error checking code on Vega10 when smu failed, print out the error info immediately for debug. smum_send_msg_to_smu always return true, so no need to check return value. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 122 ++++++--------------- .../gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c | 22 ++-- .../gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c | 10 +- .../gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c | 55 ++++------ 4 files changed, 67 insertions(+), 142 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 4c53dabb102f..2b95b17e73bc 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -2868,11 +2868,8 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) (struct vega10_hwmgr *)(hwmgr->backend); int tmp_result, result = 0; - tmp_result = smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_ConfigureTelemetry, data->config_telemetry); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to configure telemetry!", - return tmp_result); + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_ConfigureTelemetry, data->config_telemetry); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_NumOfDisplays, 0); @@ -2883,13 +2880,9 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) return 0); if ((hwmgr->smu_version == 0x001c2c00) || - (hwmgr->smu_version == 0x001c2d00)) { - tmp_result = smum_send_msg_to_smc_with_parameter(hwmgr, + (hwmgr->smu_version == 0x001c2d00)) + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_UpdatePkgPwrPidAlpha, 1); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to set package power PID!", - return tmp_result); - } tmp_result = vega10_construct_voltage_tables(hwmgr); PP_ASSERT_WITH_CODE(!tmp_result, @@ -3642,12 +3635,9 @@ static int vega10_upload_dpm_bootup_level(struct pp_hwmgr *hwmgr) if (!data->registry_data.sclk_dpm_key_disabled) { if (data->smc_state_table.gfx_boot_level != data->dpm_table.gfx_table.dpm_state.soft_min_level) { - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( - hwmgr, + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMinGfxclkByIndex, - data->smc_state_table.gfx_boot_level), - "Failed to set soft min sclk index!", - return -EINVAL); + data->smc_state_table.gfx_boot_level); data->dpm_table.gfx_table.dpm_state.soft_min_level = data->smc_state_table.gfx_boot_level; } @@ -3658,19 +3648,13 @@ static int vega10_upload_dpm_bootup_level(struct pp_hwmgr *hwmgr) data->dpm_table.mem_table.dpm_state.soft_min_level) { if (data->smc_state_table.mem_boot_level == NUM_UCLK_DPM_LEVELS - 1) { socclk_idx = vega10_get_soc_index_for_max_uclk(hwmgr); - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( - hwmgr, + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMinSocclkByIndex, - socclk_idx), - "Failed to set soft min uclk index!", - return -EINVAL); + socclk_idx); } else { - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( - hwmgr, + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMinUclkByIndex, - data->smc_state_table.mem_boot_level), - "Failed to set soft min uclk index!", - return -EINVAL); + data->smc_state_table.mem_boot_level); } data->dpm_table.mem_table.dpm_state.soft_min_level = data->smc_state_table.mem_boot_level; @@ -3689,13 +3673,10 @@ static int vega10_upload_dpm_max_level(struct pp_hwmgr *hwmgr) if (!data->registry_data.sclk_dpm_key_disabled) { if (data->smc_state_table.gfx_max_level != - data->dpm_table.gfx_table.dpm_state.soft_max_level) { - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( - hwmgr, + data->dpm_table.gfx_table.dpm_state.soft_max_level) { + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxGfxclkByIndex, - data->smc_state_table.gfx_max_level), - "Failed to set soft max sclk index!", - return -EINVAL); + data->smc_state_table.gfx_max_level); data->dpm_table.gfx_table.dpm_state.soft_max_level = data->smc_state_table.gfx_max_level; } @@ -3703,13 +3684,10 @@ static int vega10_upload_dpm_max_level(struct pp_hwmgr *hwmgr) if (!data->registry_data.mclk_dpm_key_disabled) { if (data->smc_state_table.mem_max_level != - data->dpm_table.mem_table.dpm_state.soft_max_level) { - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( - hwmgr, - PPSMC_MSG_SetSoftMaxUclkByIndex, - data->smc_state_table.mem_max_level), - "Failed to set soft max mclk index!", - return -EINVAL); + data->dpm_table.mem_table.dpm_state.soft_max_level) { + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetSoftMaxUclkByIndex, + data->smc_state_table.mem_max_level); data->dpm_table.mem_table.dpm_state.soft_max_level = data->smc_state_table.mem_max_level; } @@ -3779,7 +3757,6 @@ static int vega10_update_sclk_threshold(struct pp_hwmgr *hwmgr) { struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); - int result = 0; uint32_t low_sclk_interrupt_threshold = 0; if (PP_CAP(PHM_PlatformCaps_SclkThrottleLowNotification) && @@ -3791,12 +3768,12 @@ static int vega10_update_sclk_threshold(struct pp_hwmgr *hwmgr) cpu_to_le32(low_sclk_interrupt_threshold); /* This message will also enable SmcToHost Interrupt */ - result = smum_send_msg_to_smc_with_parameter(hwmgr, + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetLowGfxclkInterruptThreshold, (uint32_t)low_sclk_interrupt_threshold); } - return result; + return 0; } static int vega10_set_power_state_tasks(struct pp_hwmgr *hwmgr, @@ -3887,11 +3864,7 @@ static int vega10_get_gpu_power(struct pp_hwmgr *hwmgr, { uint32_t value; - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetCurrPkgPwr), - "Failed to get current package power!", - return -EINVAL); - + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrPkgPwr); vega10_read_arg_from_smc(hwmgr, &value); /* power value is an integer */ @@ -3974,10 +3947,10 @@ static int vega10_read_sensor(struct pp_hwmgr *hwmgr, int idx, return ret; } -static int vega10_notify_smc_display_change(struct pp_hwmgr *hwmgr, +static void vega10_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_disp) { - return smum_send_msg_to_smc_with_parameter(hwmgr, + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetUclkFastSwitch, has_disp ? 0 : 1); } @@ -4012,7 +3985,7 @@ int vega10_display_clock_voltage_request(struct pp_hwmgr *hwmgr, if (!result) { clk_request = (clk_freq << 16) | clk_select; - result = smum_send_msg_to_smc_with_parameter(hwmgr, + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_RequestDisplayClockByFreq, clk_request); } @@ -4081,10 +4054,9 @@ static int vega10_notify_smc_display_config_after_ps_adjustment( clock_req.clock_type = amd_pp_dcef_clock; clock_req.clock_freq_in_khz = dpm_table->dpm_levels[i].value; if (!vega10_display_clock_voltage_request(hwmgr, &clock_req)) { - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc_with_parameter( + smum_send_msg_to_smc_with_parameter( hwmgr, PPSMC_MSG_SetMinDeepSleepDcefclk, - min_clocks.dcefClockInSR /100), - "Attempt to set divider for DCEFCLK Failed!",); + min_clocks.dcefClockInSR / 100); } else { pr_info("Attempt to set Hard Min for DCEFCLK Failed!"); } @@ -4564,14 +4536,8 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, if (data->registry_data.sclk_dpm_key_disabled) break; - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetCurrentGfxclkIndex), - "Attempt to get current sclk index Failed!", - return -1); - PP_ASSERT_WITH_CODE(!vega10_read_arg_from_smc(hwmgr, - &now), - "Attempt to read sclk index Failed!", - return -1); + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentGfxclkIndex); + vega10_read_arg_from_smc(hwmgr, &now); for (i = 0; i < sclk_table->count; i++) size += sprintf(buf + size, "%d: %uMhz %s\n", @@ -4582,14 +4548,8 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, if (data->registry_data.mclk_dpm_key_disabled) break; - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetCurrentUclkIndex), - "Attempt to get current mclk index Failed!", - return -1); - PP_ASSERT_WITH_CODE(!vega10_read_arg_from_smc(hwmgr, - &now), - "Attempt to read mclk index Failed!", - return -1); + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentUclkIndex); + vega10_read_arg_from_smc(hwmgr, &now); for (i = 0; i < mclk_table->count; i++) size += sprintf(buf + size, "%d: %uMhz %s\n", @@ -4597,14 +4557,8 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, (i == now) ? "*" : ""); break; case PP_PCIE: - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetCurrentLinkIndex), - "Attempt to get current mclk index Failed!", - return -1); - PP_ASSERT_WITH_CODE(!vega10_read_arg_from_smc(hwmgr, - &now), - "Attempt to read mclk index Failed!", - return -1); + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentLinkIndex); + vega10_read_arg_from_smc(hwmgr, &now); for (i = 0; i < pcie_table->count; i++) size += sprintf(buf + size, "%d: %s %s\n", i, @@ -4836,24 +4790,18 @@ static int vega10_set_power_profile_state(struct pp_hwmgr *hwmgr, if (sclk_idx != ~0) { if (!data->registry_data.sclk_dpm_key_disabled) - PP_ASSERT_WITH_CODE( - !smum_send_msg_to_smc_with_parameter( + smum_send_msg_to_smc_with_parameter( hwmgr, PPSMC_MSG_SetSoftMinGfxclkByIndex, - sclk_idx), - "Failed to set soft min sclk index!", - return -EINVAL); + sclk_idx); } if (mclk_idx != ~0) { if (!data->registry_data.mclk_dpm_key_disabled) - PP_ASSERT_WITH_CODE( - !smum_send_msg_to_smc_with_parameter( + smum_send_msg_to_smc_with_parameter( hwmgr, PPSMC_MSG_SetSoftMinUclkByIndex, - mclk_idx), - "Failed to set soft min mclk index!", - return -EINVAL); + mclk_idx); } return 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c index 981c9e5431da..f5ed171d6940 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c @@ -850,7 +850,6 @@ static int vega10_program_gc_didt_config_registers(struct pp_hwmgr *hwmgr, const static void vega10_didt_set_mask(struct pp_hwmgr *hwmgr, const bool enable) { uint32_t data; - int result; uint32_t en = (enable ? 1 : 0); uint32_t didt_block_info = SQ_IR_MASK | TCP_IR_MASK | TD_PCC_MASK; @@ -924,11 +923,10 @@ static void vega10_didt_set_mask(struct pp_hwmgr *hwmgr, const bool enable) } } - if (enable) { - /* For Vega10, SMC does not support any mask yet. */ - result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ConfigureGfxDidt, didt_block_info); - PP_ASSERT((0 == result), "[EnableDiDtConfig] SMC Configure Gfx Didt Failed!"); - } + /* For Vega10, SMC does not support any mask yet. */ + if (enable) + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ConfigureGfxDidt, didt_block_info); + } static int vega10_enable_cac_driving_se_didt_config(struct pp_hwmgr *hwmgr) @@ -1344,7 +1342,7 @@ int vega10_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n) (struct vega10_hwmgr *)(hwmgr->backend); if (data->registry_data.enable_pkg_pwr_tracking_feature) - return smum_send_msg_to_smc_with_parameter(hwmgr, + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetPptLimit, n); return 0; @@ -1406,24 +1404,24 @@ int vega10_disable_power_containment(struct pp_hwmgr *hwmgr) return 0; } -static int vega10_set_overdrive_target_percentage(struct pp_hwmgr *hwmgr, +static void vega10_set_overdrive_target_percentage(struct pp_hwmgr *hwmgr, uint32_t adjust_percent) { - return smum_send_msg_to_smc_with_parameter(hwmgr, + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_OverDriveSetPercentage, adjust_percent); } int vega10_power_control_set_level(struct pp_hwmgr *hwmgr) { - int adjust_percent, result = 0; + int adjust_percent; if (PP_CAP(PHM_PlatformCaps_PowerContainment)) { adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ? hwmgr->platform_descriptor.TDPAdjustment : (-1 * hwmgr->platform_descriptor.TDPAdjustment); - result = vega10_set_overdrive_target_percentage(hwmgr, + vega10_set_overdrive_target_percentage(hwmgr, (uint32_t)adjust_percent); } - return result; + return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c index eb6e965ea5d7..fc2325e7f387 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c @@ -31,14 +31,8 @@ static int vega10_get_current_rpm(struct pp_hwmgr *hwmgr, uint32_t *current_rpm) { - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetCurrentRpm), - "Attempt to get current RPM from SMC Failed!", - return -1); - PP_ASSERT_WITH_CODE(!vega10_read_arg_from_smc(hwmgr, - current_rpm), - "Attempt to read current RPM from SMC Failed!", - return -1); + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentRpm); + vega10_read_arg_from_smc(hwmgr, current_rpm); return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c index b4c487fb6a1d..dd842ae804e6 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c @@ -228,20 +228,15 @@ int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, "Invalid SMU Table version!", return -EINVAL); PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, "Invalid SMU Table Length!", return -EINVAL); - PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, - priv->smu_tables.entry[table_id].table_addr_high) == 0, - "[CopyTableFromSMC] Attempt to Set Dram Addr High Failed!", return -EINVAL); - PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, + priv->smu_tables.entry[table_id].table_addr_high); + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrLow, - priv->smu_tables.entry[table_id].table_addr_low) == 0, - "[CopyTableFromSMC] Attempt to Set Dram Addr Low Failed!", - return -EINVAL); - PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, + priv->smu_tables.entry[table_id].table_addr_low); + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_TransferTableSmu2Dram, - priv->smu_tables.entry[table_id].table_id) == 0, - "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!", - return -EINVAL); + priv->smu_tables.entry[table_id].table_id); memcpy(table, priv->smu_tables.entry[table_id].table, priv->smu_tables.entry[table_id].size); @@ -270,21 +265,15 @@ int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[table_id].table, table, priv->smu_tables.entry[table_id].size); - PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, - priv->smu_tables.entry[table_id].table_addr_high) == 0, - "[CopyTableToSMC] Attempt to Set Dram Addr High Failed!", - return -EINVAL;); - PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, + priv->smu_tables.entry[table_id].table_addr_high); + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrLow, - priv->smu_tables.entry[table_id].table_addr_low) == 0, - "[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!", - return -EINVAL); - PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, + priv->smu_tables.entry[table_id].table_addr_low); + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_TransferTableDram2Smu, - priv->smu_tables.entry[table_id].table_id) == 0, - "[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!", - return -EINVAL); + priv->smu_tables.entry[table_id].table_id); return 0; } @@ -323,13 +312,9 @@ int vega10_get_smc_features(struct pp_hwmgr *hwmgr, if (features_enabled == NULL) return -EINVAL; - if (!vega10_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetEnabledSmuFeatures)) { - vega10_read_arg_from_smc(hwmgr, features_enabled); - return 0; - } - - return -EINVAL; + vega10_send_msg_to_smc(hwmgr, PPSMC_MSG_GetEnabledSmuFeatures); + vega10_read_arg_from_smc(hwmgr, features_enabled); + return 0; } int vega10_set_tools_address(struct pp_hwmgr *hwmgr) @@ -339,12 +324,12 @@ int vega10_set_tools_address(struct pp_hwmgr *hwmgr) if (priv->smu_tables.entry[TOOLSTABLE].table_addr_high || priv->smu_tables.entry[TOOLSTABLE].table_addr_low) { - if (!vega10_send_msg_to_smc_with_parameter(hwmgr, + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetToolsDramAddrHigh, - priv->smu_tables.entry[TOOLSTABLE].table_addr_high)) - vega10_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetToolsDramAddrLow, - priv->smu_tables.entry[TOOLSTABLE].table_addr_low); + priv->smu_tables.entry[TOOLSTABLE].table_addr_high); + vega10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetToolsDramAddrLow, + priv->smu_tables.entry[TOOLSTABLE].table_addr_low); } return 0; } -- cgit v1.2.3 From af264d0245271822bb56145c4633a50fd730d0ab Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Thu, 22 Feb 2018 20:27:07 +0800 Subject: drm/amd/pp: Refine code in powerplay for Cz/Vega10 Add dpm check functions on CZ/Vega10 to smu backend function table. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c | 27 ++-------------------- drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h | 1 - drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 15 ++---------- drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c | 24 +++++++++++++++++++ drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h | 2 ++ .../gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c | 13 +++++++++++ 6 files changed, 43 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c index 5a7b99f45d36..4b4876599746 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c @@ -1009,32 +1009,9 @@ static void cz_reset_acp_boot_level(struct pp_hwmgr *hwmgr) cz_hwmgr->acp_boot_level = 0xff; } -static bool cz_dpm_check_smu_features(struct pp_hwmgr *hwmgr, - unsigned long check_feature) -{ - int result; - unsigned long features; - - result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetFeatureStatus, 0); - if (result == 0) { - features = smum_get_argument(hwmgr); - if (features & check_feature) - return true; - } - - return false; -} - -static bool cz_check_for_dpm_enabled(struct pp_hwmgr *hwmgr) -{ - if (cz_dpm_check_smu_features(hwmgr, SMU_EnabledFeatureScoreboard_SclkDpmOn)) - return true; - return false; -} - static int cz_disable_dpm_tasks(struct pp_hwmgr *hwmgr) { - if (!cz_check_for_dpm_enabled(hwmgr)) { + if (!smum_is_dpm_running(hwmgr)) { pr_info("dpm has been disabled\n"); return 0; } @@ -1049,7 +1026,7 @@ static int cz_disable_dpm_tasks(struct pp_hwmgr *hwmgr) static int cz_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { - if (cz_check_for_dpm_enabled(hwmgr)) { + if (smum_is_dpm_running(hwmgr)) { pr_info("dpm has been enabled\n"); return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h index 468c739a4299..b56720a3fc88 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h @@ -171,7 +171,6 @@ struct cz_power_state { #define DPMFlags_Debug 0x80000000 #define SMU_EnabledFeatureScoreboard_AcpDpmOn 0x00000001 /* bit 0 */ -#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00200000 #define SMU_EnabledFeatureScoreboard_UvdDpmOn 0x00800000 /* bit 23 */ #define SMU_EnabledFeatureScoreboard_VceDpmOn 0x01000000 /* bit 24 */ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 2b95b17e73bc..b13f55d04833 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -931,17 +931,6 @@ static int vega10_setup_asic_task(struct pp_hwmgr *hwmgr) return 0; } -static bool vega10_is_dpm_running(struct pp_hwmgr *hwmgr) -{ - uint32_t features_enabled; - - if (!vega10_get_smc_features(hwmgr, &features_enabled)) { - if (features_enabled & SMC_DPM_FEATURES) - return true; - } - return false; -} - /** * Remove repeated voltage values and create table with unique values. * @@ -2874,7 +2863,7 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_NumOfDisplays, 0); - tmp_result = (!vega10_is_dpm_running(hwmgr)) ? 0 : -1; + tmp_result = (!smum_is_dpm_running(hwmgr)) ? 0 : -1; PP_ASSERT_WITH_CODE(!tmp_result, "DPM is already running right , skipping re-enablement!", return 0); @@ -4699,7 +4688,7 @@ static int vega10_disable_dpm_tasks(struct pp_hwmgr *hwmgr) { int tmp_result, result = 0; - tmp_result = (vega10_is_dpm_running(hwmgr)) ? 0 : -1; + tmp_result = (smum_is_dpm_running(hwmgr)) ? 0 : -1; PP_ASSERT_WITH_CODE(tmp_result == 0, "DPM is not running right now, no need to disable DPM!", return 0); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c index 4d3aff381bca..7fe4c1170edc 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c @@ -855,6 +855,29 @@ static int cz_smu_fini(struct pp_hwmgr *hwmgr) return 0; } +static bool cz_dpm_check_smu_features(struct pp_hwmgr *hwmgr, + unsigned long check_feature) +{ + int result; + unsigned long features; + + result = cz_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetFeatureStatus, 0); + if (result == 0) { + features = smum_get_argument(hwmgr); + if (features & check_feature) + return true; + } + + return false; +} + +static bool cz_is_dpm_running(struct pp_hwmgr *hwmgr) +{ + if (cz_dpm_check_smu_features(hwmgr, SMU_EnabledFeatureScoreboard_SclkDpmOn)) + return true; + return false; +} + const struct pp_smumgr_func cz_smu_funcs = { .smu_init = cz_smu_init, .smu_fini = cz_smu_fini, @@ -867,5 +890,6 @@ const struct pp_smumgr_func cz_smu_funcs = { .send_msg_to_smc_with_parameter = cz_send_msg_to_smc_with_parameter, .download_pptable_settings = cz_download_pptable_settings, .upload_pptable_settings = cz_upload_pptable_settings, + .is_dpm_running = cz_is_dpm_running, }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h index 7c3a290c8957..756b2c4b5af0 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h @@ -31,6 +31,8 @@ #define CZ_SCRATCH_SIZE_SDMA_METADATA 1024 #define CZ_SCRATCH_SIZE_IH ((2*256+1)*4) +#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00200000 + enum cz_scratch_entry { CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0 = 0, CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c index dd842ae804e6..70dd5f8906db 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c @@ -317,6 +317,18 @@ int vega10_get_smc_features(struct pp_hwmgr *hwmgr, return 0; } +static bool vega10_is_dpm_running(struct pp_hwmgr *hwmgr) +{ + uint32_t features_enabled = 0; + + vega10_get_smc_features(hwmgr, &features_enabled); + + if (features_enabled & SMC_DPM_FEATURES) + return true; + else + return false; +} + int vega10_set_tools_address(struct pp_hwmgr *hwmgr) { struct vega10_smumgr *priv = @@ -583,4 +595,5 @@ const struct pp_smumgr_func vega10_smu_funcs = { .send_msg_to_smc_with_parameter = &vega10_send_msg_to_smc_with_parameter, .download_pptable_settings = NULL, .upload_pptable_settings = NULL, + .is_dpm_running = vega10_is_dpm_running, }; -- cgit v1.2.3 From e21148ecbac33b854156a2741d35c33892c2ac34 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Fri, 23 Feb 2018 13:13:13 +0800 Subject: drm/amd/pp: Cleaning up vega10_enable_dpm_tasks function 1. move display num initialize out of dpm enable tasks. 2. do not set/restore smc telemetry if dpm is runing. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index b13f55d04833..9b0fcb6eb8d2 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -928,6 +928,8 @@ static int vega10_setup_asic_task(struct pp_hwmgr *hwmgr) "Failed to set up led dpm config!", return -EINVAL); + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_NumOfDisplays, 0); + return 0; } @@ -2857,12 +2859,6 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) (struct vega10_hwmgr *)(hwmgr->backend); int tmp_result, result = 0; - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_ConfigureTelemetry, data->config_telemetry); - - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_NumOfDisplays, 0); - tmp_result = (!smum_is_dpm_running(hwmgr)) ? 0 : -1; PP_ASSERT_WITH_CODE(!tmp_result, "DPM is already running right , skipping re-enablement!", @@ -2873,6 +2869,9 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_UpdatePkgPwrPidAlpha, 1); + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_ConfigureTelemetry, data->config_telemetry); + tmp_result = vega10_construct_voltage_tables(hwmgr); PP_ASSERT_WITH_CODE(!tmp_result, "Failed to contruct voltage tables!", -- cgit v1.2.3 From cd277585d69394507137b513b51f40d2590abda4 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Thu, 22 Feb 2018 20:46:49 +0800 Subject: drm/amd/pp: Move common dpm check functions to hardwaremanager.c Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c | 9 --------- drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c | 10 ++++++++++ drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 10 ---------- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 10 ---------- 4 files changed, 10 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c index 4b4876599746..2aa84c728e81 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c @@ -1011,10 +1011,6 @@ static void cz_reset_acp_boot_level(struct pp_hwmgr *hwmgr) static int cz_disable_dpm_tasks(struct pp_hwmgr *hwmgr) { - if (!smum_is_dpm_running(hwmgr)) { - pr_info("dpm has been disabled\n"); - return 0; - } cz_disable_nb_dpm(hwmgr); cz_clear_voting_clients(hwmgr); @@ -1026,11 +1022,6 @@ static int cz_disable_dpm_tasks(struct pp_hwmgr *hwmgr) static int cz_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { - if (smum_is_dpm_running(hwmgr)) { - pr_info("dpm has been enabled\n"); - return 0; - } - cz_program_voting_clients(hwmgr); if (cz_start_dpm(hwmgr)) return -EINVAL; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c index fdd2c05d25d5..33480deb64b9 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c @@ -79,6 +79,11 @@ int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr) bool enabled; PHM_FUNC_CHECK(hwmgr); + if (smum_is_dpm_running(hwmgr)) { + pr_info("dpm has been enabled\n"); + return 0; + } + if (NULL != hwmgr->hwmgr_func->dynamic_state_management_enable) ret = hwmgr->hwmgr_func->dynamic_state_management_enable(hwmgr); @@ -96,6 +101,11 @@ int phm_disable_dynamic_state_management(struct pp_hwmgr *hwmgr) PHM_FUNC_CHECK(hwmgr); + if (!smum_is_dpm_running(hwmgr)) { + pr_info("dpm has been disabled\n"); + return 0; + } + if (hwmgr->hwmgr_func->dynamic_state_management_disable) ret = hwmgr->hwmgr_func->dynamic_state_management_disable(hwmgr); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 1d988ef1978e..535d786b79ae 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -1239,11 +1239,6 @@ static int smu7_enable_dpm_tasks(struct pp_hwmgr *hwmgr) int tmp_result = 0; int result = 0; - tmp_result = (!smum_is_dpm_running(hwmgr)) ? 0 : -1; - PP_ASSERT_WITH_CODE(tmp_result == 0, - "DPM is already running", - ); - if (smu7_voltage_control(hwmgr)) { tmp_result = smu7_enable_voltage_control(hwmgr); PP_ASSERT_WITH_CODE(tmp_result == 0, @@ -1406,11 +1401,6 @@ int smu7_disable_dpm_tasks(struct pp_hwmgr *hwmgr) { int tmp_result, result = 0; - tmp_result = (smum_is_dpm_running(hwmgr)) ? 0 : -1; - PP_ASSERT_WITH_CODE(tmp_result == 0, - "DPM is not running right now, no need to disable DPM!", - return 0); - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ThermalController)) PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 9b0fcb6eb8d2..f5df20a22e97 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -2859,11 +2859,6 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) (struct vega10_hwmgr *)(hwmgr->backend); int tmp_result, result = 0; - tmp_result = (!smum_is_dpm_running(hwmgr)) ? 0 : -1; - PP_ASSERT_WITH_CODE(!tmp_result, - "DPM is already running right , skipping re-enablement!", - return 0); - if ((hwmgr->smu_version == 0x001c2c00) || (hwmgr->smu_version == 0x001c2d00)) smum_send_msg_to_smc_with_parameter(hwmgr, @@ -4687,11 +4682,6 @@ static int vega10_disable_dpm_tasks(struct pp_hwmgr *hwmgr) { int tmp_result, result = 0; - tmp_result = (smum_is_dpm_running(hwmgr)) ? 0 : -1; - PP_ASSERT_WITH_CODE(tmp_result == 0, - "DPM is not running right now, no need to disable DPM!", - return 0); - if (PP_CAP(PHM_PlatformCaps_ThermalController)) vega10_disable_thermal_protection(hwmgr); -- cgit v1.2.3 From e44fcf71f4092121f24b0d1b0c613a4e9c1e84e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 12:00:05 +0100 Subject: drm/ttm: add default implementations for ttm_tt_(un)populate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use ttm_pool_populate/ttm_pool_unpopulate if the driver doesn't provide a function. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/ttm/ttm_tt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 9fd7115a013a..65bf4eac184b 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -410,7 +410,10 @@ int ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx) if (ttm->state != tt_unpopulated) return 0; - ret = ttm->bdev->driver->ttm_tt_populate(ttm, ctx); + if (ttm->bdev->driver->ttm_tt_populate) + ret = ttm->bdev->driver->ttm_tt_populate(ttm, ctx); + else + ret = ttm_pool_populate(ttm, ctx); if (!ret) ttm_tt_add_mapping(ttm); return ret; @@ -436,5 +439,8 @@ void ttm_tt_unpopulate(struct ttm_tt *ttm) return; ttm_tt_clear_mapping(ttm); - ttm->bdev->driver->ttm_tt_unpopulate(ttm); + if (ttm->bdev->driver->ttm_tt_unpopulate) + ttm->bdev->driver->ttm_tt_unpopulate(ttm); + else + ttm_pool_unpopulate(ttm); } -- cgit v1.2.3 From b3afc7989fd814704ee09a8cf99998f9d790b1c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 12:01:38 +0100 Subject: drm/virtio: remove ttm_pool_* wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TTM calls the default implementation now. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/virtio/virtgpu_ttm.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_ttm.c b/drivers/gpu/drm/virtio/virtgpu_ttm.c index 36655b709eb2..1cde060602aa 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ttm.c +++ b/drivers/gpu/drm/virtio/virtgpu_ttm.c @@ -324,20 +324,6 @@ static struct ttm_backend_func virtio_gpu_backend_func = { .destroy = &virtio_gpu_ttm_backend_destroy, }; -static int virtio_gpu_ttm_tt_populate(struct ttm_tt *ttm, - struct ttm_operation_ctx *ctx) -{ - if (ttm->state != tt_unpopulated) - return 0; - - return ttm_pool_populate(ttm, ctx); -} - -static void virtio_gpu_ttm_tt_unpopulate(struct ttm_tt *ttm) -{ - ttm_pool_unpopulate(ttm); -} - static struct ttm_tt *virtio_gpu_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, uint32_t page_flags, @@ -421,8 +407,6 @@ static void virtio_gpu_bo_swap_notify(struct ttm_buffer_object *tbo) static struct ttm_bo_driver virtio_gpu_bo_driver = { .ttm_tt_create = &virtio_gpu_ttm_tt_create, - .ttm_tt_populate = &virtio_gpu_ttm_tt_populate, - .ttm_tt_unpopulate = &virtio_gpu_ttm_tt_unpopulate, .invalidate_caches = &virtio_gpu_invalidate_caches, .init_mem_type = &virtio_gpu_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, -- cgit v1.2.3 From b31925a83f0aa172562a35b6161501559b1367aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 12:02:36 +0100 Subject: drm/mgag200: remove ttm_pool_* wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TTM calls the default implementation now. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/mgag200/mgag200_ttm.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index c97009bb77dd..26e5f14645c5 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -216,21 +216,8 @@ static struct ttm_tt *mgag200_ttm_tt_create(struct ttm_bo_device *bdev, return tt; } -static int mgag200_ttm_tt_populate(struct ttm_tt *ttm, - struct ttm_operation_ctx *ctx) -{ - return ttm_pool_populate(ttm, ctx); -} - -static void mgag200_ttm_tt_unpopulate(struct ttm_tt *ttm) -{ - ttm_pool_unpopulate(ttm); -} - struct ttm_bo_driver mgag200_bo_driver = { .ttm_tt_create = mgag200_ttm_tt_create, - .ttm_tt_populate = mgag200_ttm_tt_populate, - .ttm_tt_unpopulate = mgag200_ttm_tt_unpopulate, .init_mem_type = mgag200_bo_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = mgag200_bo_evict_flags, -- cgit v1.2.3 From 401fedc21890f4e6e1fb82a3ffd7280736872920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 12:03:58 +0100 Subject: drm/hisilicon: remove ttm_pool_* wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TTM calls the default implementation now. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c index 8516e005643f..0c93349fbacf 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c @@ -223,21 +223,8 @@ static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_bo_device *bdev, return tt; } -static int hibmc_ttm_tt_populate(struct ttm_tt *ttm, - struct ttm_operation_ctx *ctx) -{ - return ttm_pool_populate(ttm, ctx); -} - -static void hibmc_ttm_tt_unpopulate(struct ttm_tt *ttm) -{ - ttm_pool_unpopulate(ttm); -} - struct ttm_bo_driver hibmc_bo_driver = { .ttm_tt_create = hibmc_ttm_tt_create, - .ttm_tt_populate = hibmc_ttm_tt_populate, - .ttm_tt_unpopulate = hibmc_ttm_tt_unpopulate, .init_mem_type = hibmc_bo_init_mem_type, .evict_flags = hibmc_bo_evict_flags, .move = NULL, -- cgit v1.2.3 From a29f0ca0c9313e4efde2c0af0bac1109b7f498a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 12:05:09 +0100 Subject: drm/ast: remove ttm_pool_* wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TTM calls the default implementation now. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/ast/ast_ttm.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index 7b784d91e258..68b9c5522eaa 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -216,21 +216,8 @@ static struct ttm_tt *ast_ttm_tt_create(struct ttm_bo_device *bdev, return tt; } -static int ast_ttm_tt_populate(struct ttm_tt *ttm, - struct ttm_operation_ctx *ctx) -{ - return ttm_pool_populate(ttm, ctx); -} - -static void ast_ttm_tt_unpopulate(struct ttm_tt *ttm) -{ - ttm_pool_unpopulate(ttm); -} - struct ttm_bo_driver ast_bo_driver = { .ttm_tt_create = ast_ttm_tt_create, - .ttm_tt_populate = ast_ttm_tt_populate, - .ttm_tt_unpopulate = ast_ttm_tt_unpopulate, .init_mem_type = ast_bo_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = ast_bo_evict_flags, -- cgit v1.2.3 From 2a7b464f846aa49ab7f585d0ff2257d269fc2147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 12:06:59 +0100 Subject: drm/qxl: remove ttm_pool_* wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TTM calls the default implementation now. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/qxl/qxl_ttm.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index 59cd74c3f3af..07d4f3fde6c1 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -291,26 +291,6 @@ static struct ttm_backend_func qxl_backend_func = { .destroy = &qxl_ttm_backend_destroy, }; -static int qxl_ttm_tt_populate(struct ttm_tt *ttm, - struct ttm_operation_ctx *ctx) -{ - int r; - - if (ttm->state != tt_unpopulated) - return 0; - - r = ttm_pool_populate(ttm, ctx); - if (r) - return r; - - return 0; -} - -static void qxl_ttm_tt_unpopulate(struct ttm_tt *ttm) -{ - ttm_pool_unpopulate(ttm); -} - static struct ttm_tt *qxl_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, uint32_t page_flags, struct page *dummy_read_page) @@ -379,8 +359,6 @@ static void qxl_bo_move_notify(struct ttm_buffer_object *bo, static struct ttm_bo_driver qxl_bo_driver = { .ttm_tt_create = &qxl_ttm_tt_create, - .ttm_tt_populate = &qxl_ttm_tt_populate, - .ttm_tt_unpopulate = &qxl_ttm_tt_unpopulate, .invalidate_caches = &qxl_invalidate_caches, .init_mem_type = &qxl_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, -- cgit v1.2.3 From e55b33f8ab0d04172206d7b409321226c2ef0001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 12:11:25 +0100 Subject: drm/cirrus: remove ttm_pool_* wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TTM calls the default implementation now. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/cirrus/cirrus_ttm.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index a8e31ea07382..33798c76a64b 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -216,21 +216,8 @@ static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_bo_device *bdev, return tt; } -static int cirrus_ttm_tt_populate(struct ttm_tt *ttm, - struct ttm_operation_ctx *ctx) -{ - return ttm_pool_populate(ttm, ctx); -} - -static void cirrus_ttm_tt_unpopulate(struct ttm_tt *ttm) -{ - ttm_pool_unpopulate(ttm); -} - struct ttm_bo_driver cirrus_bo_driver = { .ttm_tt_create = cirrus_ttm_tt_create, - .ttm_tt_populate = cirrus_ttm_tt_populate, - .ttm_tt_unpopulate = cirrus_ttm_tt_unpopulate, .init_mem_type = cirrus_bo_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = cirrus_bo_evict_flags, -- cgit v1.2.3 From 95bbb6d35d0b182968d7ce803a0cdc27e6e5fcb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 12:12:41 +0100 Subject: drm/bochs: remove the default ttm_tt_populate callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TTM calls the default implementation now. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/bochs/bochs_mm.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 704e879711e4..5525b6660340 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -196,8 +196,6 @@ static struct ttm_tt *bochs_ttm_tt_create(struct ttm_bo_device *bdev, struct ttm_bo_driver bochs_bo_driver = { .ttm_tt_create = bochs_ttm_tt_create, - .ttm_tt_populate = ttm_pool_populate, - .ttm_tt_unpopulate = ttm_pool_unpopulate, .init_mem_type = bochs_bo_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = bochs_bo_evict_flags, -- cgit v1.2.3 From 886a16b3582d256c7bc93cdb773678c26632b987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 14:53:42 +0100 Subject: staging: vboxvideo: remove ttm_pool_* wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TTM calls the default implementation now. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Signed-off-by: Alex Deucher --- drivers/staging/vboxvideo/vbox_ttm.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vboxvideo/vbox_ttm.c b/drivers/staging/vboxvideo/vbox_ttm.c index 2ea31589d773..c4b7a6b9abd5 100644 --- a/drivers/staging/vboxvideo/vbox_ttm.c +++ b/drivers/staging/vboxvideo/vbox_ttm.c @@ -213,21 +213,8 @@ static struct ttm_tt *vbox_ttm_tt_create(struct ttm_bo_device *bdev, return tt; } -static int vbox_ttm_tt_populate(struct ttm_tt *ttm, - struct ttm_operation_ctx *ctx) -{ - return ttm_pool_populate(ttm, ctx); -} - -static void vbox_ttm_tt_unpopulate(struct ttm_tt *ttm) -{ - ttm_pool_unpopulate(ttm); -} - static struct ttm_bo_driver vbox_bo_driver = { .ttm_tt_create = vbox_ttm_tt_create, - .ttm_tt_populate = vbox_ttm_tt_populate, - .ttm_tt_unpopulate = vbox_ttm_tt_unpopulate, .init_mem_type = vbox_bo_init_mem_type, .eviction_valuable = ttm_bo_eviction_valuable, .evict_flags = vbox_bo_evict_flags, -- cgit v1.2.3 From 38392633627c60ca8a1e90106055c85b5215a494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 21 Feb 2018 17:26:45 +0100 Subject: drm/ttm: drop bo->glob MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pointer is available as bo->bdev->glob as well. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/qxl/qxl_release.c | 2 +- drivers/gpu/drm/ttm/ttm_bo.c | 23 ++++++++++++----------- drivers/gpu/drm/ttm/ttm_bo_util.c | 2 +- drivers/gpu/drm/ttm/ttm_execbuf_util.c | 6 +++--- 4 files changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c index b223c8d0a491..5d84a66fed36 100644 --- a/drivers/gpu/drm/qxl/qxl_release.c +++ b/drivers/gpu/drm/qxl/qxl_release.c @@ -458,7 +458,7 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release) trace_dma_fence_emit(&release->base); driver = bdev->driver; - glob = bo->glob; + glob = bdev->glob; spin_lock(&glob->lru_lock); diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 2bde37291e3e..fe4aef6b1a7a 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -149,7 +149,7 @@ static void ttm_bo_release_list(struct kref *list_kref) BUG_ON(!list_empty(&bo->lru)); BUG_ON(!list_empty(&bo->ddestroy)); ttm_tt_destroy(bo->ttm); - atomic_dec(&bo->glob->bo_count); + atomic_dec(&bo->bdev->glob->bo_count); dma_fence_put(bo->moving); reservation_object_fini(&bo->ttm_resv); mutex_destroy(&bo->wu_mutex); @@ -174,7 +174,7 @@ void ttm_bo_add_to_lru(struct ttm_buffer_object *bo) if (bo->ttm && !(bo->ttm->page_flags & (TTM_PAGE_FLAG_SG | TTM_PAGE_FLAG_SWAPPED))) { list_add_tail(&bo->swap, - &bo->glob->swap_lru[bo->priority]); + &bdev->glob->swap_lru[bo->priority]); kref_get(&bo->list_kref); } } @@ -205,9 +205,11 @@ void ttm_bo_del_from_lru(struct ttm_buffer_object *bo) void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo) { - spin_lock(&bo->glob->lru_lock); + struct ttm_bo_global *glob = bo->bdev->glob; + + spin_lock(&glob->lru_lock); ttm_bo_del_from_lru(bo); - spin_unlock(&bo->glob->lru_lock); + spin_unlock(&glob->lru_lock); } EXPORT_SYMBOL(ttm_bo_del_sub_from_lru); @@ -226,7 +228,7 @@ EXPORT_SYMBOL(ttm_bo_move_to_lru_tail); static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc) { struct ttm_bo_device *bdev = bo->bdev; - struct ttm_bo_global *glob = bo->glob; + struct ttm_bo_global *glob = bdev->glob; int ret = 0; uint32_t page_flags = 0; @@ -429,7 +431,7 @@ static void ttm_bo_flush_all_fences(struct ttm_buffer_object *bo) static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) { struct ttm_bo_device *bdev = bo->bdev; - struct ttm_bo_global *glob = bo->glob; + struct ttm_bo_global *glob = bdev->glob; int ret; ret = ttm_bo_individualize_resv(bo); @@ -500,7 +502,7 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool interruptible, bool no_wait_gpu, bool unlock_resv) { - struct ttm_bo_global *glob = bo->glob; + struct ttm_bo_global *glob = bo->bdev->glob; struct reservation_object *resv; int ret; @@ -1191,7 +1193,6 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, INIT_LIST_HEAD(&bo->io_reserve_lru); mutex_init(&bo->wu_mutex); bo->bdev = bdev; - bo->glob = bdev->glob; bo->type = type; bo->num_pages = num_pages; bo->mem.size = num_pages << PAGE_SHIFT; @@ -1213,7 +1214,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, bo->resv = &bo->ttm_resv; } reservation_object_init(&bo->ttm_resv); - atomic_inc(&bo->glob->bo_count); + atomic_inc(&bo->bdev->glob->bo_count); drm_vma_node_reset(&bo->vma_node); bo->priority = 0; @@ -1246,9 +1247,9 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, } if (resv && !(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) { - spin_lock(&bo->glob->lru_lock); + spin_lock(&bdev->glob->lru_lock); ttm_bo_add_to_lru(bo); - spin_unlock(&bo->glob->lru_lock); + spin_unlock(&bdev->glob->lru_lock); } return ret; diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 38da6903cae9..6d6a3f46143b 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -470,7 +470,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, * TODO: Explicit member copy would probably be better here. */ - atomic_inc(&bo->glob->bo_count); + atomic_inc(&bo->bdev->glob->bo_count); INIT_LIST_HEAD(&fbo->ddestroy); INIT_LIST_HEAD(&fbo->lru); INIT_LIST_HEAD(&fbo->swap); diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index fa44f7b15285..3dca206e85f7 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -62,7 +62,7 @@ void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket, return; entry = list_first_entry(list, struct ttm_validate_buffer, head); - glob = entry->bo->glob; + glob = entry->bo->bdev->glob; spin_lock(&glob->lru_lock); list_for_each_entry(entry, list, head) { @@ -102,7 +102,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, return 0; entry = list_first_entry(list, struct ttm_validate_buffer, head); - glob = entry->bo->glob; + glob = entry->bo->bdev->glob; if (ticket) ww_acquire_init(ticket, &reservation_ww_class); @@ -194,7 +194,7 @@ void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket, bo = list_first_entry(list, struct ttm_validate_buffer, head)->bo; bdev = bo->bdev; driver = bdev->driver; - glob = bo->glob; + glob = bo->bdev->glob; spin_lock(&glob->lru_lock); -- cgit v1.2.3 From 3231a7696e22538529e9ee3500f2116a40a22734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 21 Feb 2018 19:02:06 +0100 Subject: drm/ttm: drop ttm->glob MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pointer is available as ttm->bdev->glob as well. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/ttm/ttm_page_alloc.c | 6 +++--- drivers/gpu/drm/ttm/ttm_page_alloc_dma.c | 11 ++++++----- drivers/gpu/drm/ttm/ttm_tt.c | 2 -- 3 files changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 5edcd896cd53..2c28c4568c5f 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -1072,6 +1072,7 @@ void ttm_page_alloc_fini(void) static void ttm_pool_unpopulate_helper(struct ttm_tt *ttm, unsigned mem_count_update) { + struct ttm_mem_global *mem_glob = ttm->bdev->glob->mem_glob; unsigned i; if (mem_count_update == 0) @@ -1081,8 +1082,7 @@ ttm_pool_unpopulate_helper(struct ttm_tt *ttm, unsigned mem_count_update) if (!ttm->pages[i]) continue; - ttm_mem_global_free_page(ttm->glob->mem_glob, ttm->pages[i], - PAGE_SIZE); + ttm_mem_global_free_page(mem_glob, ttm->pages[i], PAGE_SIZE); } put_pages: @@ -1093,7 +1093,7 @@ put_pages: int ttm_pool_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx) { - struct ttm_mem_global *mem_glob = ttm->glob->mem_glob; + struct ttm_mem_global *mem_glob = ttm->bdev->glob->mem_glob; unsigned i; int ret; diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c index b122f6eee94c..3b4c97011b5c 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c @@ -929,7 +929,7 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev, struct ttm_operation_ctx *ctx) { struct ttm_tt *ttm = &ttm_dma->ttm; - struct ttm_mem_global *mem_glob = ttm->glob->mem_glob; + struct ttm_mem_global *mem_glob = ttm->bdev->glob->mem_glob; unsigned long num_pages = ttm->num_pages; struct dma_pool *pool; struct dma_page *d_page; @@ -1031,6 +1031,7 @@ EXPORT_SYMBOL_GPL(ttm_dma_populate); void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev) { struct ttm_tt *ttm = &ttm_dma->ttm; + struct ttm_mem_global *mem_glob = ttm->bdev->glob->mem_glob; struct dma_pool *pool; struct dma_page *d_page, *next; enum pool_type type; @@ -1051,8 +1052,8 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev) count++; if (d_page->vaddr & VADDR_FLAG_UPDATED_COUNT) { - ttm_mem_global_free_page(ttm->glob->mem_glob, - d_page->p, pool->size); + ttm_mem_global_free_page(mem_glob, d_page->p, + pool->size); d_page->vaddr &= ~VADDR_FLAG_UPDATED_COUNT; } ttm_dma_page_put(pool, d_page); @@ -1080,8 +1081,8 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev) count++; if (d_page->vaddr & VADDR_FLAG_UPDATED_COUNT) { - ttm_mem_global_free_page(ttm->glob->mem_glob, - d_page->p, pool->size); + ttm_mem_global_free_page(mem_glob, d_page->p, + pool->size); d_page->vaddr &= ~VADDR_FLAG_UPDATED_COUNT; } diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 65bf4eac184b..5d8f7f9b84b1 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -195,7 +195,6 @@ int ttm_tt_init(struct ttm_tt *ttm, struct ttm_bo_device *bdev, struct page *dummy_read_page) { ttm->bdev = bdev; - ttm->glob = bdev->glob; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ttm->caching_state = tt_cached; ttm->page_flags = page_flags; @@ -226,7 +225,6 @@ int ttm_dma_tt_init(struct ttm_dma_tt *ttm_dma, struct ttm_bo_device *bdev, struct ttm_tt *ttm = &ttm_dma->ttm; ttm->bdev = bdev; - ttm->glob = bdev->glob; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ttm->caching_state = tt_cached; ttm->page_flags = page_flags; -- cgit v1.2.3 From 231cdafc75434015f3925d6662a1821fcfef16b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 21 Feb 2018 20:34:13 +0100 Subject: drm/ttm: drop ttm->dummy_read_page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only used by the AGP backend and there it can be easily accessed using ttm->bdev->glob. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 5 ++--- drivers/gpu/drm/ast/ast_ttm.c | 5 ++--- drivers/gpu/drm/bochs/bochs_mm.c | 5 ++--- drivers/gpu/drm/cirrus/cirrus_ttm.c | 5 ++--- drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c | 5 ++--- drivers/gpu/drm/mgag200/mgag200_ttm.c | 5 ++--- drivers/gpu/drm/nouveau/nouveau_bo.c | 6 +++--- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 5 ++--- drivers/gpu/drm/nouveau/nouveau_ttm.h | 3 +-- drivers/gpu/drm/qxl/qxl_ttm.c | 6 ++---- drivers/gpu/drm/radeon/radeon_ttm.c | 7 +++---- drivers/gpu/drm/ttm/ttm_agp_backend.c | 8 ++++---- drivers/gpu/drm/ttm/ttm_bo.c | 6 ++---- drivers/gpu/drm/ttm/ttm_tt.c | 8 ++------ drivers/gpu/drm/virtio/virtgpu_ttm.c | 6 ++---- drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 9 +++------ drivers/staging/vboxvideo/vbox_ttm.c | 5 ++--- 17 files changed, 38 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index b372d8d650a5..e38e6db8f760 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -969,8 +969,7 @@ static struct ttm_backend_func amdgpu_backend_func = { }; static struct ttm_tt *amdgpu_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags, - struct page *dummy_read_page) + unsigned long size, uint32_t page_flags) { struct amdgpu_device *adev; struct amdgpu_ttm_tt *gtt; @@ -983,7 +982,7 @@ static struct ttm_tt *amdgpu_ttm_tt_create(struct ttm_bo_device *bdev, } gtt->ttm.ttm.func = &amdgpu_backend_func; gtt->adev = adev; - if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags, dummy_read_page)) { + if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags)) { kfree(gtt); return NULL; } diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index 68b9c5522eaa..77d2035dc7b7 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -200,8 +200,7 @@ static struct ttm_backend_func ast_tt_backend_func = { static struct ttm_tt *ast_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags, - struct page *dummy_read_page) + unsigned long size, uint32_t page_flags) { struct ttm_tt *tt; @@ -209,7 +208,7 @@ static struct ttm_tt *ast_ttm_tt_create(struct ttm_bo_device *bdev, if (tt == NULL) return NULL; tt->func = &ast_tt_backend_func; - if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) { + if (ttm_tt_init(tt, bdev, size, page_flags)) { kfree(tt); return NULL; } diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 5525b6660340..96edf005bfea 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -178,8 +178,7 @@ static struct ttm_backend_func bochs_tt_backend_func = { static struct ttm_tt *bochs_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, - uint32_t page_flags, - struct page *dummy_read_page) + uint32_t page_flags) { struct ttm_tt *tt; @@ -187,7 +186,7 @@ static struct ttm_tt *bochs_ttm_tt_create(struct ttm_bo_device *bdev, if (tt == NULL) return NULL; tt->func = &bochs_tt_backend_func; - if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) { + if (ttm_tt_init(tt, bdev, size, page_flags)) { kfree(tt); return NULL; } diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index 33798c76a64b..3413389c0fbe 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -200,8 +200,7 @@ static struct ttm_backend_func cirrus_tt_backend_func = { static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags, - struct page *dummy_read_page) + unsigned long size, uint32_t page_flags) { struct ttm_tt *tt; @@ -209,7 +208,7 @@ static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_bo_device *bdev, if (tt == NULL) return NULL; tt->func = &cirrus_tt_backend_func; - if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) { + if (ttm_tt_init(tt, bdev, size, page_flags)) { kfree(tt); return NULL; } diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c index 0c93349fbacf..50e317a2a4ca 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c @@ -202,8 +202,7 @@ static struct ttm_backend_func hibmc_tt_backend_func = { static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, - u32 page_flags, - struct page *dummy_read_page) + u32 page_flags) { struct ttm_tt *tt; int ret; @@ -214,7 +213,7 @@ static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_bo_device *bdev, return NULL; } tt->func = &hibmc_tt_backend_func; - ret = ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page); + ret = ttm_tt_init(tt, bdev, size, page_flags); if (ret) { DRM_ERROR("failed to initialize ttm_tt: %d\n", ret); kfree(tt); diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index 26e5f14645c5..cd55ff5f0f0a 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -200,8 +200,7 @@ static struct ttm_backend_func mgag200_tt_backend_func = { static struct ttm_tt *mgag200_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags, - struct page *dummy_read_page) + unsigned long size, uint32_t page_flags) { struct ttm_tt *tt; @@ -209,7 +208,7 @@ static struct ttm_tt *mgag200_ttm_tt_create(struct ttm_bo_device *bdev, if (tt == NULL) return NULL; tt->func = &mgag200_tt_backend_func; - if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) { + if (ttm_tt_init(tt, bdev, size, page_flags)) { kfree(tt); return NULL; } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 80fa68d54bd3..5c01ccfd3066 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -605,18 +605,18 @@ nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val) static struct ttm_tt * nouveau_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, - uint32_t page_flags, struct page *dummy_read) + uint32_t page_flags) { #if IS_ENABLED(CONFIG_AGP) struct nouveau_drm *drm = nouveau_bdev(bdev); if (drm->agp.bridge) { return ttm_agp_tt_create(bdev, drm->agp.bridge, size, - page_flags, dummy_read); + page_flags); } #endif - return nouveau_sgdma_create_ttm(bdev, size, page_flags, dummy_read); + return nouveau_sgdma_create_ttm(bdev, size, page_flags); } static int diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 11f6ca89769b..87b030437f4d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -83,8 +83,7 @@ static struct ttm_backend_func nv50_sgdma_backend = { struct ttm_tt * nouveau_sgdma_create_ttm(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags, - struct page *dummy_read_page) + unsigned long size, uint32_t page_flags) { struct nouveau_drm *drm = nouveau_bdev(bdev); struct nouveau_sgdma_be *nvbe; @@ -98,7 +97,7 @@ nouveau_sgdma_create_ttm(struct ttm_bo_device *bdev, else nvbe->ttm.ttm.func = &nv50_sgdma_backend; - if (ttm_dma_tt_init(&nvbe->ttm, bdev, size, page_flags, dummy_read_page)) + if (ttm_dma_tt_init(&nvbe->ttm, bdev, size, page_flags)) /* * A failing ttm_dma_tt_init() will call ttm_tt_destroy() * and thus our nouveau_sgdma_destroy() hook, so we don't need diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.h b/drivers/gpu/drm/nouveau/nouveau_ttm.h index 96082b696420..64e484ee5ef1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.h +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.h @@ -13,8 +13,7 @@ extern const struct ttm_mem_type_manager_func nouveau_gart_manager; extern const struct ttm_mem_type_manager_func nv04_gart_manager; struct ttm_tt *nouveau_sgdma_create_ttm(struct ttm_bo_device *, - unsigned long size, u32 page_flags, - struct page *dummy_read_page); + unsigned long size, u32 page_flags); int nouveau_ttm_init(struct nouveau_drm *drm); void nouveau_ttm_fini(struct nouveau_drm *drm); diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index 07d4f3fde6c1..2ad70eb96207 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -292,8 +292,7 @@ static struct ttm_backend_func qxl_backend_func = { }; static struct ttm_tt *qxl_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags, - struct page *dummy_read_page) + unsigned long size, uint32_t page_flags) { struct qxl_device *qdev; struct qxl_ttm_tt *gtt; @@ -304,8 +303,7 @@ static struct ttm_tt *qxl_ttm_tt_create(struct ttm_bo_device *bdev, return NULL; gtt->ttm.ttm.func = &qxl_backend_func; gtt->qdev = qdev; - if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags, - dummy_read_page)) { + if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags)) { kfree(gtt); return NULL; } diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index c50620aadbd0..009f55a2bbf9 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -687,8 +687,7 @@ static struct ttm_backend_func radeon_backend_func = { }; static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags, - struct page *dummy_read_page) + unsigned long size, uint32_t page_flags) { struct radeon_device *rdev; struct radeon_ttm_tt *gtt; @@ -697,7 +696,7 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev, #if IS_ENABLED(CONFIG_AGP) if (rdev->flags & RADEON_IS_AGP) { return ttm_agp_tt_create(bdev, rdev->ddev->agp->bridge, - size, page_flags, dummy_read_page); + size, page_flags); } #endif @@ -707,7 +706,7 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev, } gtt->ttm.ttm.func = &radeon_backend_func; gtt->rdev = rdev; - if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags, dummy_read_page)) { + if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags)) { kfree(gtt); return NULL; } diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c index 3e795a099d06..f7c2aefbec7c 100644 --- a/drivers/gpu/drm/ttm/ttm_agp_backend.c +++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c @@ -50,6 +50,7 @@ struct ttm_agp_backend { static int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) { struct ttm_agp_backend *agp_be = container_of(ttm, struct ttm_agp_backend, ttm); + struct page *dummy_read_page = ttm->bdev->glob->dummy_read_page; struct drm_mm_node *node = bo_mem->mm_node; struct agp_memory *mem; int ret, cached = (bo_mem->placement & TTM_PL_FLAG_CACHED); @@ -64,7 +65,7 @@ static int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) struct page *page = ttm->pages[i]; if (!page) - page = ttm->dummy_read_page; + page = dummy_read_page; mem->pages[mem->page_count++] = page; } @@ -111,8 +112,7 @@ static struct ttm_backend_func ttm_agp_func = { struct ttm_tt *ttm_agp_tt_create(struct ttm_bo_device *bdev, struct agp_bridge_data *bridge, - unsigned long size, uint32_t page_flags, - struct page *dummy_read_page) + unsigned long size, uint32_t page_flags) { struct ttm_agp_backend *agp_be; @@ -124,7 +124,7 @@ struct ttm_tt *ttm_agp_tt_create(struct ttm_bo_device *bdev, agp_be->bridge = bridge; agp_be->ttm.func = &ttm_agp_func; - if (ttm_tt_init(&agp_be->ttm, bdev, size, page_flags, dummy_read_page)) { + if (ttm_tt_init(&agp_be->ttm, bdev, size, page_flags)) { kfree(agp_be); return NULL; } diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index fe4aef6b1a7a..55028745214b 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -228,7 +228,6 @@ EXPORT_SYMBOL(ttm_bo_move_to_lru_tail); static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc) { struct ttm_bo_device *bdev = bo->bdev; - struct ttm_bo_global *glob = bdev->glob; int ret = 0; uint32_t page_flags = 0; @@ -247,14 +246,13 @@ static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc) page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC; case ttm_bo_type_kernel: bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, - page_flags, glob->dummy_read_page); + page_flags); if (unlikely(bo->ttm == NULL)) ret = -ENOMEM; break; case ttm_bo_type_sg: bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, - page_flags | TTM_PAGE_FLAG_SG, - glob->dummy_read_page); + page_flags | TTM_PAGE_FLAG_SG); if (unlikely(bo->ttm == NULL)) { ret = -ENOMEM; break; diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 5d8f7f9b84b1..f93cd108b19d 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -191,14 +191,12 @@ void ttm_tt_destroy(struct ttm_tt *ttm) } int ttm_tt_init(struct ttm_tt *ttm, struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags, - struct page *dummy_read_page) + unsigned long size, uint32_t page_flags) { ttm->bdev = bdev; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ttm->caching_state = tt_cached; ttm->page_flags = page_flags; - ttm->dummy_read_page = dummy_read_page; ttm->state = tt_unpopulated; ttm->swap_storage = NULL; @@ -219,8 +217,7 @@ void ttm_tt_fini(struct ttm_tt *ttm) EXPORT_SYMBOL(ttm_tt_fini); int ttm_dma_tt_init(struct ttm_dma_tt *ttm_dma, struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags, - struct page *dummy_read_page) + unsigned long size, uint32_t page_flags) { struct ttm_tt *ttm = &ttm_dma->ttm; @@ -228,7 +225,6 @@ int ttm_dma_tt_init(struct ttm_dma_tt *ttm_dma, struct ttm_bo_device *bdev, ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ttm->caching_state = tt_cached; ttm->page_flags = page_flags; - ttm->dummy_read_page = dummy_read_page; ttm->state = tt_unpopulated; ttm->swap_storage = NULL; diff --git a/drivers/gpu/drm/virtio/virtgpu_ttm.c b/drivers/gpu/drm/virtio/virtgpu_ttm.c index 1cde060602aa..ee9839fbae66 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ttm.c +++ b/drivers/gpu/drm/virtio/virtgpu_ttm.c @@ -326,8 +326,7 @@ static struct ttm_backend_func virtio_gpu_backend_func = { static struct ttm_tt *virtio_gpu_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, - uint32_t page_flags, - struct page *dummy_read_page) + uint32_t page_flags) { struct virtio_gpu_device *vgdev; struct virtio_gpu_ttm_tt *gtt; @@ -338,8 +337,7 @@ static struct ttm_tt *virtio_gpu_ttm_tt_create(struct ttm_bo_device *bdev, return NULL; gtt->ttm.ttm.func = &virtio_gpu_backend_func; gtt->vgdev = vgdev; - if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags, - dummy_read_page)) { + if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags)) { kfree(gtt); return NULL; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index 22231bc9e845..fead3f2dbb46 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -694,8 +694,7 @@ static struct ttm_backend_func vmw_ttm_func = { }; static struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev, - unsigned long size, uint32_t page_flags, - struct page *dummy_read_page) + unsigned long size, uint32_t page_flags) { struct vmw_ttm_tt *vmw_be; int ret; @@ -709,11 +708,9 @@ static struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev, vmw_be->mob = NULL; if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent) - ret = ttm_dma_tt_init(&vmw_be->dma_ttm, bdev, size, page_flags, - dummy_read_page); + ret = ttm_dma_tt_init(&vmw_be->dma_ttm, bdev, size, page_flags); else - ret = ttm_tt_init(&vmw_be->dma_ttm.ttm, bdev, size, page_flags, - dummy_read_page); + ret = ttm_tt_init(&vmw_be->dma_ttm.ttm, bdev, size, page_flags); if (unlikely(ret != 0)) goto out_no_init; diff --git a/drivers/staging/vboxvideo/vbox_ttm.c b/drivers/staging/vboxvideo/vbox_ttm.c index c4b7a6b9abd5..d1a211b61718 100644 --- a/drivers/staging/vboxvideo/vbox_ttm.c +++ b/drivers/staging/vboxvideo/vbox_ttm.c @@ -195,8 +195,7 @@ static struct ttm_backend_func vbox_tt_backend_func = { static struct ttm_tt *vbox_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, - u32 page_flags, - struct page *dummy_read_page) + u32 page_flags) { struct ttm_tt *tt; @@ -205,7 +204,7 @@ static struct ttm_tt *vbox_ttm_tt_create(struct ttm_bo_device *bdev, return NULL; tt->func = &vbox_tt_backend_func; - if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) { + if (ttm_tt_init(tt, bdev, size, page_flags)) { kfree(tt); return NULL; } -- cgit v1.2.3 From 724daa4fd65d927e406f2cc0661c9a329876267b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 15:52:31 +0100 Subject: drm/ttm: drop persistent_swap_storage from ttm_bo_init and co MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Never used as parameter, the only driver actually using this is nouveau and there it is initialized after the BO is initialized. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 4 ++-- drivers/gpu/drm/ast/ast_ttm.c | 2 +- drivers/gpu/drm/bochs/bochs_mm.c | 2 +- drivers/gpu/drm/cirrus/cirrus_ttm.c | 2 +- drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c | 2 +- drivers/gpu/drm/mgag200/mgag200_ttm.c | 2 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 2 +- drivers/gpu/drm/qxl/qxl_object.c | 2 +- drivers/gpu/drm/radeon/radeon_object.c | 4 ++-- drivers/gpu/drm/ttm/ttm_bo.c | 9 ++------- drivers/gpu/drm/virtio/virtgpu_object.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_mob.c | 5 ++--- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 4 ++-- drivers/staging/vboxvideo/vbox_ttm.c | 2 +- 15 files changed, 20 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index c2a4b7215c46..216799ccb545 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -418,8 +418,8 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, amdgpu_ttm_placement_from_domain(bo, domain); r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, size, type, - &bo->placement, page_align, &ctx, NULL, - acc_size, sg, resv, &amdgpu_ttm_bo_destroy); + &bo->placement, page_align, &ctx, acc_size, + sg, resv, &amdgpu_ttm_bo_destroy); if (unlikely(r != 0)) return r; diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index 77d2035dc7b7..211224f6bdd3 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -321,7 +321,7 @@ int ast_bo_create(struct drm_device *dev, int size, int align, ret = ttm_bo_init(&ast->ttm.bdev, &astbo->bo, size, ttm_bo_type_device, &astbo->placement, - align >> PAGE_SHIFT, false, NULL, acc_size, + align >> PAGE_SHIFT, false, acc_size, NULL, NULL, ast_bo_ttm_destroy); if (ret) goto error; diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 96edf005bfea..73722484e12b 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -368,7 +368,7 @@ static int bochs_bo_create(struct drm_device *dev, int size, int align, ret = ttm_bo_init(&bochs->ttm.bdev, &bochsbo->bo, size, ttm_bo_type_device, &bochsbo->placement, - align >> PAGE_SHIFT, false, NULL, acc_size, + align >> PAGE_SHIFT, false, acc_size, NULL, NULL, bochs_bo_ttm_destroy); if (ret) return ret; diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index 3413389c0fbe..6cd0233b3bf8 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -328,7 +328,7 @@ int cirrus_bo_create(struct drm_device *dev, int size, int align, ret = ttm_bo_init(&cirrus->ttm.bdev, &cirrusbo->bo, size, ttm_bo_type_device, &cirrusbo->placement, - align >> PAGE_SHIFT, false, NULL, acc_size, + align >> PAGE_SHIFT, false, acc_size, NULL, NULL, cirrus_bo_ttm_destroy); if (ret) return ret; diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c index 50e317a2a4ca..8dfffdbb6b07 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c @@ -317,7 +317,7 @@ int hibmc_bo_create(struct drm_device *dev, int size, int align, ret = ttm_bo_init(&hibmc->bdev, &hibmcbo->bo, size, ttm_bo_type_device, &hibmcbo->placement, - align >> PAGE_SHIFT, false, NULL, acc_size, + align >> PAGE_SHIFT, false, acc_size, NULL, NULL, hibmc_bo_ttm_destroy); if (ret) { hibmc_bo_unref(&hibmcbo); diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index cd55ff5f0f0a..69beb2046008 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -324,7 +324,7 @@ int mgag200_bo_create(struct drm_device *dev, int size, int align, ret = ttm_bo_init(&mdev->ttm.bdev, &mgabo->bo, size, ttm_bo_type_device, &mgabo->placement, - align >> PAGE_SHIFT, false, NULL, acc_size, + align >> PAGE_SHIFT, false, acc_size, NULL, NULL, mgag200_bo_ttm_destroy); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 5c01ccfd3066..49cc8dfcb141 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -298,7 +298,7 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align, ret = ttm_bo_init(&drm->ttm.bdev, &nvbo->bo, size, type, &nvbo->placement, - align >> PAGE_SHIFT, false, NULL, acc_size, sg, + align >> PAGE_SHIFT, false, acc_size, sg, robj, nouveau_bo_del_ttm); if (ret) { /* ttm will call nouveau_bo_del_ttm if it fails.. */ diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index f6b80fe47d1f..af62824ed4cc 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -109,7 +109,7 @@ int qxl_bo_create(struct qxl_device *qdev, qxl_ttm_placement_from_domain(bo, domain, pinned); r = ttm_bo_init(&qdev->mman.bdev, &bo->tbo, size, type, - &bo->placement, 0, !kernel, NULL, size, + &bo->placement, 0, !kernel, size, NULL, NULL, &qxl_ttm_bo_destroy); if (unlikely(r != 0)) { if (r != -ERESTARTSYS) diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 64ab11d4ea58..38431f682ed0 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -255,8 +255,8 @@ int radeon_bo_create(struct radeon_device *rdev, /* Kernel allocation are uninterruptible */ down_read(&rdev->pm.mclk_lock); r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type, - &bo->placement, page_align, !kernel, NULL, - acc_size, sg, resv, &radeon_ttm_bo_destroy); + &bo->placement, page_align, !kernel, acc_size, + sg, resv, &radeon_ttm_bo_destroy); up_read(&rdev->pm.mclk_lock); if (unlikely(r != 0)) { return r; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 55028745214b..4bfa109e2a66 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1149,7 +1149,6 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, struct ttm_placement *placement, uint32_t page_alignment, struct ttm_operation_ctx *ctx, - struct file *persistent_swap_storage, size_t acc_size, struct sg_table *sg, struct reservation_object *resv, @@ -1202,7 +1201,6 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, bo->mem.bus.io_reserved_count = 0; bo->moving = NULL; bo->mem.placement = (TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED); - bo->persistent_swap_storage = persistent_swap_storage; bo->acc_size = acc_size; bo->sg = sg; if (resv) { @@ -1261,7 +1259,6 @@ int ttm_bo_init(struct ttm_bo_device *bdev, struct ttm_placement *placement, uint32_t page_alignment, bool interruptible, - struct file *persistent_swap_storage, size_t acc_size, struct sg_table *sg, struct reservation_object *resv, @@ -1271,8 +1268,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev, int ret; ret = ttm_bo_init_reserved(bdev, bo, size, type, placement, - page_alignment, &ctx, - persistent_swap_storage, acc_size, + page_alignment, &ctx, acc_size, sg, resv, destroy); if (ret) return ret; @@ -1318,7 +1314,6 @@ int ttm_bo_create(struct ttm_bo_device *bdev, struct ttm_placement *placement, uint32_t page_alignment, bool interruptible, - struct file *persistent_swap_storage, struct ttm_buffer_object **p_bo) { struct ttm_buffer_object *bo; @@ -1331,7 +1326,7 @@ int ttm_bo_create(struct ttm_bo_device *bdev, acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct ttm_buffer_object)); ret = ttm_bo_init(bdev, bo, size, type, placement, page_alignment, - interruptible, persistent_swap_storage, acc_size, + interruptible, acc_size, NULL, NULL, NULL); if (likely(ret == 0)) *p_bo = bo; diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index 0b90cdb3d9fe..9f2f470efd9b 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -89,7 +89,7 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, virtio_gpu_init_ttm_placement(bo, pinned); ret = ttm_bo_init(&vgdev->mman.bdev, &bo->tbo, size, type, - &bo->placement, 0, !kernel, NULL, acc_size, + &bo->placement, 0, !kernel, acc_size, NULL, NULL, &virtio_gpu_ttm_bo_destroy); /* ttm_bo_init failure will call the destroy */ if (ret != 0) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index c706ad30411b..f283324ce598 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -1245,7 +1245,7 @@ int vmw_cmdbuf_set_pool_size(struct vmw_cmdbuf_man *man, return -ENOMEM; ret = ttm_bo_create(&dev_priv->bdev, size, ttm_bo_type_device, - &vmw_mob_ne_placement, 0, false, NULL, + &vmw_mob_ne_placement, 0, false, &man->cmd_space); if (ret) return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index 736ca47e28ea..d07c585e3c1d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -260,8 +260,7 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv, ret = ttm_bo_create(&dev_priv->bdev, bo_size, ttm_bo_type_device, &vmw_sys_ne_placement, - 0, false, NULL, - &batch->otable_bo); + 0, false, &batch->otable_bo); if (unlikely(ret != 0)) goto out_no_bo; @@ -444,7 +443,7 @@ static int vmw_mob_pt_populate(struct vmw_private *dev_priv, ret = ttm_bo_create(&dev_priv->bdev, mob->num_pages * PAGE_SIZE, ttm_bo_type_device, &vmw_sys_ne_placement, - 0, false, NULL, &mob->pt_bo); + 0, false, &mob->pt_bo); if (unlikely(ret != 0)) return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 200904ff9a22..9e101450cc4d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -384,8 +384,8 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv, ret = ttm_bo_init(bdev, &vmw_bo->base, size, ttm_bo_type_device, placement, - 0, interruptible, - NULL, acc_size, NULL, NULL, bo_free); + 0, interruptible, acc_size, + NULL, NULL, bo_free); return ret; } diff --git a/drivers/staging/vboxvideo/vbox_ttm.c b/drivers/staging/vboxvideo/vbox_ttm.c index d1a211b61718..2c7daa3d0f24 100644 --- a/drivers/staging/vboxvideo/vbox_ttm.c +++ b/drivers/staging/vboxvideo/vbox_ttm.c @@ -331,7 +331,7 @@ int vbox_bo_create(struct drm_device *dev, int size, int align, ret = ttm_bo_init(&vbox->ttm.bdev, &vboxbo->bo, size, ttm_bo_type_device, &vboxbo->placement, - align >> PAGE_SHIFT, false, NULL, acc_size, + align >> PAGE_SHIFT, false, acc_size, NULL, NULL, vbox_bo_ttm_destroy); if (ret) goto err_free_vboxbo; -- cgit v1.2.3 From ec3fe391bdb321b1629cfb0ddbb9fcc114b579bc Mon Sep 17 00:00:00 2001 From: Roger He Date: Mon, 5 Feb 2018 17:57:07 +0800 Subject: drm/ttm: check if free mem space is under the lower limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the free mem space and the lower limit both include two parts: system memory and swap space. For the OOM triggered by TTM, that is the case as below: first swap space is full of swapped out pages and soon system memory also is filled up with ttm pages. and then any memory allocation request will run into OOM. to cover two cases: a. if no swap disk at all or free swap space is under swap mem limit but available system mem is bigger than sys mem limit, allow TTM allocation; b. if the available system mem is less than sys mem limit but free swap space is bigger than swap mem limit, allow TTM allocation. v2: merge two memory limit(swap and system) into one v3: keep original behavior except ttm_opt_ctx->flags with TTM_OPT_FLAG_FORCE_ALLOC v4: always set force_alloc as tx->flags & TTM_OPT_FLAG_FORCE_ALLOC v5: add an attribute for lower_mem_limit v6: set lower_mem_limit as 0 to keep original behavior Signed-off-by: Roger He Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/ttm/ttm_memory.c | 93 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/ttm/ttm_page_alloc.c | 3 ++ drivers/gpu/drm/ttm/ttm_page_alloc_dma.c | 3 ++ 3 files changed, 99 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c index aa0c38136958..27856c55dc84 100644 --- a/drivers/gpu/drm/ttm/ttm_memory.c +++ b/drivers/gpu/drm/ttm/ttm_memory.c @@ -36,6 +36,7 @@ #include #include #include +#include #define TTM_MEMORY_ALLOC_RETRIES 4 @@ -166,6 +167,54 @@ static struct kobj_type ttm_mem_zone_kobj_type = { .default_attrs = ttm_mem_zone_attrs, }; +static struct attribute ttm_mem_global_lower_mem_limit = { + .name = "lower_mem_limit", + .mode = S_IRUGO | S_IWUSR +}; + +static ssize_t ttm_mem_global_show(struct kobject *kobj, + struct attribute *attr, + char *buffer) +{ + struct ttm_mem_global *glob = + container_of(kobj, struct ttm_mem_global, kobj); + uint64_t val = 0; + + spin_lock(&glob->lock); + val = glob->lower_mem_limit; + spin_unlock(&glob->lock); + /* convert from number of pages to KB */ + val <<= (PAGE_SHIFT - 10); + return snprintf(buffer, PAGE_SIZE, "%llu\n", + (unsigned long long) val); +} + +static ssize_t ttm_mem_global_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, + size_t size) +{ + int chars; + uint64_t val64; + unsigned long val; + struct ttm_mem_global *glob = + container_of(kobj, struct ttm_mem_global, kobj); + + chars = sscanf(buffer, "%lu", &val); + if (chars == 0) + return size; + + val64 = val; + /* convert from KB to number of pages */ + val64 >>= (PAGE_SHIFT - 10); + + spin_lock(&glob->lock); + glob->lower_mem_limit = val64; + spin_unlock(&glob->lock); + + return size; +} + static void ttm_mem_global_kobj_release(struct kobject *kobj) { struct ttm_mem_global *glob = @@ -174,8 +223,20 @@ static void ttm_mem_global_kobj_release(struct kobject *kobj) kfree(glob); } +static struct attribute *ttm_mem_global_attrs[] = { + &ttm_mem_global_lower_mem_limit, + NULL +}; + +static const struct sysfs_ops ttm_mem_global_ops = { + .show = &ttm_mem_global_show, + .store = &ttm_mem_global_store, +}; + static struct kobj_type ttm_mem_glob_kobj_type = { .release = &ttm_mem_global_kobj_release, + .sysfs_ops = &ttm_mem_global_ops, + .default_attrs = ttm_mem_global_attrs, }; static bool ttm_zones_above_swap_target(struct ttm_mem_global *glob, @@ -375,6 +436,9 @@ int ttm_mem_global_init(struct ttm_mem_global *glob) si_meminfo(&si); + /* set it as 0 by default to keep original behavior of OOM */ + glob->lower_mem_limit = 0; + ret = ttm_mem_init_kernel_zone(glob, &si); if (unlikely(ret != 0)) goto out_no_zone; @@ -469,6 +533,35 @@ void ttm_mem_global_free(struct ttm_mem_global *glob, } EXPORT_SYMBOL(ttm_mem_global_free); +/* + * check if the available mem is under lower memory limit + * + * a. if no swap disk at all or free swap space is under swap_mem_limit + * but available system mem is bigger than sys_mem_limit, allow TTM + * allocation; + * + * b. if the available system mem is less than sys_mem_limit but free + * swap disk is bigger than swap_mem_limit, allow TTM allocation. + */ +bool +ttm_check_under_lowerlimit(struct ttm_mem_global *glob, + uint64_t num_pages, + struct ttm_operation_ctx *ctx) +{ + int64_t available; + + if (ctx->flags & TTM_OPT_FLAG_FORCE_ALLOC) + return false; + + available = get_nr_swap_pages() + si_mem_available(); + available -= num_pages; + if (available < glob->lower_mem_limit) + return true; + + return false; +} +EXPORT_SYMBOL(ttm_check_under_lowerlimit); + static int ttm_mem_global_reserve(struct ttm_mem_global *glob, struct ttm_mem_zone *single_zone, uint64_t amount, bool reserve) diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 2c28c4568c5f..f0481b7b60c5 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -1100,6 +1100,9 @@ int ttm_pool_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx) if (ttm->state != tt_unpopulated) return 0; + if (ttm_check_under_lowerlimit(mem_glob, ttm->num_pages, ctx)) + return -ENOMEM; + ret = ttm_get_pages(ttm->pages, ttm->num_pages, ttm->page_flags, ttm->caching_state); if (unlikely(ret != 0)) { diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c index 3b4c97011b5c..8a25d1974385 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c @@ -940,6 +940,9 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev, if (ttm->state != tt_unpopulated) return 0; + if (ttm_check_under_lowerlimit(mem_glob, num_pages, ctx)) + return -ENOMEM; + INIT_LIST_HEAD(&ttm_dma->pages_list); i = 0; -- cgit v1.2.3 From 97b7e1b8b55d5696093b4ebddb9dad63813bdcf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 08:54:57 +0100 Subject: drm/ttm: move ttm_tt_create into ttm_tt.c v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename ttm_bo_add_ttm to ttm_tt_create and move it into ttm_tt.c. v2: separate the cleanup. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Reviewed-by: Roger He Signed-off-by: Alex Deucher --- drivers/gpu/drm/ttm/ttm_bo.c | 50 ++------------------------------------------ drivers/gpu/drm/ttm/ttm_tt.c | 46 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 4bfa109e2a66..ad142a92eb80 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -222,52 +222,6 @@ void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo) } EXPORT_SYMBOL(ttm_bo_move_to_lru_tail); -/* - * Call bo->mutex locked. - */ -static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc) -{ - struct ttm_bo_device *bdev = bo->bdev; - int ret = 0; - uint32_t page_flags = 0; - - reservation_object_assert_held(bo->resv); - bo->ttm = NULL; - - if (bdev->need_dma32) - page_flags |= TTM_PAGE_FLAG_DMA32; - - if (bdev->no_retry) - page_flags |= TTM_PAGE_FLAG_NO_RETRY; - - switch (bo->type) { - case ttm_bo_type_device: - if (zero_alloc) - page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC; - case ttm_bo_type_kernel: - bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, - page_flags); - if (unlikely(bo->ttm == NULL)) - ret = -ENOMEM; - break; - case ttm_bo_type_sg: - bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, - page_flags | TTM_PAGE_FLAG_SG); - if (unlikely(bo->ttm == NULL)) { - ret = -ENOMEM; - break; - } - bo->ttm->sg = bo->sg; - break; - default: - pr_err("Illegal buffer object type\n"); - ret = -EINVAL; - break; - } - - return ret; -} - static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem, bool evict, struct ttm_operation_ctx *ctx) @@ -295,7 +249,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) { if (bo->ttm == NULL) { bool zero = !(old_man->flags & TTM_MEMTYPE_FLAG_FIXED); - ret = ttm_bo_add_ttm(bo, zero); + ret = ttm_tt_create(bo, zero); if (ret) goto out_err; } @@ -1134,7 +1088,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, * We might need to add a TTM. */ if (bo->mem.mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { - ret = ttm_bo_add_ttm(bo, true); + ret = ttm_tt_create(bo, true); if (ret) return ret; } diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index f93cd108b19d..917942d03047 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -47,6 +47,52 @@ #include #endif +/** + * Allocates a ttm structure for the given BO. + */ +int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) +{ + struct ttm_bo_device *bdev = bo->bdev; + int ret = 0; + uint32_t page_flags = 0; + + reservation_object_assert_held(bo->resv); + bo->ttm = NULL; + + if (bdev->need_dma32) + page_flags |= TTM_PAGE_FLAG_DMA32; + + if (bdev->no_retry) + page_flags |= TTM_PAGE_FLAG_NO_RETRY; + + switch (bo->type) { + case ttm_bo_type_device: + if (zero_alloc) + page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC; + case ttm_bo_type_kernel: + bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, + page_flags); + if (unlikely(bo->ttm == NULL)) + ret = -ENOMEM; + break; + case ttm_bo_type_sg: + bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, + page_flags | TTM_PAGE_FLAG_SG); + if (unlikely(bo->ttm == NULL)) { + ret = -ENOMEM; + break; + } + bo->ttm->sg = bo->sg; + break; + default: + pr_err("Illegal buffer object type\n"); + ret = -EINVAL; + break; + } + + return ret; +} + /** * Allocates storage for pointers to the pages that back the ttm. */ -- cgit v1.2.3 From 45a9d154f61519b64c95bf27ef341e0b50931998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 22 Feb 2018 08:54:57 +0100 Subject: drm/ttm: cleanup ttm_tt_create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanup ttm_tt_create a bit. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Reviewed-by: Roger He Signed-off-by: Alex Deucher --- drivers/gpu/drm/ttm/ttm_tt.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 917942d03047..0ee3b8f11605 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -53,11 +53,9 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) { struct ttm_bo_device *bdev = bo->bdev; - int ret = 0; uint32_t page_flags = 0; reservation_object_assert_held(bo->resv); - bo->ttm = NULL; if (bdev->need_dma32) page_flags |= TTM_PAGE_FLAG_DMA32; @@ -69,28 +67,27 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) case ttm_bo_type_device: if (zero_alloc) page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC; + break; case ttm_bo_type_kernel: - bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, - page_flags); - if (unlikely(bo->ttm == NULL)) - ret = -ENOMEM; break; case ttm_bo_type_sg: - bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, - page_flags | TTM_PAGE_FLAG_SG); - if (unlikely(bo->ttm == NULL)) { - ret = -ENOMEM; - break; - } - bo->ttm->sg = bo->sg; + page_flags |= TTM_PAGE_FLAG_SG; break; default: + bo->ttm = NULL; pr_err("Illegal buffer object type\n"); - ret = -EINVAL; - break; + return -EINVAL; } - return ret; + bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, + page_flags); + if (unlikely(bo->ttm == NULL)) + return -ENOMEM; + + if (bo->type == ttm_bo_type_sg) + bo->ttm->sg = bo->sg; + + return 0; } /** -- cgit v1.2.3 From 585b7f161c85bd5ca675b97580faf21c506541e3 Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Mon, 26 Feb 2018 09:09:26 -0500 Subject: drm/amd/amdgpu: Correct VRAM width for APUs with GMC9 DDR4 has a 64-bit width not 128-bits. It was reporting twice the width. Tested with my Ryzen 2400G. Signed-off-by: Tom St Denis Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index bc4bd5e7ac94..4dd469188e2b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -722,7 +722,10 @@ static int gmc_v9_0_mc_init(struct amdgpu_device *adev) adev->gmc.vram_width = amdgpu_atomfirmware_get_vram_width(adev); if (!adev->gmc.vram_width) { /* hbm memory channel size */ - chansize = 128; + if (adev->flags & AMD_IS_APU) + chansize = 64; + else + chansize = 128; tmp = RREG32_SOC15(DF, 0, mmDF_CS_AON0_DramBaseAddress0); tmp &= DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK; -- cgit v1.2.3 From 2e7cbbbcf9a0c3492a919bf25921437c9e1342db Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 26 Feb 2018 13:34:13 -0500 Subject: drm/amdgpu/powerplay/smu7: use proper dep table for mclk For mclk od, use the vdd dependency on mclk table. Looks like a cut and paste typo. Reviewed-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c | 2 +- drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c | 2 +- drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c index 9d5ccdbc391d..047b2dfd89e2 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c @@ -1205,7 +1205,7 @@ static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr, phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; if (hwmgr->od_enabled) - vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk; + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_mclk; else vdd_dep_table = table_info->vdd_dep_on_mclk; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c index bfb2c85d3c60..1f4e90c41456 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c @@ -1112,7 +1112,7 @@ static int polaris10_populate_single_memory_level(struct pp_hwmgr *hwmgr, cgs_get_active_displays_info(hwmgr->device, &info); if (hwmgr->od_enabled) - vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk; + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_mclk; else vdd_dep_table = table_info->vdd_dep_on_mclk; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c index 97404a578542..9e98c1dff5c4 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c @@ -969,7 +969,7 @@ static int tonga_populate_single_memory_level( phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; if (hwmgr->od_enabled) - vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk; + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_mclk; else vdd_dep_table = pptable_info->vdd_dep_on_mclk; -- cgit v1.2.3 From 9a191b114906457c4b2494c474f58ae4142d4e67 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 21 Feb 2018 11:50:03 +1000 Subject: virtio-gpu: fix ioctl and expose the fixed status to userspace. This exposes to mesa that it can use the fixed ioctl for querying later cap sets, cap set 1 is forever frozen in time. Signed-off-by: Dave Airlie Link: http://patchwork.freedesktop.org/patch/msgid/20180221015003.22884-1-airlied@gmail.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 5720a0d4ac0a..677ac16c8a6d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -197,6 +197,9 @@ static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data, case VIRTGPU_PARAM_3D_FEATURES: value = vgdev->has_virgl_3d == true ? 1 : 0; break; + case VIRTGPU_PARAM_CAPSET_QUERY_FIX: + value = 1; + break; default: return -EINVAL; } @@ -472,7 +475,7 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, { struct virtio_gpu_device *vgdev = dev->dev_private; struct drm_virtgpu_get_caps *args = data; - int size; + unsigned size, host_caps_size; int i; int found_valid = -1; int ret; @@ -481,6 +484,10 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, if (vgdev->num_capsets == 0) return -ENOSYS; + /* don't allow userspace to pass 0 */ + if (args->size == 0) + return -EINVAL; + spin_lock(&vgdev->display_info_lock); for (i = 0; i < vgdev->num_capsets; i++) { if (vgdev->capsets[i].id == args->cap_set_id) { @@ -496,11 +503,9 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, return -EINVAL; } - size = vgdev->capsets[found_valid].max_size; - if (args->size > size) { - spin_unlock(&vgdev->display_info_lock); - return -EINVAL; - } + host_caps_size = vgdev->capsets[found_valid].max_size; + /* only copy to user the minimum of the host caps size or the guest caps size */ + size = min(args->size, host_caps_size); list_for_each_entry(cache_ent, &vgdev->cap_cache, head) { if (cache_ent->id == args->cap_set_id && -- cgit v1.2.3 From 1858b85606ccf6705018452873600f3aa2948906 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 22 Feb 2018 20:59:47 -0300 Subject: drm/virtio: Add tabs at the start of a line This patch fixes the checkpatch.pl errors: drivers/gpu/drm/virtio/virtgpu_drv.h:371: ERROR: code indent should use tabs where possible ... Signed-off-by: Rodrigo Siqueira Reviewed-by: Gurchetan Singh Link: http://patchwork.freedesktop.org/patch/msgid/1c77c233d4454ee2bdb85beaf17d413e310fac0a.1519343668.git.rodrigosiqueiramelo@gmail.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_display.c | 2 +- drivers/gpu/drm/virtio/virtgpu_drv.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 19114a3c5ee4..22513d7f895c 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -387,7 +387,7 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev) for (i = 0 ; i < vgdev->num_scanouts; ++i) vgdev_output_init(vgdev, i); - drm_mode_config_reset(vgdev->ddev); + drm_mode_config_reset(vgdev->ddev); return 0; } diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index da2fb585fea4..59801728cfeb 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -363,12 +363,12 @@ int virtgpu_gem_prime_pin(struct drm_gem_object *obj); void virtgpu_gem_prime_unpin(struct drm_gem_object *obj); struct sg_table *virtgpu_gem_prime_get_sg_table(struct drm_gem_object *obj); struct drm_gem_object *virtgpu_gem_prime_import_sg_table( - struct drm_device *dev, struct dma_buf_attachment *attach, - struct sg_table *sgt); + struct drm_device *dev, struct dma_buf_attachment *attach, + struct sg_table *sgt); void *virtgpu_gem_prime_vmap(struct drm_gem_object *obj); void virtgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); int virtgpu_gem_prime_mmap(struct drm_gem_object *obj, - struct vm_area_struct *vma); + struct vm_area_struct *vma); static inline struct virtio_gpu_object* virtio_gpu_object_ref(struct virtio_gpu_object *bo) -- cgit v1.2.3 From 9d492b6bece4ecce096894153005fa2bb31f911f Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 22 Feb 2018 21:00:00 -0300 Subject: drm/virtio: Add blank line after variable declarations This patch fixes the checkpatch.pl warnings: virtgpu_drv.c:57: WARNING: Missing a blank line after declarations virtgpu_display.c:99: WARNING: Missing a blank line after declarations ... Signed-off-by: Rodrigo Siqueira Reviewed-by: Gurchetan Singh Link: http://patchwork.freedesktop.org/patch/msgid/41767852ff9dc584c825e32db6222b9a311603b9.1519343668.git.rodrigosiqueiramelo@gmail.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_display.c | 1 + drivers/gpu/drm/virtio/virtgpu_drv.c | 1 + drivers/gpu/drm/virtio/virtgpu_fb.c | 4 ++++ drivers/gpu/drm/virtio/virtgpu_gem.c | 1 + drivers/gpu/drm/virtio/virtgpu_ioctl.c | 2 ++ drivers/gpu/drm/virtio/virtgpu_vq.c | 3 +++ 6 files changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 22513d7f895c..2d1b25630c0e 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -96,6 +96,7 @@ virtio_gpu_framebuffer_init(struct drm_device *dev, { int ret; struct virtio_gpu_object *bo; + vgfb->obj = obj; bo = gem_to_virtio_gpu_obj(obj); diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 49a3d8d5a249..5d21433b1cdf 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -54,6 +54,7 @@ static int virtio_gpu_probe(struct virtio_device *vdev) static void virtio_gpu_remove(struct virtio_device *vdev) { struct drm_device *dev = vdev->priv; + drm_put_dev(dev); } diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c index 15d18fd0c64b..b933cbba0685 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fb.c +++ b/drivers/gpu/drm/virtio/virtgpu_fb.c @@ -127,6 +127,7 @@ int virtio_gpu_surface_dirty(struct virtio_gpu_framebuffer *vgfb, int left, right, top, bottom; int i; int inc = 1; + if (!num_clips) { num_clips = 1; clips = &norect; @@ -172,6 +173,7 @@ static void virtio_gpu_3d_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct virtio_gpu_fbdev *vfbdev = info->par; + drm_fb_helper_sys_fillrect(info, rect); virtio_gpu_dirty_update(&vfbdev->vgfb, true, rect->dx, rect->dy, rect->width, rect->height); @@ -182,6 +184,7 @@ static void virtio_gpu_3d_copyarea(struct fb_info *info, const struct fb_copyarea *area) { struct virtio_gpu_fbdev *vfbdev = info->par; + drm_fb_helper_sys_copyarea(info, area); virtio_gpu_dirty_update(&vfbdev->vgfb, true, area->dx, area->dy, area->width, area->height); @@ -192,6 +195,7 @@ static void virtio_gpu_3d_imageblit(struct fb_info *info, const struct fb_image *image) { struct virtio_gpu_fbdev *vfbdev = info->par; + drm_fb_helper_sys_imageblit(info, image); virtio_gpu_dirty_update(&vfbdev->vgfb, true, image->dx, image->dy, image->width, image->height); diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c index 92fb27753b9e..0f2768eacaee 100644 --- a/drivers/gpu/drm/virtio/virtgpu_gem.c +++ b/drivers/gpu/drm/virtio/virtgpu_gem.c @@ -124,6 +124,7 @@ int virtio_gpu_mode_dumb_mmap(struct drm_file *file_priv, { struct drm_gem_object *gobj; struct virtio_gpu_object *obj; + BUG_ON(!offset_p); gobj = drm_gem_object_lookup(file_priv, handle); if (gobj == NULL) diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 355569a9b5cb..7fe04537fb8c 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -83,6 +83,7 @@ static void virtio_gpu_unref_list(struct list_head *head) struct ttm_validate_buffer *buf; struct ttm_buffer_object *bo; struct virtio_gpu_object *qobj; + list_for_each_entry(buf, head, head) { bo = buf->bo; qobj = container_of(bo, struct virtio_gpu_object, tbo); @@ -478,6 +479,7 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, int ret; struct virtio_gpu_drv_cap_cache *cache_ent; void *ptr; + if (vgdev->num_capsets == 0) return -ENOSYS; diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 9eb96fb2c147..16c05bc34bef 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -62,6 +62,7 @@ void virtio_gpu_ctrl_ack(struct virtqueue *vq) { struct drm_device *dev = vq->vdev->priv; struct virtio_gpu_device *vgdev = dev->dev_private; + schedule_work(&vgdev->ctrlq.dequeue_work); } @@ -69,6 +70,7 @@ void virtio_gpu_cursor_ack(struct virtqueue *vq) { struct drm_device *dev = vq->vdev->priv; struct virtio_gpu_device *vgdev = dev->dev_private; + schedule_work(&vgdev->cursorq.dequeue_work); } @@ -852,6 +854,7 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, if (!obj->pages) { int ret; + ret = virtio_gpu_object_get_sg_table(vgdev, obj); if (ret) return ret; -- cgit v1.2.3 From 5d883850dc23a52960b3633ca119dcf2413477ae Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 22 Feb 2018 21:00:17 -0300 Subject: drm/virtio: Add */ in block comments to separate line This patch fixes the checkpatch.pl warning: virtgpu_ioctl.c:551: WARNING: Block comments use a trailing */ on a separate line ... Signed-off-by: Rodrigo Siqueira Reviewed-by: Gurchetan Singh Link: http://patchwork.freedesktop.org/patch/msgid/f0bd4104a7d26bf7561c3a2b4632041c5411f1f2.1519343668.git.rodrigosiqueiramelo@gmail.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 3 ++- drivers/gpu/drm/virtio/virtgpu_prime.c | 3 ++- drivers/gpu/drm/virtio/virtgpu_vq.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 7fe04537fb8c..684f443ec7ef 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -550,7 +550,8 @@ struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = { DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), /* make transfer async to the main ring? - no sure, can we - thread these in the underlying GL */ + * thread these in the underlying GL + */ DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_FROM_HOST, virtio_gpu_transfer_from_host_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), diff --git a/drivers/gpu/drm/virtio/virtgpu_prime.c b/drivers/gpu/drm/virtio/virtgpu_prime.c index 385e0eb9826a..6c6e9dbab096 100644 --- a/drivers/gpu/drm/virtio/virtgpu_prime.c +++ b/drivers/gpu/drm/virtio/virtgpu_prime.c @@ -25,7 +25,8 @@ #include "virtgpu_drv.h" /* Empty Implementations as there should not be any other driver for a virtual - * device that might share buffers with virtgpu */ + * device that might share buffers with virtgpu + */ int virtgpu_gem_prime_pin(struct drm_gem_object *obj) { diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 16c05bc34bef..809d20eb6571 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -383,7 +383,8 @@ retry: } /* just create gem objects for userspace and long lived objects, - just use dma_alloced pages for the queue objects? */ + * just use dma_alloced pages for the queue objects? + */ /* create a basic resource */ void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev, -- cgit v1.2.3 From 1a5019f125038817b585f1703823cac256c11a66 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 22 Feb 2018 21:00:33 -0300 Subject: drm/virtio: Remove return from void function This patch fixes the checkpatch.pl warning: virtgpu_ttm.c:181: WARNING: void function return statements are not generally useful ... Signed-off-by: Rodrigo Siqueira Reviewed-by: Gurchetan Singh Link: http://patchwork.freedesktop.org/patch/msgid/fd8dc6599c81c7aec6753c8552c1cabb7baa7577.1519343668.git.rodrigosiqueiramelo@gmail.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_ttm.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_ttm.c b/drivers/gpu/drm/virtio/virtgpu_ttm.c index 36655b709eb2..cd4a17a1409a 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ttm.c +++ b/drivers/gpu/drm/virtio/virtgpu_ttm.c @@ -177,7 +177,6 @@ static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem) { mem->mm_node = (void *)NULL; - return; } static int ttm_bo_man_init(struct ttm_mem_type_manager *man, @@ -244,7 +243,6 @@ static void virtio_gpu_evict_flags(struct ttm_buffer_object *bo, placement->busy_placement = &placements; placement->num_placement = 1; placement->num_busy_placement = 1; - return; } static int virtio_gpu_verify_access(struct ttm_buffer_object *bo, -- cgit v1.2.3 From dc31b3b76c8a7be9728cd0771a1f17fb896f85b8 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 22 Feb 2018 21:00:45 -0300 Subject: drm/virtio: Replace 'unsigned' for 'unsigned int' This patch fixes the checkpatch.pl warning: drivers/gpu/drm/virtio/virtgpu_display.c:64: WARNING: Prefer 'unsigned int' to bare use of 'unsigned' ... Signed-off-by: Rodrigo Siqueira Reviewed-by: Gurchetan Singh Link: http://patchwork.freedesktop.org/patch/msgid/ac9c4110785e6519801d44c57d4f05c3e0cdad53.1519343668.git.rodrigosiqueiramelo@gmail.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_display.c | 4 ++-- drivers/gpu/drm/virtio/virtgpu_drv.h | 2 +- drivers/gpu/drm/virtio/virtgpu_fb.c | 2 +- drivers/gpu/drm/virtio/virtgpu_ttm.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 2d1b25630c0e..8cc8c34d67f5 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -61,9 +61,9 @@ static void virtio_gpu_user_framebuffer_destroy(struct drm_framebuffer *fb) static int virtio_gpu_framebuffer_surface_dirty(struct drm_framebuffer *fb, struct drm_file *file_priv, - unsigned flags, unsigned color, + unsigned int flags, unsigned int color, struct drm_clip_rect *clips, - unsigned num_clips) + unsigned int num_clips) { struct virtio_gpu_framebuffer *virtio_gpu_fb = to_virtio_gpu_framebuffer(fb); diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 59801728cfeb..d25c8ca224aa 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -246,7 +246,7 @@ int virtio_gpu_fbdev_init(struct virtio_gpu_device *vgdev); void virtio_gpu_fbdev_fini(struct virtio_gpu_device *vgdev); int virtio_gpu_surface_dirty(struct virtio_gpu_framebuffer *qfb, struct drm_clip_rect *clips, - unsigned num_clips); + unsigned int num_clips); /* virtio vg */ int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev); void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev); diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c index b933cbba0685..8af69ab58b89 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fb.c +++ b/drivers/gpu/drm/virtio/virtgpu_fb.c @@ -118,7 +118,7 @@ static int virtio_gpu_dirty_update(struct virtio_gpu_framebuffer *fb, int virtio_gpu_surface_dirty(struct virtio_gpu_framebuffer *vgfb, struct drm_clip_rect *clips, - unsigned num_clips) + unsigned int num_clips) { struct virtio_gpu_device *vgdev = vgfb->base.dev->dev_private; struct virtio_gpu_object *obj = gem_to_virtio_gpu_obj(vgfb->obj); diff --git a/drivers/gpu/drm/virtio/virtgpu_ttm.c b/drivers/gpu/drm/virtio/virtgpu_ttm.c index cd4a17a1409a..580323ceeb8a 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ttm.c +++ b/drivers/gpu/drm/virtio/virtgpu_ttm.c @@ -224,7 +224,7 @@ static int virtio_gpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->default_caching = TTM_PL_FLAG_CACHED; break; default: - DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); + DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type); return -EINVAL; } return 0; -- cgit v1.2.3 From 601030e262c3840200178139b2fff99f9cfca151 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 22 Feb 2018 21:00:57 -0300 Subject: drm/virtio: Remove multiple blank lines This patch fixes the checkpatch.pl check: virtgpu_drv.c:116: CHECK: Please don't use multiple blank lines virtgpu_vq.c:599: CHECK: Please don't use multiple blank lines virtgpu_prime.c:42: CHECK: Please don't use multiple blank lines Signed-off-by: Rodrigo Siqueira Reviewed-by: Gurchetan Singh Link: http://patchwork.freedesktop.org/patch/msgid/c43a006f2ed93a16fe824b4a2686a2d5e2ef56f5.1519343668.git.rodrigosiqueiramelo@gmail.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_drv.c | 1 - drivers/gpu/drm/virtio/virtgpu_prime.c | 1 - drivers/gpu/drm/virtio/virtgpu_vq.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 5d21433b1cdf..d9287c144fe5 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -113,7 +113,6 @@ static const struct file_operations virtio_gpu_driver_fops = { .llseek = noop_llseek, }; - static struct drm_driver driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC, .load = virtio_gpu_driver_load, diff --git a/drivers/gpu/drm/virtio/virtgpu_prime.c b/drivers/gpu/drm/virtio/virtgpu_prime.c index 6c6e9dbab096..d27a1688714f 100644 --- a/drivers/gpu/drm/virtio/virtgpu_prime.c +++ b/drivers/gpu/drm/virtio/virtgpu_prime.c @@ -39,7 +39,6 @@ void virtgpu_gem_prime_unpin(struct drm_gem_object *obj) WARN_ONCE(1, "not implemented"); } - struct sg_table *virtgpu_gem_prime_get_sg_table(struct drm_gem_object *obj) { WARN_ONCE(1, "not implemented"); diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 809d20eb6571..18c78a7fa044 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -596,7 +596,6 @@ static void virtio_gpu_cmd_capset_cb(struct virtio_gpu_device *vgdev, wake_up(&vgdev->resp_wq); } - int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev) { struct virtio_gpu_ctrl_hdr *cmd_p; -- cgit v1.2.3 From dbe37dc31c7177f60518320e8f92cb337ad107dc Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 22 Feb 2018 21:01:10 -0300 Subject: drm/virtio: Add spaces around operators This patch fixes the checkpatch.pl check: virtgpu_ioctl.c:535: CHECK: spaces preferred around that '|' (ctx:VxV) virtgpu_vq.c:277: CHECK: spaces preferred around that '+' (ctx:VxV) ... Signed-off-by: Rodrigo Siqueira Reviewed-by: Gurchetan Singh Link: http://patchwork.freedesktop.org/patch/msgid/8402b55696b44483ba2e1f6aaeb53bf709ffbfe7.1519343668.git.rodrigosiqueiramelo@gmail.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 18 +++++++++--------- drivers/gpu/drm/virtio/virtgpu_vq.c | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 684f443ec7ef..a14e8a2ec682 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -534,34 +534,34 @@ copy_exit: struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = { DRM_IOCTL_DEF_DRV(VIRTGPU_MAP, virtio_gpu_map_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIRTGPU_EXECBUFFER, virtio_gpu_execbuffer_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIRTGPU_GETPARAM, virtio_gpu_getparam_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_CREATE, virtio_gpu_resource_create_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_INFO, virtio_gpu_resource_info_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), /* make transfer async to the main ring? - no sure, can we * thread these in the underlying GL */ DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_FROM_HOST, virtio_gpu_transfer_from_host_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_TO_HOST, virtio_gpu_transfer_to_host_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIRTGPU_WAIT, virtio_gpu_wait_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIRTGPU_GET_CAPS, virtio_gpu_get_caps_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), }; diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 18c78a7fa044..48e4f1df6e5d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -274,7 +274,7 @@ static int virtio_gpu_queue_ctrl_buffer_locked(struct virtio_gpu_device *vgdev, return -ENODEV; sg_init_one(&vcmd, vbuf->buf, vbuf->size); - sgs[outcnt+incnt] = &vcmd; + sgs[outcnt + incnt] = &vcmd; outcnt++; if (vbuf->data_size) { @@ -709,8 +709,8 @@ void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id, cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_CTX_CREATE); cmd_p->hdr.ctx_id = cpu_to_le32(id); cmd_p->nlen = cpu_to_le32(nlen); - strncpy(cmd_p->debug_name, name, sizeof(cmd_p->debug_name)-1); - cmd_p->debug_name[sizeof(cmd_p->debug_name)-1] = 0; + strncpy(cmd_p->debug_name, name, sizeof(cmd_p->debug_name) - 1); + cmd_p->debug_name[sizeof(cmd_p->debug_name) - 1] = 0; virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); } -- cgit v1.2.3 From 6662ae6af82df10259a70c7569b4c12ea7f3ba93 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 21 Feb 2018 09:11:00 +0100 Subject: gpiolib: Keep returning EPROBE_DEFER when we should Commits c85823390215 ("gpio: of: Support SPI nonstandard GPIO properties") and 6a537d48461d ("gpio: of: Support regulator nonstandard GPIO properties") have introduced a regression in the way error codes from of_get_named_gpiod_flags are handled. Previously, those errors codes were returned immediately, but the two commits mentioned above are now overwriting the error pointer, meaning that whatever value has been returned will be dropped in favor of whatever the two new functions will return. This might not be a big deal except for EPROBE_DEFER, on which GPIOlib customers will depend on, and that will now be returned as an hard error which means that they will not probe anymore, instead of gently deferring their probe. Since EPROBE_DEFER basically means that we have found a valid property but there was no GPIO controller registered to handle it, fix this issues by returning it as soon as we encounter it. Fixes: c85823390215 ("gpio: of: Support SPI nonstandard GPIO properties") Fixes: 6a537d48461d ("gpio: of: Support regulator nonstandard GPIO properties") Signed-off-by: Maxime Ripard [Fold in fix to the fix] Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 564bb7a31da4..0ee5dc70268a 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -241,6 +241,19 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, &of_flags); + /* + * -EPROBE_DEFER in our case means that we found a + * valid GPIO property, but no controller has been + * registered so far. + * + * This means we don't need to look any further for + * alternate name conventions, and we should really + * preserve the return code for our user to be able to + * retry probing later. + */ + if (IS_ERR(desc) && PTR_ERR(desc) == -EPROBE_DEFER) + return desc; + if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT)) break; } -- cgit v1.2.3 From ce27fb2c56db6ccfe8099343bb4afdab15e77e7b Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 13 Feb 2018 14:08:14 +0800 Subject: gpio: Handle deferred probing in of_find_gpio() properly of_get_named_gpiod_flags() used directly in of_find_gpio() or indirectly through of_find_spi_gpio() or of_find_regulator_gpio() can return -EPROBE_DEFER. This gets overwritten by the subsequent of_find_*_gpio() calls. This patch fixes this by trying of_find_spi_gpio() or of_find_regulator_gpio() only if deferred probing was not requested by the previous of_get_named_gpiod_flags() call. Fixes: 6a537d48461d ("gpio: of: Support regulator nonstandard GPIO properties") Fixes: c85823390215 ("gpio: of: Support SPI nonstandard GPIO properties") Signed-off-by: Chen-Yu Tsai [Augmented to fit with Maxime's patch] Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 0ee5dc70268a..84e5a9df2344 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -263,7 +263,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, desc = of_find_spi_gpio(dev, con_id, &of_flags); /* Special handling for regulator GPIOs if used */ - if (IS_ERR(desc)) + if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER) desc = of_find_regulator_gpio(dev, con_id, &of_flags); if (IS_ERR(desc)) -- cgit v1.2.3 From f8870ae6e2d6be75b1accc2db981169fdfbea7ab Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 14 Feb 2018 15:57:43 +0200 Subject: mmc: sdhci-pci: Fix S0i3 for Intel BYT-based controllers Tuning can leave the IP in an active state (Buffer Read Enable bit set) which prevents the entry to low power states (i.e. S0i3). Data reset will clear it. Generally tuning is followed by a data transfer which will anyway sort out the state, so it is rare that S0i3 is actually prevented. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 6d1a983e6227..82c4f05f91d8 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -654,9 +654,36 @@ static void byt_read_dsm(struct sdhci_pci_slot *slot) slot->chip->rpm_retune = intel_host->d3_retune; } -static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) +static int intel_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + int err = sdhci_execute_tuning(mmc, opcode); + struct sdhci_host *host = mmc_priv(mmc); + + if (err) + return err; + + /* + * Tuning can leave the IP in an active state (Buffer Read Enable bit + * set) which prevents the entry to low power states (i.e. S0i3). Data + * reset will clear it. + */ + sdhci_reset(host, SDHCI_RESET_DATA); + + return 0; +} + +static void byt_probe_slot(struct sdhci_pci_slot *slot) { + struct mmc_host_ops *ops = &slot->host->mmc_host_ops; + byt_read_dsm(slot); + + ops->execute_tuning = intel_execute_tuning; +} + +static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) +{ + byt_probe_slot(slot); slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | MMC_CAP_CMD_DURING_TFR | @@ -779,7 +806,7 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot) { int err; - byt_read_dsm(slot); + byt_probe_slot(slot); err = ni_set_max_freq(slot); if (err) @@ -792,7 +819,7 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot) static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) { - byt_read_dsm(slot); + byt_probe_slot(slot); slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE | MMC_CAP_WAIT_WHILE_BUSY; return 0; @@ -800,7 +827,7 @@ static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) { - byt_read_dsm(slot); + byt_probe_slot(slot); slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_AGGRESSIVE_PM | MMC_CAP_CD_WAKE; slot->cd_idx = 0; -- cgit v1.2.3 From 325501d9360eb42c7c51e6daa0d733844c1e790b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 13:44:19 +0100 Subject: mmc: dw_mmc-k3: Fix out-of-bounds access through DT alias The hs_timing_cfg[] array is indexed using a value derived from the "mshcN" alias in DT, which may lead to an out-of-bounds access. Fix this by adding a range check. Fixes: 361c7fe9b02eee7e ("mmc: dw_mmc-k3: add sd support for hi3660") Signed-off-by: Geert Uytterhoeven Reviewed-by: Shawn Lin Cc: Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-k3.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c index 73fd75c3c824..75ae5803b0db 100644 --- a/drivers/mmc/host/dw_mmc-k3.c +++ b/drivers/mmc/host/dw_mmc-k3.c @@ -135,6 +135,9 @@ static int dw_mci_hi6220_parse_dt(struct dw_mci *host) if (priv->ctrl_id < 0) priv->ctrl_id = 0; + if (priv->ctrl_id >= TIMING_MODE) + return -EINVAL; + host->priv = priv; return 0; } -- cgit v1.2.3 From a4faa4929ed3be15e2d500d2405f992f6dedc8eb Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Sat, 24 Feb 2018 14:17:22 +0800 Subject: mmc: dw_mmc: Factor out dw_mci_init_slot_caps Factor out dw_mci_init_slot_caps to consolidate parsing all differents types of capabilities from host contrllers. No functional change intended. Signed-off-by: Shawn Lin Fixes: 800d78bfccb3 ("mmc: dw_mmc: add support for implementation specific callbacks") Cc: Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 73 ++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 0aa39975f33b..4033cf96c7d7 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2778,12 +2778,50 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static int dw_mci_init_slot_caps(struct dw_mci_slot *slot) +{ + struct dw_mci *host = slot->host; + const struct dw_mci_drv_data *drv_data = host->drv_data; + struct mmc_host *mmc = slot->mmc; + int ctrl_id; + + if (host->pdata->caps) + mmc->caps = host->pdata->caps; + + /* + * Support MMC_CAP_ERASE by default. + * It needs to use trim/discard/erase commands. + */ + mmc->caps |= MMC_CAP_ERASE; + + if (host->pdata->pm_caps) + mmc->pm_caps = host->pdata->pm_caps; + + if (host->dev->of_node) { + ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); + if (ctrl_id < 0) + ctrl_id = 0; + } else { + ctrl_id = to_platform_device(host->dev)->id; + } + if (drv_data && drv_data->caps) + mmc->caps |= drv_data->caps[ctrl_id]; + + if (host->pdata->caps2) + mmc->caps2 = host->pdata->caps2; + + /* Process SDIO IRQs through the sdio_irq_work. */ + if (mmc->caps & MMC_CAP_SDIO_IRQ) + mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; + + return 0; +} + static int dw_mci_init_slot(struct dw_mci *host) { struct mmc_host *mmc; struct dw_mci_slot *slot; - const struct dw_mci_drv_data *drv_data = host->drv_data; - int ctrl_id, ret; + int ret; u32 freq[2]; mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); @@ -2817,38 +2855,13 @@ static int dw_mci_init_slot(struct dw_mci *host) if (!mmc->ocr_avail) mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - if (host->pdata->caps) - mmc->caps = host->pdata->caps; - - /* - * Support MMC_CAP_ERASE by default. - * It needs to use trim/discard/erase commands. - */ - mmc->caps |= MMC_CAP_ERASE; - - if (host->pdata->pm_caps) - mmc->pm_caps = host->pdata->pm_caps; - - if (host->dev->of_node) { - ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); - if (ctrl_id < 0) - ctrl_id = 0; - } else { - ctrl_id = to_platform_device(host->dev)->id; - } - if (drv_data && drv_data->caps) - mmc->caps |= drv_data->caps[ctrl_id]; - - if (host->pdata->caps2) - mmc->caps2 = host->pdata->caps2; - ret = mmc_of_parse(mmc); if (ret) goto err_host_allocated; - /* Process SDIO IRQs through the sdio_irq_work. */ - if (mmc->caps & MMC_CAP_SDIO_IRQ) - mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; + ret = dw_mci_init_slot_caps(slot); + if (ret) + goto err_host_allocated; /* Useful defaults if platform data is unset. */ if (host->use_dma == TRANS_MODE_IDMAC) { -- cgit v1.2.3 From 0d84b9e5631d923744767dc6608672df906dd092 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Sat, 24 Feb 2018 14:17:23 +0800 Subject: mmc: dw_mmc: Fix out-of-bounds access for slot's caps Add num_caps field for dw_mci_drv_data to validate the controller id from DT alias and non-DT ways. Reported-by: Geert Uytterhoeven Signed-off-by: Shawn Lin Fixes: 800d78bfccb3 ("mmc: dw_mmc: add support for implementation specific callbacks") Cc: Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-exynos.c | 1 + drivers/mmc/host/dw_mmc-k3.c | 1 + drivers/mmc/host/dw_mmc-rockchip.c | 1 + drivers/mmc/host/dw_mmc-zx.c | 1 + drivers/mmc/host/dw_mmc.c | 9 ++++++++- drivers/mmc/host/dw_mmc.h | 2 ++ 6 files changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 35026795be28..fa41d9422d57 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -487,6 +487,7 @@ static unsigned long exynos_dwmmc_caps[4] = { static const struct dw_mci_drv_data exynos_drv_data = { .caps = exynos_dwmmc_caps, + .num_caps = ARRAY_SIZE(exynos_dwmmc_caps), .init = dw_mci_exynos_priv_init, .set_ios = dw_mci_exynos_set_ios, .parse_dt = dw_mci_exynos_parse_dt, diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c index 75ae5803b0db..89cdb3d533bb 100644 --- a/drivers/mmc/host/dw_mmc-k3.c +++ b/drivers/mmc/host/dw_mmc-k3.c @@ -210,6 +210,7 @@ static int dw_mci_hi6220_execute_tuning(struct dw_mci_slot *slot, u32 opcode) static const struct dw_mci_drv_data hi6220_data = { .caps = dw_mci_hi6220_caps, + .num_caps = ARRAY_SIZE(dw_mci_hi6220_caps), .switch_voltage = dw_mci_hi6220_switch_voltage, .set_ios = dw_mci_hi6220_set_ios, .parse_dt = dw_mci_hi6220_parse_dt, diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index a3f1c2b30145..339295212935 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -319,6 +319,7 @@ static const struct dw_mci_drv_data rk2928_drv_data = { static const struct dw_mci_drv_data rk3288_drv_data = { .caps = dw_mci_rk3288_dwmmc_caps, + .num_caps = ARRAY_SIZE(dw_mci_rk3288_dwmmc_caps), .set_ios = dw_mci_rk3288_set_ios, .execute_tuning = dw_mci_rk3288_execute_tuning, .parse_dt = dw_mci_rk3288_parse_dt, diff --git a/drivers/mmc/host/dw_mmc-zx.c b/drivers/mmc/host/dw_mmc-zx.c index d38e94ae2b85..c06b5393312f 100644 --- a/drivers/mmc/host/dw_mmc-zx.c +++ b/drivers/mmc/host/dw_mmc-zx.c @@ -195,6 +195,7 @@ static unsigned long zx_dwmmc_caps[3] = { static const struct dw_mci_drv_data zx_drv_data = { .caps = zx_dwmmc_caps, + .num_caps = ARRAY_SIZE(zx_dwmmc_caps), .execute_tuning = dw_mci_zx_execute_tuning, .prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning, .parse_dt = dw_mci_zx_parse_dt, diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 4033cf96c7d7..a850f8d7d4b5 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2804,8 +2804,15 @@ static int dw_mci_init_slot_caps(struct dw_mci_slot *slot) } else { ctrl_id = to_platform_device(host->dev)->id; } - if (drv_data && drv_data->caps) + + if (drv_data && drv_data->caps) { + if (ctrl_id >= drv_data->num_caps) { + dev_err(host->dev, "invalid controller id %d\n", + ctrl_id); + return -EINVAL; + } mmc->caps |= drv_data->caps[ctrl_id]; + } if (host->pdata->caps2) mmc->caps2 = host->pdata->caps2; diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index e3124f06a47e..1424bd490dd1 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -543,6 +543,7 @@ struct dw_mci_slot { /** * dw_mci driver data - dw-mshc implementation specific driver data. * @caps: mmc subsystem specified capabilities of the controller(s). + * @num_caps: number of capabilities specified by @caps. * @init: early implementation specific initialization. * @set_ios: handle bus specific extensions. * @parse_dt: parse implementation specific device tree properties. @@ -554,6 +555,7 @@ struct dw_mci_slot { */ struct dw_mci_drv_data { unsigned long *caps; + u32 num_caps; int (*init)(struct dw_mci *host); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); int (*parse_dt)(struct dw_mci *host); -- cgit v1.2.3 From 5b43df8b4c1a7f0c3fbf793c9566068e6b1e570c Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 23 Feb 2018 16:47:25 +0800 Subject: mmc: dw_mmc: Avoid accessing registers in runtime suspended state cat /sys/kernel/debug/mmc0/regs will hang up the system since it's in runtime suspended state, so the genpd and biu_clk is off. This patch fixes this problem by calling pm_runtime_get_sync to wake it up before reading the registers. Fixes: e9ed8835e990 ("mmc: dw_mmc: add runtime PM callback") Cc: Signed-off-by: Shawn Lin Reviewed-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index a850f8d7d4b5..d9b4acefed31 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -165,6 +165,8 @@ static int dw_mci_regs_show(struct seq_file *s, void *v) { struct dw_mci *host = s->private; + pm_runtime_get_sync(host->dev); + seq_printf(s, "STATUS:\t0x%08x\n", mci_readl(host, STATUS)); seq_printf(s, "RINTSTS:\t0x%08x\n", mci_readl(host, RINTSTS)); seq_printf(s, "CMD:\t0x%08x\n", mci_readl(host, CMD)); @@ -172,6 +174,8 @@ static int dw_mci_regs_show(struct seq_file *s, void *v) seq_printf(s, "INTMASK:\t0x%08x\n", mci_readl(host, INTMASK)); seq_printf(s, "CLKENA:\t0x%08x\n", mci_readl(host, CLKENA)); + pm_runtime_put_autosuspend(host->dev); + return 0; } -- cgit v1.2.3 From 3a574919f0cc15a46ec14c3e5e08300908991915 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 27 Feb 2018 11:49:09 +0100 Subject: mmc: core: Avoid hanging to claim host for mmc via some nested calls As the block layer, since the conversion to blkmq, claims the host using a context, a following nested call to mmc_claim_host(), which isn't using a context, may hang. Calling mmc_interrupt_hpi() and mmc_read_bkops_status() via the mmc block layer, may suffer from this problem, as these functions are calling mmc_claim|release_host(). Let's fix the problem by removing the calls to mmc_claim|release_host() from the above mentioned functions and instead make the callers responsible of claiming/releasing the host. As a matter of fact, the existing callers already deals with it. Fixes: 81196976ed94 ("mmc: block: Add blk-mq support") Reported-by: Dmitry Osipenko Suggested-by: Adrian Hunter Tested-by: Dmitry Osipenko Signed-off-by: Ulf Hansson Acked-by: Adrian Hunter Reviewed-by: Shawn Lin --- drivers/mmc/core/mmc_ops.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 908e4db03535..42d6aa89a48a 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -848,7 +848,6 @@ int mmc_interrupt_hpi(struct mmc_card *card) return 1; } - mmc_claim_host(card->host); err = mmc_send_status(card, &status); if (err) { pr_err("%s: Get card status fail\n", mmc_hostname(card->host)); @@ -890,7 +889,6 @@ int mmc_interrupt_hpi(struct mmc_card *card) } while (!err); out: - mmc_release_host(card->host); return err; } @@ -932,9 +930,7 @@ static int mmc_read_bkops_status(struct mmc_card *card) int err; u8 *ext_csd; - mmc_claim_host(card->host); err = mmc_get_ext_csd(card, &ext_csd); - mmc_release_host(card->host); if (err) return err; -- cgit v1.2.3 From d716d9b702bb759dd6fb50804f10a174bd156d71 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 14 Feb 2018 18:40:12 +0900 Subject: dmaengine: rcar-dmac: fix max_chunk_size for R-Car Gen3 According to R-Car Gen3 Rev.0.80 manual, the DMATCR can be set to 16,777,215 as maximum. So, this patch fixes the max_chunk_size for safety on all of SoCs. Otherwise, a system may hang if the DMATCR is set to 0 on R-Car Gen3. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Vinod Koul --- drivers/dma/sh/rcar-dmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index e3ff162c03fc..d0cacdb0713e 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -917,7 +917,7 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl, rcar_dmac_chan_configure_desc(chan, desc); - max_chunk_size = (RCAR_DMATCR_MASK + 1) << desc->xfer_shift; + max_chunk_size = RCAR_DMATCR_MASK << desc->xfer_shift; /* * Allocate and fill the transfer chunk descriptors. We own the only -- cgit v1.2.3 From 0373ca74831b0f93cd4cdbf7ad3aec3c33a479a5 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 23 Feb 2018 09:38:28 +0530 Subject: cpufreq: s3c24xx: Fix broken s3c_cpufreq_init() commit a307a1e6bc0d "cpufreq: s3c: use cpufreq_generic_init()" accidentally broke cpufreq on s3c2410 and s3c2412. These two platforms don't have a CPU frequency table and used to skip calling cpufreq_table_validate_and_show() for them. But with the above commit, we started calling it unconditionally and that will eventually fail as the frequency table pointer is NULL. Fix this by calling cpufreq_table_validate_and_show() conditionally again. Fixes: a307a1e6bc0d "cpufreq: s3c: use cpufreq_generic_init()" Cc: 3.13+ # v3.13+ Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/s3c24xx-cpufreq.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 7b596fa38ad2..6bebc1f9f55a 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -351,7 +351,13 @@ struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name) static int s3c_cpufreq_init(struct cpufreq_policy *policy) { policy->clk = clk_arm; - return cpufreq_generic_init(policy, ftab, cpu_cur.info->latency); + + policy->cpuinfo.transition_latency = cpu_cur.info->latency; + + if (ftab) + return cpufreq_table_validate_and_show(policy, ftab); + + return 0; } static int __init s3c_cpufreq_initclks(void) -- cgit v1.2.3 From 02aa8a8b2b84531fa78b9a486d9b2a0700f7bc08 Mon Sep 17 00:00:00 2001 From: Coly Li Date: Tue, 27 Feb 2018 09:49:29 -0800 Subject: bcache: correct flash only vols (check all uuids) Commit 2831231d4c3f ("bcache: reduce cache_set devices iteration by devices_max_used") adds c->devices_max_used to reduce iteration of c->uuids elements, this value is updated in bcache_device_attach(). But for flash only volume, when calling flash_devs_run(), the function bcache_device_attach() is not called yet and c->devices_max_used is not updated. The unexpected result is, the flash only volume won't be run by flash_devs_run(). This patch fixes the issue by iterate all c->uuids elements in flash_devs_run(). c->devices_max_used will be updated properly when bcache_device_attach() gets called. [mlyle: commit subject edited for character limit] Fixes: 2831231d4c3f ("bcache: reduce cache_set devices iteration by devices_max_used") Reported-by: Tang Junhui Signed-off-by: Coly Li Reviewed-by: Michael Lyle Signed-off-by: Jens Axboe --- drivers/md/bcache/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 312895788036..4d1d8dfb2d2a 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1274,7 +1274,7 @@ static int flash_devs_run(struct cache_set *c) struct uuid_entry *u; for (u = c->uuids; - u < c->uuids + c->devices_max_used && !ret; + u < c->uuids + c->nr_uuids && !ret; u++) if (UUID_FLASH_ONLY(u)) ret = flash_dev_run(c, u); -- cgit v1.2.3 From 60eb34ec5526e264c2bbaea4f7512d714d791caf Mon Sep 17 00:00:00 2001 From: Tang Junhui Date: Tue, 27 Feb 2018 09:49:30 -0800 Subject: bcache: fix kcrashes with fio in RAID5 backend dev Kernel crashed when run fio in a RAID5 backend bcache device, the call trace is bellow: [ 440.012034] kernel BUG at block/blk-ioc.c:146! [ 440.012696] invalid opcode: 0000 [#1] SMP NOPTI [ 440.026537] CPU: 2 PID: 2205 Comm: md127_raid5 Not tainted 4.15.0 #8 [ 440.027441] Hardware name: HP ProLiant MicroServer Gen8, BIOS J06 07/16 /2015 [ 440.028615] RIP: 0010:put_io_context+0x8b/0x90 [ 440.029246] RSP: 0018:ffffa8c882b43af8 EFLAGS: 00010246 [ 440.029990] RAX: 0000000000000000 RBX: ffffa8c88294fca0 RCX: 0000000000 0f4240 [ 440.031006] RDX: 0000000000000004 RSI: 0000000000000286 RDI: ffffa8c882 94fca0 [ 440.032030] RBP: ffffa8c882b43b10 R08: 0000000000000003 R09: ffff949cb8 0c1700 [ 440.033206] R10: 0000000000000104 R11: 000000000000b71c R12: 00000000000 01000 [ 440.034222] R13: 0000000000000000 R14: ffff949cad84db70 R15: ffff949cb11 bd1e0 [ 440.035239] FS: 0000000000000000(0000) GS:ffff949cba280000(0000) knlGS: 0000000000000000 [ 440.060190] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 440.084967] CR2: 00007ff0493ef000 CR3: 00000002f1e0a002 CR4: 00000000001 606e0 [ 440.110498] Call Trace: [ 440.135443] bio_disassociate_task+0x1b/0x60 [ 440.160355] bio_free+0x1b/0x60 [ 440.184666] bio_put+0x23/0x30 [ 440.208272] search_free+0x23/0x40 [bcache] [ 440.231448] cached_dev_write_complete+0x31/0x70 [bcache] [ 440.254468] closure_put+0xb6/0xd0 [bcache] [ 440.277087] request_endio+0x30/0x40 [bcache] [ 440.298703] bio_endio+0xa1/0x120 [ 440.319644] handle_stripe+0x418/0x2270 [raid456] [ 440.340614] ? load_balance+0x17b/0x9c0 [ 440.360506] handle_active_stripes.isra.58+0x387/0x5a0 [raid456] [ 440.380675] ? __release_stripe+0x15/0x20 [raid456] [ 440.400132] raid5d+0x3ed/0x5d0 [raid456] [ 440.419193] ? schedule+0x36/0x80 [ 440.437932] ? schedule_timeout+0x1d2/0x2f0 [ 440.456136] md_thread+0x122/0x150 [ 440.473687] ? wait_woken+0x80/0x80 [ 440.491411] kthread+0x102/0x140 [ 440.508636] ? find_pers+0x70/0x70 [ 440.524927] ? kthread_associate_blkcg+0xa0/0xa0 [ 440.541791] ret_from_fork+0x35/0x40 [ 440.558020] Code: c2 48 00 5b 41 5c 41 5d 5d c3 48 89 c6 4c 89 e7 e8 bb c2 48 00 48 8b 3d bc 36 4b 01 48 89 de e8 7c f7 e0 ff 5b 41 5c 41 5d 5d c3 <0f> 0b 0f 1f 00 0f 1f 44 00 00 55 48 8d 47 b8 48 89 e5 41 57 41 [ 440.610020] RIP: put_io_context+0x8b/0x90 RSP: ffffa8c882b43af8 [ 440.628575] ---[ end trace a1fd79d85643a73e ]-- All the crash issue happened when a bypass IO coming, in such scenario s->iop.bio is pointed to the s->orig_bio. In search_free(), it finishes the s->orig_bio by calling bio_complete(), and after that, s->iop.bio became invalid, then kernel would crash when calling bio_put(). Maybe its upper layer's faulty, since bio should not be freed before we calling bio_put(), but we'd better calling bio_put() first before calling bio_complete() to notify upper layer ending this bio. This patch moves bio_complete() under bio_put() to avoid kernel crash. [mlyle: fixed commit subject for character limits] Reported-by: Matthias Ferdinand Tested-by: Matthias Ferdinand Signed-off-by: Tang Junhui Reviewed-by: Michael Lyle Signed-off-by: Jens Axboe --- drivers/md/bcache/request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 1a46b41dac70..6422846b546e 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -659,11 +659,11 @@ static void do_bio_hook(struct search *s, struct bio *orig_bio) static void search_free(struct closure *cl) { struct search *s = container_of(cl, struct search, cl); - bio_complete(s); if (s->iop.bio) bio_put(s->iop.bio); + bio_complete(s); closure_debug_destroy(cl); mempool_free(s, s->d->c->search); } -- cgit v1.2.3 From 9c2c2e62df3fa30fb13fbeb7512a4eede729383b Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Tue, 27 Feb 2018 01:56:06 +0100 Subject: net: phy: Restore phy_resume() locking assumption commit f5e64032a799 ("net: phy: fix resume handling") changes the locking semantics for phy_resume() such that the caller now needs to hold the phy mutex. Not all call sites were adopted to this new semantic, resulting in warnings from the added WARN_ON(!mutex_is_locked(&phydev->lock)). Rather than change the semantics, add a __phy_resume() and restore the old behavior of phy_resume(). Reported-by: Heiner Kallweit Fixes: f5e64032a799 ("net: phy: fix resume handling") Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 2 +- drivers/net/phy/phy_device.c | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e3e29c2b028b..a6f924fee584 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -819,7 +819,7 @@ void phy_start(struct phy_device *phydev) break; case PHY_HALTED: /* if phy was suspended, bring the physical link up again */ - phy_resume(phydev); + __phy_resume(phydev); /* make sure interrupts are re-enabled for the PHY */ if (phy_interrupt_is_valid(phydev)) { diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index d39ae77707ef..478405e544cc 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -135,9 +135,7 @@ static int mdio_bus_phy_resume(struct device *dev) if (!mdio_bus_phy_may_suspend(phydev)) goto no_resume; - mutex_lock(&phydev->lock); ret = phy_resume(phydev); - mutex_unlock(&phydev->lock); if (ret < 0) return ret; @@ -1041,9 +1039,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, if (err) goto error; - mutex_lock(&phydev->lock); phy_resume(phydev); - mutex_unlock(&phydev->lock); phy_led_triggers_register(phydev); return err; @@ -1172,7 +1168,7 @@ int phy_suspend(struct phy_device *phydev) } EXPORT_SYMBOL(phy_suspend); -int phy_resume(struct phy_device *phydev) +int __phy_resume(struct phy_device *phydev) { struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver); int ret = 0; @@ -1189,6 +1185,18 @@ int phy_resume(struct phy_device *phydev) return ret; } +EXPORT_SYMBOL(__phy_resume); + +int phy_resume(struct phy_device *phydev) +{ + int ret; + + mutex_lock(&phydev->lock); + ret = __phy_resume(phydev); + mutex_unlock(&phydev->lock); + + return ret; +} EXPORT_SYMBOL(phy_resume); int phy_loopback(struct phy_device *phydev, bool enable) -- cgit v1.2.3 From 55ea874306ea28e6be9e07b7e89bbb9fb674e8eb Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 27 Feb 2018 14:58:16 +0300 Subject: sh_eth: uninline TSU register accessors We have uninlined the sh_eth_{read|write}() functions introduced in the commit 4a55530f38e ("net: sh_eth: modify the definitions of register"). Now remove *inline* from sh_eth_tsu_{read|write}() as well and move these functions from the header to the driver itself. This saves 684 more bytes of object code (ARM gcc 4.8.5)... Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 11 +++++++++++ drivers/net/ethernet/renesas/sh_eth.h | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 92dcf8717fc6..14c839bb09e7 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -439,6 +439,17 @@ static void sh_eth_modify(struct net_device *ndev, int enum_index, u32 clear, enum_index); } +static void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data, + int enum_index) +{ + iowrite32(data, mdp->tsu_addr + mdp->reg_offset[enum_index]); +} + +static u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index) +{ + return ioread32(mdp->tsu_addr + mdp->reg_offset[enum_index]); +} + static bool sh_eth_is_gether(struct sh_eth_private *mdp) { return mdp->reg_offset == sh_eth_offset_gigabit; diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index a6753ccba711..e5fe70134690 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -567,15 +567,4 @@ static inline void *sh_eth_tsu_get_offset(struct sh_eth_private *mdp, return mdp->tsu_addr + mdp->reg_offset[enum_index]; } -static inline void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data, - int enum_index) -{ - iowrite32(data, mdp->tsu_addr + mdp->reg_offset[enum_index]); -} - -static inline u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index) -{ - return ioread32(mdp->tsu_addr + mdp->reg_offset[enum_index]); -} - #endif /* #ifndef __SH_ETH_H__ */ -- cgit v1.2.3 From 8ca88b5486cd87ac4fbda94f0a8ac5f36eb71c4b Mon Sep 17 00:00:00 2001 From: Bassem Boubaker Date: Tue, 27 Feb 2018 14:04:44 +0100 Subject: cdc_ether: flag the Cinterion PLS8 modem by gemalto as WWAN The Cinterion PL8 is an LTE modem with 2 possible WWAN interfaces. The modem is controlled via AT commands through the exposed TTYs. AT^SWWAN write command can be used to activate or deactivate a WWAN connection for a PDP context defined with AT+CGDCONT. UE supports two WWAN adapter. Both WWAN adapters can be activated a the same time Signed-off-by: Bassem Boubaker Acked-by: Oliver Neukum Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ether.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 05dca3e5c93d..fff4b13eece2 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -895,6 +895,12 @@ static const struct usb_device_id products[] = { USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), .driver_info = (unsigned long)&wwan_info, +}, { + /* Cinterion PLS8 modem by GEMALTO */ + USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0061, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&wwan_info, }, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), -- cgit v1.2.3 From 0979962f5490abe75b3e2befb07a564fa0cf631b Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 12 Feb 2018 11:14:55 -0600 Subject: nbd: fix return value in error handling path It seems that the proper value to return in this particular case is the one contained into variable new_index instead of ret. Addresses-Coverity-ID: 1465148 ("Copy-paste error") Fixes: e46c7287b1c2 ("nbd: add a basic netlink interface") Reviewed-by: Omar Sandoval Signed-off-by: Gustavo A. R. Silva Signed-off-by: Jens Axboe --- drivers/block/nbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 5f2a4240a204..86258b00a1d4 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1591,7 +1591,7 @@ again: if (new_index < 0) { mutex_unlock(&nbd_index_mutex); printk(KERN_ERR "nbd: failed to add new device\n"); - return ret; + return new_index; } nbd = idr_find(&nbd_index_idr, new_index); } -- cgit v1.2.3 From 084a804e01205bcd74cd0849bc72cb5c88f8e648 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Tue, 27 Feb 2018 12:41:41 +0200 Subject: usb: dwc3: Fix lock-up on ID change during system suspend/resume To reproduce the lock up do the following - connect otg host adapter and a USB device to the dual-role port so that it is in host mode. - suspend to mem. - disconnect otg adapter. - resume the system. If we call dwc3_host_exit() before tasks are thawed xhci_plat_remove() seems to lock up at the second usb_remove_hcd() call. To work around this we queue the _dwc3_set_mode() work on the system_freezable_wq. Fixes: 41ce1456e1db ("usb: dwc3: core: make dwc3_set_mode() work properly") Cc: # v4.12+ Suggested-by: Manu Gautam Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index f1d838a4acd6..e94bf91cc58a 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -175,7 +175,7 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode) dwc->desired_dr_role = mode; spin_unlock_irqrestore(&dwc->lock, flags); - queue_work(system_power_efficient_wq, &dwc->drd_work); + queue_work(system_freezable_wq, &dwc->drd_work); } u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) -- cgit v1.2.3 From 9bd82b1a4418d9b7db000bf557ed608f2872b7c9 Mon Sep 17 00:00:00 2001 From: Baegjae Sung Date: Wed, 28 Feb 2018 16:06:04 +0900 Subject: nvme-multipath: fix sysfs dangerously created links If multipathing is enabled, each NVMe subsystem creates a head namespace (e.g., nvme0n1) and multiple private namespaces (e.g., nvme0c0n1 and nvme0c1n1) in sysfs. When creating links for private namespaces, links of head namespace are used, so the namespace creation order must be followed (e.g., nvme0n1 -> nvme0c1n1). If the order is not followed, links of sysfs will be incomplete or kernel panic will occur. The kernel panic was: kernel BUG at fs/sysfs/symlink.c:27! Call Trace: nvme_mpath_add_disk_links+0x5d/0x80 [nvme_core] nvme_validate_ns+0x5c2/0x850 [nvme_core] nvme_scan_work+0x1af/0x2d0 [nvme_core] Correct order Context A Context B nvme0n1 nvme0c0n1 nvme0c1n1 Incorrect order Context A Context B nvme0c1n1 nvme0n1 nvme0c0n1 The nvme_mpath_add_disk (for creating head namespace) is called just before the nvme_mpath_add_disk_links (for creating private namespaces). In nvme_mpath_add_disk, the first context acquires the lock of subsystem and creates a head namespace, and other contexts do nothing by checking GENHD_FL_UP of a head namespace after waiting to acquire the lock. We verified the code with or without multipathing using three vendors of dual-port NVMe SSDs. Signed-off-by: Baegjae Sung Reviewed-by: Christoph Hellwig Signed-off-by: Keith Busch --- drivers/nvme/host/core.c | 12 +++--------- drivers/nvme/host/multipath.c | 15 ++++++++++----- 2 files changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index f431c32774f3..6088ea13a6bf 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2835,7 +2835,7 @@ out: } static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid, - struct nvme_id_ns *id, bool *new) + struct nvme_id_ns *id) { struct nvme_ctrl *ctrl = ns->ctrl; bool is_shared = id->nmic & (1 << 0); @@ -2851,8 +2851,6 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid, ret = PTR_ERR(head); goto out_unlock; } - - *new = true; } else { struct nvme_ns_ids ids; @@ -2864,8 +2862,6 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid, ret = -EINVAL; goto out_unlock; } - - *new = false; } list_add_tail(&ns->siblings, &head->list); @@ -2936,7 +2932,6 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) struct nvme_id_ns *id; char disk_name[DISK_NAME_LEN]; int node = dev_to_node(ctrl->dev), flags = GENHD_FL_EXT_DEVT; - bool new = true; ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node); if (!ns) @@ -2962,7 +2957,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) if (id->ncap == 0) goto out_free_id; - if (nvme_init_ns_head(ns, nsid, id, &new)) + if (nvme_init_ns_head(ns, nsid, id)) goto out_free_id; nvme_setup_streams_ns(ctrl, ns); @@ -3028,8 +3023,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) pr_warn("%s: failed to register lightnvm sysfs group for identification\n", ns->disk->disk_name); - if (new) - nvme_mpath_add_disk(ns->head); + nvme_mpath_add_disk(ns->head); nvme_mpath_add_disk_links(ns); return; out_unlink_ns: diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index 3b211d9e58b8..b7e5c6db4d92 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -198,11 +198,16 @@ void nvme_mpath_add_disk(struct nvme_ns_head *head) { if (!head->disk) return; - device_add_disk(&head->subsys->dev, head->disk); - if (sysfs_create_group(&disk_to_dev(head->disk)->kobj, - &nvme_ns_id_attr_group)) - pr_warn("%s: failed to create sysfs group for identification\n", - head->disk->disk_name); + + mutex_lock(&head->subsys->lock); + if (!(head->disk->flags & GENHD_FL_UP)) { + device_add_disk(&head->subsys->dev, head->disk); + if (sysfs_create_group(&disk_to_dev(head->disk)->kobj, + &nvme_ns_id_attr_group)) + pr_warn("%s: failed to create sysfs group for identification\n", + head->disk->disk_name); + } + mutex_unlock(&head->subsys->lock); } void nvme_mpath_add_disk_links(struct nvme_ns *ns) -- cgit v1.2.3 From 28b0f8a6962a24ed21737578f3b1b07424635c9e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 13 Feb 2018 07:38:08 -0800 Subject: tty: make n_tty_read() always abort if hangup is in progress A tty is hung up by __tty_hangup() setting file->f_op to hung_up_tty_fops, which is skipped on ttys whose write operation isn't tty_write(). This means that, for example, /dev/console whose write op is redirected_tty_write() is never actually marked hung up. Because n_tty_read() uses the hung up status to decide whether to abort the waiting readers, the lack of hung-up marking can lead to the following scenario. 1. A session contains two processes. The leader and its child. The child ignores SIGHUP. 2. The leader exits and starts disassociating from the controlling terminal (/dev/console). 3. __tty_hangup() skips setting f_op to hung_up_tty_fops. 4. SIGHUP is delivered and ignored. 5. tty_ldisc_hangup() is invoked. It wakes up the waits which should clear the read lockers of tty->ldisc_sem. 6. The reader wakes up but because tty_hung_up_p() is false, it doesn't abort and goes back to sleep while read-holding tty->ldisc_sem. 7. The leader progresses to tty_ldisc_lock() in tty_ldisc_hangup() and is now stuck in D sleep indefinitely waiting for tty->ldisc_sem. The following is Alan's explanation on why some ttys aren't hung up. http://lkml.kernel.org/r/20171101170908.6ad08580@alans-desktop 1. It broke the serial consoles because they would hang up and close down the hardware. With tty_port that *should* be fixable properly for any cases remaining. 2. The console layer was (and still is) completely broken and doens't refcount properly. So if you turn on console hangups it breaks (as indeed does freeing consoles and half a dozen other things). As neither can be fixed quickly, this patch works around the problem by introducing a new flag, TTY_HUPPING, which is used solely to tell n_tty_read() that hang-up is in progress for the console and the readers should be aborted regardless of the hung-up status of the device. The following is a sample hung task warning caused by this issue. INFO: task agetty:2662 blocked for more than 120 seconds. Not tainted 4.11.3-dbg-tty-lockup-02478-gfd6c7ee-dirty #28 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. 0 2662 1 0x00000086 Call Trace: __schedule+0x267/0x890 schedule+0x36/0x80 schedule_timeout+0x23c/0x2e0 ldsem_down_write+0xce/0x1f6 tty_ldisc_lock+0x16/0x30 tty_ldisc_hangup+0xb3/0x1b0 __tty_hangup+0x300/0x410 disassociate_ctty+0x6c/0x290 do_exit+0x7ef/0xb00 do_group_exit+0x3f/0xa0 get_signal+0x1b3/0x5d0 do_signal+0x28/0x660 exit_to_usermode_loop+0x46/0x86 do_syscall_64+0x9c/0xb0 entry_SYSCALL64_slow_path+0x25/0x25 The following is the repro. Run "$PROG /dev/console". The parent process hangs in D state. #include #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char **argv) { struct sigaction sact = { .sa_handler = SIG_IGN }; struct timespec ts1s = { .tv_sec = 1 }; pid_t pid; int fd; if (argc < 2) { fprintf(stderr, "test-hung-tty /dev/$TTY\n"); return 1; } /* fork a child to ensure that it isn't already the session leader */ pid = fork(); if (pid < 0) { perror("fork"); return 1; } if (pid > 0) { /* top parent, wait for everyone */ while (waitpid(-1, NULL, 0) >= 0) ; if (errno != ECHILD) perror("waitpid"); return 0; } /* new session, start a new session and set the controlling tty */ if (setsid() < 0) { perror("setsid"); return 1; } fd = open(argv[1], O_RDWR); if (fd < 0) { perror("open"); return 1; } if (ioctl(fd, TIOCSCTTY, 1) < 0) { perror("ioctl"); return 1; } /* fork a child, sleep a bit and exit */ pid = fork(); if (pid < 0) { perror("fork"); return 1; } if (pid > 0) { nanosleep(&ts1s, NULL); printf("Session leader exiting\n"); exit(0); } /* * The child ignores SIGHUP and keeps reading from the controlling * tty. Because SIGHUP is ignored, the child doesn't get killed on * parent exit and the bug in n_tty makes the read(2) block the * parent's control terminal hangup attempt. The parent ends up in * D sleep until the child is explicitly killed. */ sigaction(SIGHUP, &sact, NULL); printf("Child reading tty\n"); while (1) { char buf[1024]; if (read(fd, buf, sizeof(buf)) < 0) { perror("read"); return 1; } } return 0; } Signed-off-by: Tejun Heo Cc: Alan Cox Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 6 ++++++ drivers/tty/tty_io.c | 9 +++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 5c0e59e8fe46..cbe98bc2b998 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -2180,6 +2180,12 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, } if (tty_hung_up_p(file)) break; + /* + * Abort readers for ttys which never actually + * get hung up. See __tty_hangup(). + */ + if (test_bit(TTY_HUPPING, &tty->flags)) + break; if (!timeout) break; if (file->f_flags & O_NONBLOCK) { diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index eb9133b472f4..63114ea35ec1 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -586,6 +586,14 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) return; } + /* + * Some console devices aren't actually hung up for technical and + * historical reasons, which can lead to indefinite interruptible + * sleep in n_tty_read(). The following explicitly tells + * n_tty_read() to abort readers. + */ + set_bit(TTY_HUPPING, &tty->flags); + /* inuse_filps is protected by the single tty lock, this really needs to change if we want to flush the workqueue with the lock held */ @@ -640,6 +648,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) * from the ldisc side, which is now guaranteed. */ set_bit(TTY_HUPPED, &tty->flags); + clear_bit(TTY_HUPPING, &tty->flags); tty_unlock(tty); if (f) -- cgit v1.2.3 From fd63a8903a2c40425a9811c3371dd4d0f42c0ad3 Mon Sep 17 00:00:00 2001 From: Jonas Danielsson Date: Mon, 29 Jan 2018 12:39:15 +0100 Subject: tty/serial: atmel: add new version check for usart On our at91sam9260 based board the usart0 and usart1 ports report their versions (ATMEL_US_VERSION) as 0x10302. This version is not included in the current checks in the driver. Signed-off-by: Jonas Danielsson Acked-by: Richard Genoud Acked-by: Nicolas Ferre Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index df46a9e88c34..e287fe8f10fc 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1734,6 +1734,7 @@ static void atmel_get_ip_name(struct uart_port *port) switch (version) { case 0x302: case 0x10213: + case 0x10302: dev_dbg(port->dev, "This version is usart\n"); atmel_port->has_frac_baudrate = true; atmel_port->has_hw_timer = true; -- cgit v1.2.3 From e7f3e99cb1a667d04d60d02957fbed58b50d4e5a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 2 Feb 2018 20:39:13 +0200 Subject: serial: 8250_pci: Don't fail on multiport card class Do not fail on multiport cards in serial_pci_is_class_communication(). It restores behaviour for SUNIX multiport cards, that enumerated by class and have a custom board data. Moreover it allows users to reenumerate port-by-port from user space. Fixes: 7d8905d06405 ("serial: 8250_pci: Enable device after we check black list") Reported-by: Nikola Ciprich Signed-off-by: Andy Shevchenko Tested-by: Nikola Ciprich Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 54adf8d56350..d580625acc79 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -3387,11 +3387,9 @@ static int serial_pci_is_class_communication(struct pci_dev *dev) /* * If it is not a communications device or the programming * interface is greater than 6, give up. - * - * (Should we try to make guesses for multiport serial devices - * later?) */ if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && + ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MULTISERIAL) && ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || (dev->class & 0xff) > 6) return -ENODEV; @@ -3428,6 +3426,12 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) { int num_iomem, num_port, first_port = -1, i; + /* + * Should we try to make guesses for multiport serial devices later? + */ + if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_MULTISERIAL) + return -ENODEV; + num_iomem = num_port = 0; for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { if (pci_resource_flags(dev, i) & IORESOURCE_IO) { -- cgit v1.2.3 From 714569064adee3c114a2a6490735b94abe269068 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Sat, 3 Feb 2018 12:27:23 +0100 Subject: serial: core: mark port as initialized in autoconfig This is a followup on 44117a1d1732 ("serial: core: mark port as initialized after successful IRQ change"). Nikola has been using autoconfig via setserial and reported a crash similar to what I fixed in the earlier mentioned commit. Here I do the same fixup for the autoconfig. I wasn't sure that this is the right approach. Nikola confirmed that it fixes his crash. Fixes: b3b576461864 ("tty: serial_core: convert uart_open to use tty_port_open") Link: http://lkml.kernel.org/r/20180131072000.GD1853@localhost.localdomain Reported-by: Nikola Ciprich Tested-by: Nikola Ciprich Cc: Signed-off-by: Sebastian Andrzej Siewior Tested-by: Nikola Ciprich Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index c8dde56b532b..35b9201db3b4 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1144,6 +1144,8 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) uport->ops->config_port(uport, flags); ret = uart_startup(tty, state, 1); + if (ret == 0) + tty_port_set_initialized(port, true); if (ret > 0) ret = 0; } -- cgit v1.2.3 From 1f66dd36bb18437397ea0d7882c52f7e3c476e15 Mon Sep 17 00:00:00 2001 From: Greentime Hu Date: Tue, 13 Feb 2018 17:09:08 +0800 Subject: earlycon: add reg-offset to physical address before mapping It will get the wrong virtual address because port->mapbase is not added the correct reg-offset yet. We have to update it before earlycon_map() is called Signed-off-by: Greentime Hu Acked-by: Arnd Bergmann Cc: Peter Hurley Cc: stable@vger.kernel.org Fixes: 088da2a17619 ("of: earlycon: Initialize port fields from DT properties") Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/earlycon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 870e84fb6e39..a24278380fec 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -245,11 +245,12 @@ int __init of_setup_earlycon(const struct earlycon_id *match, } port->mapbase = addr; port->uartclk = BASE_BAUD * 16; - port->membase = earlycon_map(port->mapbase, SZ_4K); val = of_get_flat_dt_prop(node, "reg-offset", NULL); if (val) port->mapbase += be32_to_cpu(*val); + port->membase = earlycon_map(port->mapbase, SZ_4K); + val = of_get_flat_dt_prop(node, "reg-shift", NULL); if (val) port->regshift = be32_to_cpu(*val); -- cgit v1.2.3 From 9f2068f35729948bde84d87a40d135015911345d Mon Sep 17 00:00:00 2001 From: Nikola Ciprich Date: Tue, 13 Feb 2018 15:04:46 +0100 Subject: serial: 8250_pci: Add Brainboxes UC-260 4 port serial device Add PCI ids for two variants of Brainboxes UC-260 quad port PCI serial cards. Suggested-by: Andy Shevchenko Signed-off-by: Nikola Ciprich Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index d580625acc79..a93f77ab3da0 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -4702,6 +4702,17 @@ static const struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0dc0 */ pbn_b2_4_115200 }, + /* + * BrainBoxes UC-260 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0D21, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, + pbn_b2_4_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0E34, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, + pbn_b2_4_115200 }, /* * Perle PCI-RAS cards */ -- cgit v1.2.3 From 7842055bfce4bf0170d0f61df8b2add8399697be Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Thu, 15 Feb 2018 13:02:27 +0100 Subject: serial: sh-sci: prevent lockup on full TTY buffers When the TTY buffers fill up to the configured maximum, a system lockup occurs: [ 598.820128] INFO: rcu_preempt detected stalls on CPUs/tasks: [ 598.825796] 0-...!: (1 GPs behind) idle=5a6/2/0 softirq=1974/1974 fqs=1 [ 598.832577] (detected by 3, t=62517 jiffies, g=296, c=295, q=126) [ 598.838755] Task dump for CPU 0: [ 598.841977] swapper/0 R running task 0 0 0 0x00000022 [ 598.849023] Call trace: [ 598.851476] __switch_to+0x98/0xb0 [ 598.854870] (null) This can be prevented by doing a dummy read of the RX data register. This issue affects both HSCIF and SCIF ports. Reported for R-Car H3 ES2.0; reproduced and fixed on H3 ES1.1. Probably affects other R-Car platforms as well. Reported-by: Yoshihiro Shimoda Signed-off-by: Ulrich Hecht Reviewed-by: Geert Uytterhoeven Cc: stable Tested-by: Nguyen Viet Dung Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 7257c078e155..44adf9db38f8 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -885,6 +885,8 @@ static void sci_receive_chars(struct uart_port *port) /* Tell the rest of the system the news. New characters! */ tty_flip_buffer_push(tport); } else { + /* TTY buffers full; read from RX reg to prevent lockup */ + serial_port_in(port, SCxRDR); serial_port_in(port, SCxSR); /* dummy read */ sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); } -- cgit v1.2.3 From 5d7f77ec72d10c421bc33958f06a5583f2d27ed6 Mon Sep 17 00:00:00 2001 From: phil eichinger Date: Mon, 19 Feb 2018 10:24:15 +0100 Subject: serial: imx: fix bogus dev_err MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only one of the two is really required, not both: * have_rtscts or * have_rtsgpio In imx_rs485_config() this is done correctly, so RS485 is working, just the error message is false. Signed-off-by: Phil Eichinger Reviewed-by: Fabio Estevam Fixes: b8f3bff057b0 ("serial: imx: Support common rs485 binding for RTS polarity" Acked-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 1d7ca382bc12..a33c685af990 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2093,7 +2093,7 @@ static int serial_imx_probe(struct platform_device *pdev) uart_get_rs485_mode(&pdev->dev, &sport->port.rs485); if (sport->port.rs485.flags & SER_RS485_ENABLED && - (!sport->have_rtscts || !sport->have_rtsgpio)) + (!sport->have_rtscts && !sport->have_rtsgpio)) dev_err(&pdev->dev, "no RTS control, disabling rs485\n"); imx_rs485_config(&sport->port, &sport->port.rs485); -- cgit v1.2.3 From 5753405e27f8fe4c42c1537d3ddbd9e058e54cdc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 28 Feb 2018 10:56:10 +0100 Subject: clocksource/drivers/mips-gic-timer: Use correct shift count to extract data __gic_clocksource_init() extracts the GIC_CONFIG_COUNTBITS field from read_gic_config() by right shifting the register value. The shift count is determined by the most significant bit (__fls) of the bitmask which is wrong as it shifts out the complete bitfield. Use the least significant bit (__ffs) instead to shift the bitfield down to bit 0. Fixes: e07127a077c7 ("clocksource: mips-gic-timer: Use new GIC accessor functions") Signed-off-by: Felix Fietkau Signed-off-by: Thomas Gleixner Cc: daniel.lezcano@linaro.org Cc: paul.burton@imgtec.com Link: https://lkml.kernel.org/r/20180228095610.50341-1-nbd@nbd.name --- drivers/clocksource/mips-gic-timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 65e18c86d9b9..986b6796b631 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -166,7 +166,7 @@ static int __init __gic_clocksource_init(void) /* Set clocksource mask. */ count_width = read_gic_config() & GIC_CONFIG_COUNTBITS; - count_width >>= __fls(GIC_CONFIG_COUNTBITS); + count_width >>= __ffs(GIC_CONFIG_COUNTBITS); count_width *= 4; count_width += 32; gic_clocksource.mask = CLOCKSOURCE_MASK(count_width); -- cgit v1.2.3 From a4f538573cd72e7961f4ec5eb13c171f5add58ec Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 21 Feb 2018 11:31:31 -0800 Subject: clocksource/drivers/arc_timer: Update some comments TIMER0 interrupt ACK is different for ARC700 and HS3x cores. This came to light in some internal discussions and it is nice to have this documented rather than digging up the PRM (Programmers Reference Manual). Signed-off-by: Vineet Gupta Signed-off-by: Thomas Gleixner Cc: Daniel Lezcano Cc: Vineet Gupta Cc: linux-snps-arc@lists.infradead.org Link: https://lkml.kernel.org/r/1519241491-12570-1-git-send-email-vgupta@synopsys.com --- drivers/clocksource/arc_timer.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/arc_timer.c b/drivers/clocksource/arc_timer.c index 4927355f9cbe..471b428d8034 100644 --- a/drivers/clocksource/arc_timer.c +++ b/drivers/clocksource/arc_timer.c @@ -251,9 +251,14 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id) int irq_reenable = clockevent_state_periodic(evt); /* - * Any write to CTRL reg ACks the interrupt, we rewrite the - * Count when [N]ot [H]alted bit. - * And re-arm it if perioid by [I]nterrupt [E]nable bit + * 1. ACK the interrupt + * - For ARC700, any write to CTRL reg ACKs it, so just rewrite + * Count when [N]ot [H]alted bit. + * - For HS3x, it is a bit subtle. On taken count-down interrupt, + * IP bit [3] is set, which needs to be cleared for ACK'ing. + * The write below can only update the other two bits, hence + * explicitly clears IP bit + * 2. Re-arm interrupt if periodic by writing to IE bit [0] */ write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH); -- cgit v1.2.3 From b08e5fd90bfc7553d36fa42a03fb7f5e82d252eb Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 26 Feb 2018 16:10:56 +0000 Subject: arm_pmu: Use disable_irq_nosync when disabling SPI in CPU teardown hook Commit 6de3f79112cc ("arm_pmu: explicitly enable/disable SPIs at hotplug") moved all of the arm_pmu IRQ enable/disable calls to the CPU hotplug hooks, regardless of whether they are implemented as PPIs or SPIs. This can lead to us sleeping from atomic context due to disable_irq blocking: | BUG: sleeping function called from invalid context at kernel/irq/manage.c:112 | in_atomic(): 1, irqs_disabled(): 128, pid: 15, name: migration/1 | no locks held by migration/1/15. | irq event stamp: 192 | hardirqs last enabled at (191): [<00000000803c2507>] | _raw_spin_unlock_irq+0x2c/0x4c | hardirqs last disabled at (192): [<000000007f57ad28>] multi_cpu_stop+0x9c/0x140 | softirqs last enabled at (0): [<0000000004ee1b58>] | copy_process.isra.77.part.78+0x43c/0x1504 | softirqs last disabled at (0): [< (null)>] (null) | CPU: 1 PID: 15 Comm: migration/1 Not tainted 4.16.0-rc3-salvator-x #1651 | Hardware name: Renesas Salvator-X board based on r8a7796 (DT) | Call trace: | dump_backtrace+0x0/0x140 | show_stack+0x14/0x1c | dump_stack+0xb4/0xf0 | ___might_sleep+0x1fc/0x218 | __might_sleep+0x70/0x80 | synchronize_irq+0x40/0xa8 | disable_irq+0x20/0x2c | arm_perf_teardown_cpu+0x80/0xac Since the interrupt is always CPU-affine and this code is running with interrupts disabled, we can just use disable_irq_nosync as we know there isn't a concurrent invocation of the handler to worry about. Fixes: 6de3f79112cc ("arm_pmu: explicitly enable/disable SPIs at hotplug") Reported-by: Geert Uytterhoeven Tested-by: Geert Uytterhoeven Acked-by: Mark Rutland Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas --- drivers/perf/arm_pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 0c2ed11c0603..f63db346c219 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -638,7 +638,7 @@ static int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node) if (irq_is_percpu_devid(irq)) disable_percpu_irq(irq); else - disable_irq(irq); + disable_irq_nosync(irq); } per_cpu(cpu_armpmu, cpu) = NULL; -- cgit v1.2.3 From 590399ddf9561f2ed0839311c8ae1be21597ba68 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 27 Feb 2018 17:33:10 +0200 Subject: gianfar: Fix Rx byte accounting for ndev stats Don't include in the Rx bytecount of the packet sent up the stack: the FCB (frame control block), and the padding bytes inserted by the controller into the frame payload, nor the FCS. All these are being pulled out of the skb by gfar_process_frame(). This issue is old, likely from the driver's beginnings, however it was amplified by recent: commit d903ec77118c ("gianfar: simplify FCS handling and fix memory leak") which basically added the FCS to the Rx bytecount, and so brought this to my attention. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index f5c87bd35fa1..f27f9bae1a4a 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -3063,9 +3063,6 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb) if (ndev->features & NETIF_F_RXCSUM) gfar_rx_checksum(skb, fcb); - /* Tell the skb what kind of packet this is */ - skb->protocol = eth_type_trans(skb, ndev); - /* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here. * Even if vlan rx accel is disabled, on some chips * RXFCB_VLN is pseudo randomly set. @@ -3136,13 +3133,15 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) continue; } + gfar_process_frame(ndev, skb); + /* Increment the number of packets */ total_pkts++; total_bytes += skb->len; skb_record_rx_queue(skb, rx_queue->qindex); - gfar_process_frame(ndev, skb); + skb->protocol = eth_type_trans(skb, ndev); /* Send the packet up the stack */ napi_gro_receive(&rx_queue->grp->napi_rx, skb); -- cgit v1.2.3 From 12472af89632beb1ed8dea29d4efe208ca05b06a Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 27 Feb 2018 18:58:12 +0100 Subject: s390/qeth: fix overestimated count of buffer elements qeth_get_elements_for_range() doesn't know how to handle a 0-length range (ie. start == end), and returns 1 when it should return 0. Such ranges occur on TSO skbs, where the L2/L3/L4 headers (and thus all of the skb's linear data) are skipped when mapping the skb into regular buffer elements. This overestimation may cause several performance-related issues: 1. sub-optimal IO buffer selection, where the next buffer gets selected even though the skb would actually still fit into the current buffer. 2. forced linearization, if the element count for a non-linear skb exceeds QETH_MAX_BUFFER_ELEMENTS. Rather than modifying qeth_get_elements_for_range() and adding overhead to every caller, fix up those callers that are in risk of passing a 0-length range. Fixes: 2863c61334aa ("qeth: refactor calculation of SBALE count") Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 10 ++++++---- drivers/s390/net/qeth_l3_main.c | 11 ++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index ca72f3311004..30457fca30c5 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3898,10 +3898,12 @@ EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags); int qeth_get_elements_no(struct qeth_card *card, struct sk_buff *skb, int extra_elems, int data_offset) { - int elements = qeth_get_elements_for_range( - (addr_t)skb->data + data_offset, - (addr_t)skb->data + skb_headlen(skb)) + - qeth_get_elements_for_frags(skb); + addr_t end = (addr_t)skb->data + skb_headlen(skb); + int elements = qeth_get_elements_for_frags(skb); + addr_t start = (addr_t)skb->data + data_offset; + + if (start != end) + elements += qeth_get_elements_for_range(start, end); if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { QETH_DBF_MESSAGE(2, "Invalid size of IP packet " diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index b0c888e86cd4..3421893c37a4 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2450,11 +2450,12 @@ static void qeth_tso_fill_header(struct qeth_card *card, static int qeth_l3_get_elements_no_tso(struct qeth_card *card, struct sk_buff *skb, int extra_elems) { - addr_t tcpdptr = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb); - int elements = qeth_get_elements_for_range( - tcpdptr, - (addr_t)skb->data + skb_headlen(skb)) + - qeth_get_elements_for_frags(skb); + addr_t start = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb); + addr_t end = (addr_t)skb->data + skb_headlen(skb); + int elements = qeth_get_elements_for_frags(skb); + + if (start != end) + elements += qeth_get_elements_for_range(start, end); if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { QETH_DBF_MESSAGE(2, -- cgit v1.2.3 From 98d823ab1fbdcb13abc25b420f9bb71bade42056 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 27 Feb 2018 18:58:13 +0100 Subject: s390/qeth: fix IP removal on offline cards If the HW is not reachable, then none of the IPs in qeth's internal table has been registered with the HW yet. So when deleting such an IP, there's no need to stage it for deregistration - just drop it from the table. This fixes the "add-delete-add" scenario on an offline card, where the the second "add" merely increments the IP's use count. But as the IP is still set to DISP_ADDR_DELETE from the previous "delete" step, l3_recover_ip() won't register it with the HW when the card goes online. Fixes: 5f78e29ceebf ("qeth: optimize IP handling in rx_mode callback") Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 3421893c37a4..34481b51029e 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -173,12 +173,8 @@ int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) if (addr->in_progress) return -EINPROGRESS; - if (!qeth_card_hw_is_reachable(card)) { - addr->disp_flag = QETH_DISP_ADDR_DELETE; - return 0; - } - - rc = qeth_l3_deregister_addr_entry(card, addr); + if (qeth_card_hw_is_reachable(card)) + rc = qeth_l3_deregister_addr_entry(card, addr); hash_del(&addr->hnode); kfree(addr); @@ -321,11 +317,7 @@ static void qeth_l3_recover_ip(struct qeth_card *card) spin_lock_bh(&card->ip_lock); hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) { - if (addr->disp_flag == QETH_DISP_ADDR_DELETE) { - qeth_l3_deregister_addr_entry(card, addr); - hash_del(&addr->hnode); - kfree(addr); - } else if (addr->disp_flag == QETH_DISP_ADDR_ADD) { + if (addr->disp_flag == QETH_DISP_ADDR_ADD) { if (addr->proto == QETH_PROT_IPV4) { addr->in_progress = 1; spin_unlock_bh(&card->ip_lock); -- cgit v1.2.3 From 14d066c3531a87f727968cacd85bd95c75f59843 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 27 Feb 2018 18:58:14 +0100 Subject: s390/qeth: fix double-free on IP add/remove race Registering an IPv4 address with the HW takes quite a while, so we temporarily drop the ip_htable lock. Any concurrent add/remove of the same IP adjusts the IP's use count, and (on remove) is then blocked by addr->in_progress. After the register call has completed, we check the use count for concurrently attempted add/remove calls - and possibly straight-away deregister the IP again. This happens via l3_delete_ip(), which 1) looks up the queried IP in the htable (getting a reference to the *same* queried object), 2) deregisters the IP from the HW, and 3) frees the IP object. The caller in l3_add_ip() then does a second free on the same object. For this case, skip all the extra checks and lookups in l3_delete_ip() and just deregister & free the IP object ourselves. Fixes: 5f78e29ceebf ("qeth: optimize IP handling in rx_mode callback") Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 34481b51029e..77cdb4fc7721 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -237,7 +237,8 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) (rc == IPA_RC_LAN_OFFLINE)) { addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING; if (addr->ref_counter < 1) { - qeth_l3_delete_ip(card, addr); + qeth_l3_deregister_addr_entry(card, addr); + hash_del(&addr->hnode); kfree(addr); } } else { -- cgit v1.2.3 From 4964c66fd49b2e2342da35358f2ff74614bcbaee Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 27 Feb 2018 18:58:15 +0100 Subject: Revert "s390/qeth: fix using of ref counter for rxip addresses" This reverts commit cb816192d986f7596009dedcf2201fe2e5bc2aa7. The issue this attempted to fix never actually occurs. l3_add_rxip() checks (via l3_ip_from_hash()) if the requested address was previously added to the card. If so, it returns -EEXIST and doesn't call l3_add_ip(). As a result, the "address exists" path in l3_add_ip() is never taken for rxip addresses, and this patch had no effect. Fixes: cb816192d986 ("s390/qeth: fix using of ref counter for rxip addresses") Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 77cdb4fc7721..4d8826fec6f4 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -167,8 +167,7 @@ int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) return -ENOENT; addr->ref_counter--; - if (addr->ref_counter > 0 && (addr->type == QETH_IP_TYPE_NORMAL || - addr->type == QETH_IP_TYPE_RXIP)) + if (addr->type == QETH_IP_TYPE_NORMAL && addr->ref_counter > 0) return rc; if (addr->in_progress) return -EINPROGRESS; @@ -246,9 +245,8 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) kfree(addr); } } else { - if (addr->type == QETH_IP_TYPE_NORMAL || - addr->type == QETH_IP_TYPE_RXIP) - addr->ref_counter++; + if (addr->type == QETH_IP_TYPE_NORMAL) + addr->ref_counter++; } return rc; -- cgit v1.2.3 From c5c48c58b259bb8f0482398370ee539d7a12df3e Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 27 Feb 2018 18:58:16 +0100 Subject: s390/qeth: fix IP address lookup for L3 devices Current code ("qeth_l3_ip_from_hash()") matches a queried address object against objects in the IP table by IP address, Mask/Prefix Length and MAC address ("qeth_l3_ipaddrs_is_equal()"). But what callers actually require is either a) "is this IP address registered" (ie. match by IP address only), before adding a new address. b) or "is this address object registered" (ie. match all relevant attributes), before deleting an address. Right now 1. the ADD path is too strict in its lookup, and eg. doesn't detect conflicts between an existing NORMAL address and a new VIPA address (because the NORMAL address will have mask != 0, while VIPA has a mask == 0), 2. the DELETE path is not strict enough, and eg. allows del_rxip() to delete a VIPA address as long as the IP address matches. Fix all this by adding helpers (_addr_match_ip() and _addr_match_all()) that do the appropriate checking. Note that the ADD path for NORMAL addresses is special, as qeth keeps track of how many times such an address is in use (and there is no immediate way of returning errors to the caller). So when a requested NORMAL address _fully_ matches an existing one, it's not considered a conflict and we merely increment the refcount. Fixes: 5f78e29ceebf ("qeth: optimize IP handling in rx_mode callback") Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3.h | 34 ++++++++++++++- drivers/s390/net/qeth_l3_main.c | 91 +++++++++++++++++++---------------------- 2 files changed, 74 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index bdd45f4dcace..498fe9af2cdb 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h @@ -40,8 +40,40 @@ struct qeth_ipaddr { unsigned int pfxlen; } a6; } u; - }; + +static inline bool qeth_l3_addr_match_ip(struct qeth_ipaddr *a1, + struct qeth_ipaddr *a2) +{ + if (a1->proto != a2->proto) + return false; + if (a1->proto == QETH_PROT_IPV6) + return ipv6_addr_equal(&a1->u.a6.addr, &a2->u.a6.addr); + return a1->u.a4.addr == a2->u.a4.addr; +} + +static inline bool qeth_l3_addr_match_all(struct qeth_ipaddr *a1, + struct qeth_ipaddr *a2) +{ + /* Assumes that the pair was obtained via qeth_l3_addr_find_by_ip(), + * so 'proto' and 'addr' match for sure. + * + * For ucast: + * - 'mac' is always 0. + * - 'mask'/'pfxlen' for RXIP/VIPA is always 0. For NORMAL, matching + * values are required to avoid mixups in takeover eligibility. + * + * For mcast, + * - 'mac' is mapped from the IP, and thus always matches. + * - 'mask'/'pfxlen' is always 0. + */ + if (a1->type != a2->type) + return false; + if (a1->proto == QETH_PROT_IPV6) + return a1->u.a6.pfxlen == a2->u.a6.pfxlen; + return a1->u.a4.mask == a2->u.a4.mask; +} + static inline u64 qeth_l3_ipaddr_hash(struct qeth_ipaddr *addr) { u64 ret = 0; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 4d8826fec6f4..962a04b68dd2 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -67,6 +67,24 @@ void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr, qeth_l3_ipaddr6_to_string(addr, buf); } +static struct qeth_ipaddr *qeth_l3_find_addr_by_ip(struct qeth_card *card, + struct qeth_ipaddr *query) +{ + u64 key = qeth_l3_ipaddr_hash(query); + struct qeth_ipaddr *addr; + + if (query->is_multicast) { + hash_for_each_possible(card->ip_mc_htable, addr, hnode, key) + if (qeth_l3_addr_match_ip(addr, query)) + return addr; + } else { + hash_for_each_possible(card->ip_htable, addr, hnode, key) + if (qeth_l3_addr_match_ip(addr, query)) + return addr; + } + return NULL; +} + static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len) { int i, j; @@ -120,34 +138,6 @@ static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card, return rc; } -inline int -qeth_l3_ipaddrs_is_equal(struct qeth_ipaddr *addr1, struct qeth_ipaddr *addr2) -{ - return addr1->proto == addr2->proto && - !memcmp(&addr1->u, &addr2->u, sizeof(addr1->u)) && - ether_addr_equal_64bits(addr1->mac, addr2->mac); -} - -static struct qeth_ipaddr * -qeth_l3_ip_from_hash(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) -{ - struct qeth_ipaddr *addr; - - if (tmp_addr->is_multicast) { - hash_for_each_possible(card->ip_mc_htable, addr, - hnode, qeth_l3_ipaddr_hash(tmp_addr)) - if (qeth_l3_ipaddrs_is_equal(tmp_addr, addr)) - return addr; - } else { - hash_for_each_possible(card->ip_htable, addr, - hnode, qeth_l3_ipaddr_hash(tmp_addr)) - if (qeth_l3_ipaddrs_is_equal(tmp_addr, addr)) - return addr; - } - - return NULL; -} - int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) { int rc = 0; @@ -162,8 +152,8 @@ int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8); } - addr = qeth_l3_ip_from_hash(card, tmp_addr); - if (!addr) + addr = qeth_l3_find_addr_by_ip(card, tmp_addr); + if (!addr || !qeth_l3_addr_match_all(addr, tmp_addr)) return -ENOENT; addr->ref_counter--; @@ -185,6 +175,7 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) { int rc = 0; struct qeth_ipaddr *addr; + char buf[40]; QETH_CARD_TEXT(card, 4, "addip"); @@ -195,8 +186,20 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8); } - addr = qeth_l3_ip_from_hash(card, tmp_addr); - if (!addr) { + addr = qeth_l3_find_addr_by_ip(card, tmp_addr); + if (addr) { + if (tmp_addr->type != QETH_IP_TYPE_NORMAL) + return -EADDRINUSE; + if (qeth_l3_addr_match_all(addr, tmp_addr)) { + addr->ref_counter++; + return 0; + } + qeth_l3_ipaddr_to_string(tmp_addr->proto, (u8 *)&tmp_addr->u, + buf); + dev_warn(&card->gdev->dev, + "Registering IP address %s failed\n", buf); + return -EADDRINUSE; + } else { addr = qeth_l3_get_addr_buffer(tmp_addr->proto); if (!addr) return -ENOMEM; @@ -244,11 +247,7 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) hash_del(&addr->hnode); kfree(addr); } - } else { - if (addr->type == QETH_IP_TYPE_NORMAL) - addr->ref_counter++; } - return rc; } @@ -634,12 +633,7 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, return -ENOMEM; spin_lock_bh(&card->ip_lock); - - if (qeth_l3_ip_from_hash(card, ipaddr)) - rc = -EEXIST; - else - rc = qeth_l3_add_ip(card, ipaddr); - + rc = qeth_l3_add_ip(card, ipaddr); spin_unlock_bh(&card->ip_lock); kfree(ipaddr); @@ -704,12 +698,7 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, return -ENOMEM; spin_lock_bh(&card->ip_lock); - - if (qeth_l3_ip_from_hash(card, ipaddr)) - rc = -EEXIST; - else - rc = qeth_l3_add_ip(card, ipaddr); - + rc = qeth_l3_add_ip(card, ipaddr); spin_unlock_bh(&card->ip_lock); kfree(ipaddr); @@ -1230,8 +1219,9 @@ qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev) tmp->u.a4.addr = be32_to_cpu(im4->multiaddr); tmp->is_multicast = 1; - ipm = qeth_l3_ip_from_hash(card, tmp); + ipm = qeth_l3_find_addr_by_ip(card, tmp); if (ipm) { + /* for mcast, by-IP match means full match */ ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING; } else { ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); @@ -1310,8 +1300,9 @@ static void qeth_l3_add_mc6_to_hash(struct qeth_card *card, sizeof(struct in6_addr)); tmp->is_multicast = 1; - ipm = qeth_l3_ip_from_hash(card, tmp); + ipm = qeth_l3_find_addr_by_ip(card, tmp); if (ipm) { + /* for mcast, by-IP match means full match */ ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING; continue; } -- cgit v1.2.3 From d22ffb5a712f9211ffd104c38fc17cbfb1b5e2b0 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 27 Feb 2018 18:58:17 +0100 Subject: s390/qeth: fix IPA command submission race If multiple IPA commands are build & sent out concurrently, fill_ipacmd_header() may assign a seqno value to a command that's different from what send_control_data() later assigns to this command's reply. This is due to other commands passing through send_control_data(), and incrementing card->seqno.ipa along the way. So one IPA command has no reply that's waiting for its seqno, while some other IPA command has multiple reply objects waiting for it. Only one of those waiting replies wins, and the other(s) times out and triggers a recovery via send_ipa_cmd(). Fix this by making sure that the same seqno value is assigned to a command and its reply object. Do so immediately before submitting the command & while holding the irq_pending "lock", to produce nicely ascending seqnos. As a side effect, *all* IPA commands now use a reply object that's waiting for its actual seqno. Previously, early IPA commands that were submitted while the card was still DOWN used the "catch-all" IDX seqno. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 30457fca30c5..c8b308cfabf1 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2134,24 +2134,25 @@ int qeth_send_control_data(struct qeth_card *card, int len, } reply->callback = reply_cb; reply->param = reply_param; - if (card->state == CARD_STATE_DOWN) - reply->seqno = QETH_IDX_COMMAND_SEQNO; - else - reply->seqno = card->seqno.ipa++; + init_waitqueue_head(&reply->wait_q); - spin_lock_irqsave(&card->lock, flags); - list_add_tail(&reply->list, &card->cmd_waiter_list); - spin_unlock_irqrestore(&card->lock, flags); while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ; - qeth_prepare_control_data(card, len, iob); if (IS_IPA(iob->data)) { cmd = __ipa_cmd(iob); + cmd->hdr.seqno = card->seqno.ipa++; + reply->seqno = cmd->hdr.seqno; event_timeout = QETH_IPA_TIMEOUT; } else { + reply->seqno = QETH_IDX_COMMAND_SEQNO; event_timeout = QETH_TIMEOUT; } + qeth_prepare_control_data(card, len, iob); + + spin_lock_irqsave(&card->lock, flags); + list_add_tail(&reply->list, &card->cmd_waiter_list); + spin_unlock_irqrestore(&card->lock, flags); timeout = jiffies + event_timeout; @@ -2933,7 +2934,7 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card, memset(cmd, 0, sizeof(struct qeth_ipa_cmd)); cmd->hdr.command = command; cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST; - cmd->hdr.seqno = card->seqno.ipa; + /* cmd->hdr.seqno is set by qeth_send_control_data() */ cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type); cmd->hdr.rel_adapter_no = (__u8) card->info.portno; if (card->options.layer2) -- cgit v1.2.3 From bffd2b61670feef18d2535e9b53364d270a1c991 Mon Sep 17 00:00:00 2001 From: Max Gurtovoy Date: Wed, 24 Jan 2018 17:31:45 +0200 Subject: nvmet: fix PSDT field check in command format PSDT field section according to NVM_Express-1.3: "This field specifies whether PRPs or SGLs are used for any data transfer associated with the command. PRPs shall be used for all Admin commands for NVMe over PCIe. SGLs shall be used for all Admin and I/O commands for NVMe over Fabrics. This field shall be set to 01b for NVMe over Fabrics 1.0 implementations. Suggested-by: Idan Burstein Signed-off-by: Max Gurtovoy Reviewed-by: Christoph Hellwig Signed-off-by: Keith Busch --- drivers/nvme/target/core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 0bd737117a80..a78029e4e5f4 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -520,9 +520,12 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, goto fail; } - /* either variant of SGLs is fine, as we don't support metadata */ - if (unlikely((flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METABUF && - (flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METASEG)) { + /* + * For fabrics, PSDT field shall describe metadata pointer (MPTR) that + * contains an address of a single contiguous physical buffer that is + * byte aligned. + */ + if (unlikely((flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METABUF)) { status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; goto fail; } -- cgit v1.2.3 From 4e09ff5362843dff3accfa84c805c7f3a99de9cd Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 28 Feb 2018 18:20:04 +0800 Subject: virtio-net: disable NAPI only when enabled during XDP set We try to disable NAPI to prevent a single XDP TX queue being used by multiple cpus. But we don't check if device is up (NAPI is enabled), this could result stall because of infinite wait in napi_disable(). Fixing this by checking device state through netif_running() before. Fixes: 4941d472bf95b ("virtio-net: do not reset during XDP set") Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 9bb9e562b893..2d5412317672 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -2185,8 +2185,9 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, } /* Make sure NAPI is not using any XDP TX queues for RX. */ - for (i = 0; i < vi->max_queue_pairs; i++) - napi_disable(&vi->rq[i].napi); + if (netif_running(dev)) + for (i = 0; i < vi->max_queue_pairs; i++) + napi_disable(&vi->rq[i].napi); netif_set_real_num_rx_queues(dev, curr_qp + xdp_qp); err = _virtnet_set_queues(vi, curr_qp + xdp_qp); @@ -2205,7 +2206,8 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, } if (old_prog) bpf_prog_put(old_prog); - virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi); + if (netif_running(dev)) + virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi); } return 0; -- cgit v1.2.3 From 2ddc94c76cc4ccaf51b478315912b38dfdde1afc Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 13:12:08 +0100 Subject: mlxsw: core: Fix flex keys scratchpad offset conflict IP_TTL, IP_ECN and IP_DSCP are using the same offset within the scratchpad as L4 ports. Fix this by shifting all up. Fixes: 5f57e0909136 ("mlxsw: acl: Add ip ttl acl element") Fixes: i80d0fe4710c ("mlxsw: acl: Add ip tos acl element") Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h index f6963b0b4a55..122506daa586 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h @@ -107,20 +107,20 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = { MLXSW_AFK_ELEMENT_INFO_U32(VID, 0x10, 8, 12), MLXSW_AFK_ELEMENT_INFO_U32(PCP, 0x10, 20, 3), MLXSW_AFK_ELEMENT_INFO_U32(TCP_FLAGS, 0x10, 23, 9), - MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x14, 0, 8), - MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x14, 9, 2), - MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x14, 11, 6), - MLXSW_AFK_ELEMENT_INFO_U32(SRC_IP4, 0x18, 0, 32), - MLXSW_AFK_ELEMENT_INFO_U32(DST_IP4, 0x1C, 0, 32), - MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_HI, 0x18, 8), - MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_LO, 0x20, 8), - MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_HI, 0x28, 8), - MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_LO, 0x30, 8), MLXSW_AFK_ELEMENT_INFO_U32(DST_L4_PORT, 0x14, 0, 16), MLXSW_AFK_ELEMENT_INFO_U32(SRC_L4_PORT, 0x14, 16, 16), + MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x18, 0, 8), + MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x18, 9, 2), + MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x18, 11, 6), + MLXSW_AFK_ELEMENT_INFO_U32(SRC_IP4, 0x20, 0, 32), + MLXSW_AFK_ELEMENT_INFO_U32(DST_IP4, 0x24, 0, 32), + MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_HI, 0x20, 8), + MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_LO, 0x28, 8), + MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_HI, 0x30, 8), + MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_LO, 0x38, 8), }; -#define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x38 +#define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x40 struct mlxsw_afk_element_inst { /* element instance in actual block */ const struct mlxsw_afk_element_info *info; -- cgit v1.2.3 From 77d270967c5f723e5910dd073962b6372d7ef466 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 13:12:09 +0100 Subject: mlxsw: spectrum: Fix handling of resource_size_param Current code uses global variables, adjusts them and passes pointer down to devlink. With every other mlxsw_core instance, the previously passed pointer values are rewritten. Fix this by de-globalize the variables and also memcpy size_params during devlink resource registration. Also, introduce a convenient size_param_init helper. Fixes: ef3116e5403e ("mlxsw: spectrum: Register KVD resources with devlink") Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 75 +++++++++++++------------- 1 file changed, 38 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 3dcc58d61506..c364a1ace75d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4207,13 +4207,12 @@ static struct devlink_resource_ops mlxsw_sp_resource_kvd_hash_double_ops = { .size_validate = mlxsw_sp_resource_kvd_hash_double_size_validate, }; -static struct devlink_resource_size_params mlxsw_sp_kvd_size_params; -static struct devlink_resource_size_params mlxsw_sp_linear_size_params; -static struct devlink_resource_size_params mlxsw_sp_hash_single_size_params; -static struct devlink_resource_size_params mlxsw_sp_hash_double_size_params; - static void -mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core) +mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core, + struct devlink_resource_size_params *kvd_size_params, + struct devlink_resource_size_params *linear_size_params, + struct devlink_resource_size_params *hash_double_size_params, + struct devlink_resource_size_params *hash_single_size_params) { u32 single_size_min = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE); @@ -4222,37 +4221,35 @@ mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core) u32 kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE); u32 linear_size_min = 0; - /* KVD top resource */ - mlxsw_sp_kvd_size_params.size_min = kvd_size; - mlxsw_sp_kvd_size_params.size_max = kvd_size; - mlxsw_sp_kvd_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY; - mlxsw_sp_kvd_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY; - - /* Linear part init */ - mlxsw_sp_linear_size_params.size_min = linear_size_min; - mlxsw_sp_linear_size_params.size_max = kvd_size - single_size_min - - double_size_min; - mlxsw_sp_linear_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY; - mlxsw_sp_linear_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY; - - /* Hash double part init */ - mlxsw_sp_hash_double_size_params.size_min = double_size_min; - mlxsw_sp_hash_double_size_params.size_max = kvd_size - single_size_min - - linear_size_min; - mlxsw_sp_hash_double_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY; - mlxsw_sp_hash_double_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY; - - /* Hash single part init */ - mlxsw_sp_hash_single_size_params.size_min = single_size_min; - mlxsw_sp_hash_single_size_params.size_max = kvd_size - double_size_min - - linear_size_min; - mlxsw_sp_hash_single_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY; - mlxsw_sp_hash_single_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY; + devlink_resource_size_params_init(kvd_size_params, kvd_size, kvd_size, + MLXSW_SP_KVD_GRANULARITY, + DEVLINK_RESOURCE_UNIT_ENTRY); + devlink_resource_size_params_init(linear_size_params, linear_size_min, + kvd_size - single_size_min - + double_size_min, + MLXSW_SP_KVD_GRANULARITY, + DEVLINK_RESOURCE_UNIT_ENTRY); + devlink_resource_size_params_init(hash_double_size_params, + double_size_min, + kvd_size - single_size_min - + linear_size_min, + MLXSW_SP_KVD_GRANULARITY, + DEVLINK_RESOURCE_UNIT_ENTRY); + devlink_resource_size_params_init(hash_single_size_params, + single_size_min, + kvd_size - double_size_min - + linear_size_min, + MLXSW_SP_KVD_GRANULARITY, + DEVLINK_RESOURCE_UNIT_ENTRY); } static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) { struct devlink *devlink = priv_to_devlink(mlxsw_core); + struct devlink_resource_size_params hash_single_size_params; + struct devlink_resource_size_params hash_double_size_params; + struct devlink_resource_size_params linear_size_params; + struct devlink_resource_size_params kvd_size_params; u32 kvd_size, single_size, double_size, linear_size; const struct mlxsw_config_profile *profile; int err; @@ -4261,13 +4258,17 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE)) return -EIO; - mlxsw_sp_resource_size_params_prepare(mlxsw_core); + mlxsw_sp_resource_size_params_prepare(mlxsw_core, &kvd_size_params, + &linear_size_params, + &hash_double_size_params, + &hash_single_size_params); + kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE); err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD, true, kvd_size, MLXSW_SP_RESOURCE_KVD, DEVLINK_RESOURCE_ID_PARENT_TOP, - &mlxsw_sp_kvd_size_params, + &kvd_size_params, &mlxsw_sp_resource_kvd_ops); if (err) return err; @@ -4277,7 +4278,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) false, linear_size, MLXSW_SP_RESOURCE_KVD_LINEAR, MLXSW_SP_RESOURCE_KVD, - &mlxsw_sp_linear_size_params, + &linear_size_params, &mlxsw_sp_resource_kvd_linear_ops); if (err) return err; @@ -4291,7 +4292,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) false, double_size, MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, MLXSW_SP_RESOURCE_KVD, - &mlxsw_sp_hash_double_size_params, + &hash_double_size_params, &mlxsw_sp_resource_kvd_hash_double_ops); if (err) return err; @@ -4301,7 +4302,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) false, single_size, MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, MLXSW_SP_RESOURCE_KVD, - &mlxsw_sp_hash_single_size_params, + &hash_single_size_params, &mlxsw_sp_resource_kvd_hash_single_ops); if (err) return err; -- cgit v1.2.3 From 9d45deb04c59b628b21fc5014aff4f9a1d38f969 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 13:12:10 +0100 Subject: mlxsw: spectrum: Treat IPv6 unregistered multicast as broadcast When multicast snooping is enabled, the Linux bridge resorts to flooding unregistered multicast packets to all ports only in case it did not detect a querier in the network. The above condition is not reflected to underlying drivers, which is especially problematic in IPv6 environments, as multicast snooping is enabled by default and since neighbour solicitation packets might be treated as unregistered multicast packets in case there is no corresponding MDB entry. Until the Linux bridge reflects its querier state to underlying drivers, simply treat unregistered multicast packets as broadcast and allow them to reach their destination. Fixes: 9df552ef3e21 ("mlxsw: spectrum: Improve IPv6 unregistered multicast flooding") Signed-off-by: Ido Schimmel Reported-by: David Ahern Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index bbd238e50f05..54262af4e98f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -112,11 +112,11 @@ static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, }; static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, - [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, }; static const int *mlxsw_sp_packet_type_sfgc_types[] = { -- cgit v1.2.3 From b3529af6bb0d4fe72defdd539712ceffaa054fb3 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 13:12:11 +0100 Subject: spectrum: Reference count VLAN entries One of the basic construct in the device is a port-VLAN pair, which can be bound to a FID or a RIF in order to direct packets to the bridge or the router, respectively. Since not all the netdevs are configured with a VLAN (e.g., sw1p1 vs. sw1p1.10), VID 1 is used to represent these and thus this VID can be used by both upper devices of mlxsw ports and by the driver itself. However, this VID is not reference counted and therefore might be freed prematurely, which can result in various WARNINGs. For example: $ ip link add name br0 type bridge vlan_filtering 1 $ teamd -t team0 -d -c '{"runner": {"name": "lacp"}}' $ ip link set dev team0 master br0 $ ip link set dev enp1s0np1 master team0 $ ip address add 192.0.2.1/24 dev enp1s0np1 The enslavement to team0 will fail because team0 already has an upper and thus vlan_vids_del_by_dev() will be executed as part of team's error path which will delete VID 1 from enp1s0np1 (added by br0 as PVID). The WARNING will be generated when the driver will realize it can't find VID 1 on the port and bind it to a RIF. Fix this by adding a reference count to the VLAN entries on the port, in a similar fashion to the reference counting used by the corresponding 'vlan_vid_info' structure in the 8021q driver. Fixes: c57529e1d5d8 ("mlxsw: spectrum: Replace vPorts with Port-VLAN") Reported-by: Tal Bar Signed-off-by: Ido Schimmel Tested-by: Tal Bar Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 8 +++++++- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index c364a1ace75d..c7e941aecc2a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1459,6 +1459,7 @@ mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) } mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port; + mlxsw_sp_port_vlan->ref_count = 1; mlxsw_sp_port_vlan->vid = vid; list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list); @@ -1486,8 +1487,10 @@ mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); - if (mlxsw_sp_port_vlan) + if (mlxsw_sp_port_vlan) { + mlxsw_sp_port_vlan->ref_count++; return mlxsw_sp_port_vlan; + } return mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid); } @@ -1496,6 +1499,9 @@ void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + if (--mlxsw_sp_port_vlan->ref_count != 0) + return; + if (mlxsw_sp_port_vlan->bridge_port) mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); else if (fid) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index bdd8f94a452c..4ec1ca3c96c8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -211,6 +211,7 @@ struct mlxsw_sp_port_vlan { struct list_head list; struct mlxsw_sp_port *mlxsw_sp_port; struct mlxsw_sp_fid *fid; + unsigned int ref_count; u16 vid; struct mlxsw_sp_bridge_port *bridge_port; struct list_head bridge_vlan_node; -- cgit v1.2.3 From b1b13780ab06ef8c770dd9cbe31dac549a11630e Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 14 Feb 2018 11:18:25 -0800 Subject: drm/i915: Fix rsvd2 mask when out-fence is returned GENMASK_ULL wants the high bit of the mask first. The current value cancels the in-fence when an out-fence is returned. Fixes: fec0445caa273 ("drm/i915: Support explicit fencing for execbuf") Testcase: igt/gem_exec_fence/keep-in-fence* Cc: Chris Wilson Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180214191827.8465-1-daniele.ceraolospurio@intel.com Cc: # v4.12+ (cherry picked from commit b6a88e4a804cf5a71159906e16df2c1fc7196f92) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 4401068ff468..36fca0e7b4ca 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -2410,7 +2410,7 @@ err_request: if (out_fence) { if (err == 0) { fd_install(out_fence_fd, out_fence->file); - args->rsvd2 &= GENMASK_ULL(0, 31); /* keep in-fence */ + args->rsvd2 &= GENMASK_ULL(31, 0); /* keep in-fence */ args->rsvd2 |= (u64)out_fence_fd << 32; out_fence_fd = -1; } else { -- cgit v1.2.3 From da343b6d90e11132f1e917d865d88ee35d6e6d00 Mon Sep 17 00:00:00 2001 From: Sergey Gorenko Date: Sun, 25 Feb 2018 13:39:48 +0200 Subject: IB/mlx5: Fix incorrect size of klms in the memory region The value of mr->ndescs greater than mr->max_descs is set in the function mlx5_ib_sg_to_klms() if sg_nents is greater than mr->max_descs. This is an invalid value and it causes the following error when registering mr: mlx5_0:dump_cqe:276:(pid 193): dump error cqe 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000030: 00 00 00 00 0f 00 78 06 25 00 00 8b 08 1e 8f d3 Cc: # 4.5 Fixes: b005d3164713 ("mlx5: Add arbitrary sg list support") Signed-off-by: Sergey Gorenko Tested-by: Laurence Oberman Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 556e015678de..1961c6a45437 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1816,7 +1816,6 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr, mr->ibmr.iova = sg_dma_address(sg) + sg_offset; mr->ibmr.length = 0; - mr->ndescs = sg_nents; for_each_sg(sgl, sg, sg_nents, i) { if (unlikely(i >= mr->max_descs)) @@ -1828,6 +1827,7 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr, sg_offset = 0; } + mr->ndescs = i; if (sg_offset_p) *sg_offset_p = sg_offset; -- cgit v1.2.3 From e7b169f34403becd3c9fd3b6e46614ab788f2187 Mon Sep 17 00:00:00 2001 From: Noa Osherovich Date: Sun, 25 Feb 2018 13:39:51 +0200 Subject: IB/mlx5: Avoid passing an invalid QP type to firmware During QP creation, the mlx5 driver translates the QP type to an internal value which is passed on to FW. There was no check to make sure that the translated value is valid, and -EINVAL was coerced into the mailbox command. Current firmware refuses this as an invalid QP type, but future/past firmware may do something else. Fixes: 09a7d9eca1a6c ('{net,IB}/mlx5: QP/XRCD commands via mlx5 ifc') Reviewed-by: Ilya Lesokhin Signed-off-by: Noa Osherovich Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/qp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 39d24bf694a8..e8d7eaf0670c 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1584,6 +1584,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, u32 uidx = MLX5_IB_DEFAULT_UIDX; struct mlx5_ib_create_qp ucmd; struct mlx5_ib_qp_base *base; + int mlx5_st; void *qpc; u32 *in; int err; @@ -1592,6 +1593,10 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, spin_lock_init(&qp->sq.lock); spin_lock_init(&qp->rq.lock); + mlx5_st = to_mlx5_st(init_attr->qp_type); + if (mlx5_st < 0) + return -EINVAL; + if (init_attr->rwq_ind_tbl) { if (!udata) return -ENOSYS; @@ -1753,7 +1758,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); - MLX5_SET(qpc, qpc, st, to_mlx5_st(init_attr->qp_type)); + MLX5_SET(qpc, qpc, st, mlx5_st); MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); if (init_attr->qp_type != MLX5_IB_QPT_REG_UMR) -- cgit v1.2.3 From aba462134634b502d720e15b23154f21cfa277e5 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Sun, 25 Feb 2018 13:39:53 +0200 Subject: {net, IB}/mlx5: Raise fatal IB event when sys error occurs All other mlx5_events report the port number as 1 based, which is how FW reports it in the port event EQE. Reporting 0 for this event causes mlx5_ib to not raise a fatal event notification to registered clients due to a seemingly invalid port. All switch cases in mlx5_ib_event that go through the port check are supposed to set the port now, so just do it once at variable declaration. Fixes: 89d44f0a6c73("net/mlx5_core: Add pci error handlers to mlx5_core driver") Reviewed-by: Majd Dibbiny Signed-off-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 11 ++--------- drivers/net/ethernet/mellanox/mlx5/core/health.c | 2 +- 2 files changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 4236c8086820..bab38c6647d7 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -3263,7 +3263,7 @@ static void mlx5_ib_handle_event(struct work_struct *_work) struct mlx5_ib_dev *ibdev; struct ib_event ibev; bool fatal = false; - u8 port = 0; + u8 port = (u8)work->param; if (mlx5_core_is_mp_slave(work->dev)) { ibdev = mlx5_ib_get_ibdev_from_mpi(work->context); @@ -3283,8 +3283,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) case MLX5_DEV_EVENT_PORT_UP: case MLX5_DEV_EVENT_PORT_DOWN: case MLX5_DEV_EVENT_PORT_INITIALIZED: - port = (u8)work->param; - /* In RoCE, port up/down events are handled in * mlx5_netdev_event(). */ @@ -3298,24 +3296,19 @@ static void mlx5_ib_handle_event(struct work_struct *_work) case MLX5_DEV_EVENT_LID_CHANGE: ibev.event = IB_EVENT_LID_CHANGE; - port = (u8)work->param; break; case MLX5_DEV_EVENT_PKEY_CHANGE: ibev.event = IB_EVENT_PKEY_CHANGE; - port = (u8)work->param; - schedule_work(&ibdev->devr.ports[port - 1].pkey_change_work); break; case MLX5_DEV_EVENT_GUID_CHANGE: ibev.event = IB_EVENT_GID_CHANGE; - port = (u8)work->param; break; case MLX5_DEV_EVENT_CLIENT_REREG: ibev.event = IB_EVENT_CLIENT_REREGISTER; - port = (u8)work->param; break; case MLX5_DEV_EVENT_DELAY_DROP_TIMEOUT: schedule_work(&ibdev->delay_drop.delay_drop_work); @@ -3327,7 +3320,7 @@ static void mlx5_ib_handle_event(struct work_struct *_work) ibev.device = &ibdev->ib_dev; ibev.element.port_num = port; - if (port < 1 || port > ibdev->num_ports) { + if (!rdma_is_port_valid(&ibdev->ib_dev, port)) { mlx5_ib_warn(ibdev, "warning: event on port %d\n", port); goto out; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 21d29f7936f6..d39b0b7011b2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -124,7 +124,7 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force) trigger_cmd_completions(dev); } - mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 0); + mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 1); mlx5_core_err(dev, "end\n"); unlock: -- cgit v1.2.3 From 65389322b28f81cc137b60a41044c2d958a7b950 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Sun, 25 Feb 2018 13:39:54 +0200 Subject: IB/mlx: Set slid to zero in Ethernet completion struct IB spec says that a lid should be ignored when link layer is Ethernet, for example when building or parsing a CM request message (CA17-34). However, since ib_lid_be16() and ib_lid_cpu16() validates the slid, not only when link layer is IB, we set the slid to zero to prevent false warnings in the kernel log. Fixes: 62ede7779904 ("Add OPA extended LID support") Reviewed-by: Majd Dibbiny Signed-off-by: Moni Shoua Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx4/cq.c | 4 +++- drivers/infiniband/hw/mlx5/cq.c | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 9a566ee3ceff..82adc0d1d30e 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -601,6 +601,7 @@ static void use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct wc->dlid_path_bits = 0; if (is_eth) { + wc->slid = 0; wc->vlan_id = be16_to_cpu(hdr->tun.sl_vid); memcpy(&(wc->smac[0]), (char *)&hdr->tun.mac_31_0, 4); memcpy(&(wc->smac[4]), (char *)&hdr->tun.slid_mac_47_32, 2); @@ -851,7 +852,6 @@ repoll: } } - wc->slid = be16_to_cpu(cqe->rlid); g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); wc->src_qp = g_mlpath_rqpn & 0xffffff; wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; @@ -860,6 +860,7 @@ repoll: wc->wc_flags |= mlx4_ib_ipoib_csum_ok(cqe->status, cqe->checksum) ? IB_WC_IP_CSUM_OK : 0; if (is_eth) { + wc->slid = 0; wc->sl = be16_to_cpu(cqe->sl_vid) >> 13; if (be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_CVLAN_PRESENT_MASK) { @@ -871,6 +872,7 @@ repoll: memcpy(wc->smac, cqe->smac, ETH_ALEN); wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC); } else { + wc->slid = be16_to_cpu(cqe->rlid); wc->sl = be16_to_cpu(cqe->sl_vid) >> 12; wc->vlan_id = 0xffff; } diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 5b974fb97611..b5cfdaa9c7c8 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -226,7 +226,6 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, wc->ex.invalidate_rkey = be32_to_cpu(cqe->imm_inval_pkey); break; } - wc->slid = be16_to_cpu(cqe->slid); wc->src_qp = be32_to_cpu(cqe->flags_rqpn) & 0xffffff; wc->dlid_path_bits = cqe->ml_path; g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3; @@ -241,10 +240,12 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, } if (ll != IB_LINK_LAYER_ETHERNET) { + wc->slid = be16_to_cpu(cqe->slid); wc->sl = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0xf; return; } + wc->slid = 0; vlan_present = cqe->l4_l3_hdr_type & 0x1; roce_packet_type = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0x3; if (vlan_present) { -- cgit v1.2.3 From 2fb4f4eadd180a50112618dd9c5fef7fc50d4f08 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Sun, 25 Feb 2018 13:39:56 +0200 Subject: IB/core: Fix missing RDMA cgroups release in case of failure to register device During IB device registration process, if query_device() fails or if ib_core fails to registers sysfs entries, rdma cgroup cleanup is skipped. Cc: # v4.2+ Fixes: 4be3a4fa51f4 ("IB/core: Fix kernel crash during fail to initialize device") Reviewed-by: Daniel Jurgens Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index e8010e73a1cf..bb065c9449be 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -536,14 +536,14 @@ int ib_register_device(struct ib_device *device, ret = device->query_device(device, &device->attrs, &uhw); if (ret) { pr_warn("Couldn't query the device attributes\n"); - goto cache_cleanup; + goto cg_cleanup; } ret = ib_device_register_sysfs(device, port_callback); if (ret) { pr_warn("Couldn't register device %s with driver model\n", device->name); - goto cache_cleanup; + goto cg_cleanup; } device->reg_state = IB_DEV_REGISTERED; @@ -559,6 +559,8 @@ int ib_register_device(struct ib_device *device, mutex_unlock(&device_mutex); return 0; +cg_cleanup: + ib_device_unregister_rdmacg(device); cache_cleanup: ib_cache_cleanup_one(device); ib_cache_release_one(device); -- cgit v1.2.3 From a45bc17b360d75fac9ced85e99fda14bf38b4dc3 Mon Sep 17 00:00:00 2001 From: Devesh Sharma Date: Mon, 26 Feb 2018 01:51:37 -0800 Subject: RDMA/bnxt_re: Unconditionly fence non wire memory operations HW requires an unconditonal fence for all non-wire memory operations through SQ. This guarantees the completions of these memory operations. Signed-off-by: Devesh Sharma Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 643174d949a8..755f1ccd82bb 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -2227,10 +2227,13 @@ static int bnxt_re_build_inv_wqe(struct ib_send_wr *wr, wqe->type = BNXT_QPLIB_SWQE_TYPE_LOCAL_INV; wqe->local_inv.inv_l_key = wr->ex.invalidate_rkey; + /* Need unconditional fence for local invalidate + * opcode to work as expected. + */ + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; + if (wr->send_flags & IB_SEND_SIGNALED) wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP; - if (wr->send_flags & IB_SEND_FENCE) - wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; if (wr->send_flags & IB_SEND_SOLICITED) wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SOLICIT_EVENT; @@ -2251,8 +2254,12 @@ static int bnxt_re_build_reg_wqe(struct ib_reg_wr *wr, wqe->frmr.levels = qplib_frpl->hwq.level + 1; wqe->type = BNXT_QPLIB_SWQE_TYPE_REG_MR; - if (wr->wr.send_flags & IB_SEND_FENCE) - wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; + /* Need unconditional fence for reg_mr + * opcode to function as expected. + */ + + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; + if (wr->wr.send_flags & IB_SEND_SIGNALED) wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP; -- cgit v1.2.3 From c354dff00db8df80f271418d8392065e10ffffb6 Mon Sep 17 00:00:00 2001 From: Devesh Sharma Date: Mon, 26 Feb 2018 01:51:38 -0800 Subject: RDMA/bnxt_re: Fix incorrect DB offset calculation To support host systems with non 4K page size, l2_db_size shall be calculated with 4096 instead of PAGE_SIZE. Also, supply the host page size to FW during initialization. Signed-off-by: Devesh Sharma Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 6 +++++- drivers/infiniband/hw/bnxt_re/qplib_rcfw.h | 1 + drivers/infiniband/hw/bnxt_re/qplib_sp.c | 3 ++- drivers/infiniband/hw/bnxt_re/roce_hsi.h | 25 ++++++++++++++++++++++++- 4 files changed, 32 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 8329ec6a7946..14d153d4013c 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -460,7 +460,11 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, int rc; RCFW_CMD_PREP(req, INITIALIZE_FW, cmd_flags); - + /* Supply (log-base-2-of-host-page-size - base-page-shift) + * to bono to adjust the doorbell page sizes. + */ + req.log2_dbr_pg_size = cpu_to_le16(PAGE_SHIFT - + RCFW_DBR_BASE_PAGE_SHIFT); /* * VFs need not setup the HW context area, PF * shall setup this area for VF. Skipping the diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h index 6bee6e3636ea..c7cce2e4185e 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h @@ -49,6 +49,7 @@ #define RCFW_COMM_SIZE 0x104 #define RCFW_DBR_PCI_BAR_REGION 2 +#define RCFW_DBR_BASE_PAGE_SHIFT 12 #define RCFW_CMD_PREP(req, CMD, cmd_flags) \ do { \ diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index 03057983341f..ee98e5efef84 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -139,7 +139,8 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, attr->max_pkey = le32_to_cpu(sb->max_pkeys); attr->max_inline_data = le32_to_cpu(sb->max_inline_data); - attr->l2_db_size = (sb->l2_db_space_size + 1) * PAGE_SIZE; + attr->l2_db_size = (sb->l2_db_space_size + 1) * + (0x01 << RCFW_DBR_BASE_PAGE_SHIFT); attr->max_sgid = le32_to_cpu(sb->max_gid); bnxt_qplib_query_version(rcfw, attr->fw_ver); diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h index 2d7ea096a247..3e5a4f760d0e 100644 --- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h +++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h @@ -1761,7 +1761,30 @@ struct cmdq_initialize_fw { #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_2M (0x3UL << 4) #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_8M (0x4UL << 4) #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_1G (0x5UL << 4) - __le16 reserved16; + /* This value is (log-base-2-of-DBR-page-size - 12). + * 0 for 4KB. HW supported values are enumerated below. + */ + __le16 log2_dbr_pg_size; + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_MASK 0xfUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_SFT 0 + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4K 0x0UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8K 0x1UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16K 0x2UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32K 0x3UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64K 0x4UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128K 0x5UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_256K 0x6UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_512K 0x7UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_1M 0x8UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_2M 0x9UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4M 0xaUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8M 0xbUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16M 0xcUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32M 0xdUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64M 0xeUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M 0xfUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_LAST \ + CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M __le64 qpc_page_dir; __le64 mrw_page_dir; __le64 srq_page_dir; -- cgit v1.2.3 From 72a6d72c2cd03bba7b70117b63dea83d2de88057 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 14 Feb 2018 19:38:40 +0200 Subject: drm/i915/audio: fix check for av_enc_map overflow Turns out -1 >= ARRAY_SIZE() is always true. Move the bounds check where we know pipe >= 0 and next to the array indexing where it makes most sense. Fixes: 9965db26ac05 ("drm/i915: Check for fused or unused pipes") Fixes: 0b7029b7e43f ("drm/i915: Check for fused or unused pipes") Cc: # v4.10+ Cc: Mika Kahola Cc: Rodrigo Vivi Cc: Jani Nikula Cc: Joonas Lahtinen Cc: intel-gfx@lists.freedesktop.org Reviewed-by: Dhinakaran Pandiyan Reviewed-by: Mika Kahola Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180214173840.25360-1-jani.nikula@intel.com (cherry picked from commit cdb3db8542d854bd678d60cd28861b042e191672) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/intel_audio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 522d54fecb53..4a01f62a392d 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -779,11 +779,11 @@ static struct intel_encoder *get_saved_enc(struct drm_i915_private *dev_priv, { struct intel_encoder *encoder; - if (WARN_ON(pipe >= ARRAY_SIZE(dev_priv->av_enc_map))) - return NULL; - /* MST */ if (pipe >= 0) { + if (WARN_ON(pipe >= ARRAY_SIZE(dev_priv->av_enc_map))) + return NULL; + encoder = dev_priv->av_enc_map[pipe]; /* * when bootup, audio driver may not know it is -- cgit v1.2.3 From 497158aa5f520db50452ef928c0f955cb42f2e77 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 26 Feb 2018 01:51:39 -0800 Subject: RDMA/bnxt_re: Fix the ib_reg failure cleanup Release the netdev references in the cleanup path. Invokes the cleanup routines if bnxt_re_ib_reg fails. Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 33a448036c2e..604c805ceaa7 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -1416,9 +1416,12 @@ static void bnxt_re_task(struct work_struct *work) switch (re_work->event) { case NETDEV_REGISTER: rc = bnxt_re_ib_reg(rdev); - if (rc) + if (rc) { dev_err(rdev_to_dev(rdev), "Failed to register with IB: %#x", rc); + bnxt_re_remove_one(rdev); + bnxt_re_dev_unreg(rdev); + } break; case NETDEV_UP: bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, -- cgit v1.2.3 From 4cd482c12be473ae507eba232a8374c798233e42 Mon Sep 17 00:00:00 2001 From: Muneendra Kumar M Date: Tue, 27 Feb 2018 21:51:49 -0800 Subject: IB/core : Add null pointer check in addr_resolve dev_get_by_index is being called in addr_resolve function which returns NULL and NULL pointer access leads to kernel crash. Following call trace is observed while running rdma_lat test application [ 146.173149] BUG: unable to handle kernel NULL pointer dereference at 00000000000004a0 [ 146.173198] IP: addr_resolve+0x9e/0x3e0 [ib_core] [ 146.173221] PGD 0 P4D 0 [ 146.173869] Oops: 0000 [#1] SMP PTI [ 146.182859] CPU: 8 PID: 127 Comm: kworker/8:1 Tainted: G O 4.15.0-rc6+ #18 [ 146.183758] Hardware name: LENOVO System x3650 M5: -[8871AC1]-/01KN179, BIOS-[TCE132H-2.50]- 10/11/2017 [ 146.184691] Workqueue: ib_cm cm_work_handler [ib_cm] [ 146.185632] RIP: 0010:addr_resolve+0x9e/0x3e0 [ib_core] [ 146.186584] RSP: 0018:ffffc9000362faa0 EFLAGS: 00010246 [ 146.187521] RAX: 000000000000001b RBX: ffffc9000362fc08 RCX: 0000000000000006 [ 146.188472] RDX: 0000000000000000 RSI: 0000000000000096 RDI : ffff88087fc16990 [ 146.189427] RBP: ffffc9000362fb18 R08: 00000000ffffff9d R09: 00000000000004ac [ 146.190392] R10: 00000000000001e7 R11: 0000000000000001 R12: ffff88086af2e090 [ 146.191361] R13: 0000000000000000 R14: 0000000000000001 R15: 00000000ffffff9d [ 146.192327] FS: 0000000000000000(0000) GS:ffff88087fc00000(0000) knlGS:0000000000000000 [ 146.193301] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 146.194274] CR2: 00000000000004a0 CR3: 000000000220a002 CR4: 00000000003606e0 [ 146.195258] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 146.196256] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 146.197231] Call Trace: [ 146.198209] ? rdma_addr_register_client+0x30/0x30 [ib_core] [ 146.199199] rdma_resolve_ip+0x1af/0x280 [ib_core] [ 146.200196] rdma_addr_find_l2_eth_by_grh+0x154/0x2b0 [ib_core] The below patch adds the missing NULL pointer check returned by dev_get_by_index before accessing the netdev to avoid kernel crash. We observed the below crash when we try to do the below test. server client --------- --------- |1.1.1.1|<----rxe-channel--->|1.1.1.2| --------- --------- On server: rdma_lat -c -n 2 -s 1024 On client:rdma_lat 1.1.1.1 -c -n 2 -s 1024 Fixes: 200298326b27 ("IB/core: Validate route when we init ah") Signed-off-by: Muneendra Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index a5b4cf030c11..9183d148d644 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -550,18 +550,13 @@ static int addr_resolve(struct sockaddr *src_in, dst_release(dst); } - if (ndev->flags & IFF_LOOPBACK) { - ret = rdma_translate_ip(dst_in, addr); - /* - * Put the loopback device and get the translated - * device instead. - */ + if (ndev) { + if (ndev->flags & IFF_LOOPBACK) + ret = rdma_translate_ip(dst_in, addr); + else + addr->bound_dev_if = ndev->ifindex; dev_put(ndev); - ndev = dev_get_by_index(addr->net, addr->bound_dev_if); - } else { - addr->bound_dev_if = ndev->ifindex; } - dev_put(ndev); return ret; } -- cgit v1.2.3 From 1b0008450f23632b029e9fde9a71be90f119ec35 Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Thu, 15 Feb 2018 15:26:41 +0530 Subject: drm/i915/cnl: Fix PORT_TX_DW5/7 register address Register Address for CNL_PORT_DW5_LN0_D is 0x162E54, but current code is defining it as 0x162ED4. Similarly for CNL_PORT_DW7_LN0_D register address is defined 0x162EDC instead of 0x162E5C, fix it. Signed-off-by: Mahesh Kumar Fixes: 04416108ccea ("drm/i915/cnl: Add registers related to voltage swing sequences.") Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180215095643.3844-2-mahesh1.kumar@intel.com (cherry picked from commit e103962611b2d464be6ab596d7b3495fe7b4c132) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a2108e35c599..33eb0c5b1d32 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2027,7 +2027,7 @@ enum i915_power_well_id { #define _CNL_PORT_TX_DW5_LN0_AE 0x162454 #define _CNL_PORT_TX_DW5_LN0_B 0x162654 #define _CNL_PORT_TX_DW5_LN0_C 0x162C54 -#define _CNL_PORT_TX_DW5_LN0_D 0x162ED4 +#define _CNL_PORT_TX_DW5_LN0_D 0x162E54 #define _CNL_PORT_TX_DW5_LN0_F 0x162854 #define CNL_PORT_TX_DW5_GRP(port) _MMIO_PORT6(port, \ _CNL_PORT_TX_DW5_GRP_AE, \ @@ -2058,7 +2058,7 @@ enum i915_power_well_id { #define _CNL_PORT_TX_DW7_LN0_AE 0x16245C #define _CNL_PORT_TX_DW7_LN0_B 0x16265C #define _CNL_PORT_TX_DW7_LN0_C 0x162C5C -#define _CNL_PORT_TX_DW7_LN0_D 0x162EDC +#define _CNL_PORT_TX_DW7_LN0_D 0x162E5C #define _CNL_PORT_TX_DW7_LN0_F 0x16285C #define CNL_PORT_TX_DW7_GRP(port) _MMIO_PORT6(port, \ _CNL_PORT_TX_DW7_GRP_AE, \ -- cgit v1.2.3 From e659d14ed48096f87a678e7ebbdf286a817b4d0e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 19 Feb 2018 14:01:44 +0000 Subject: drm/i915: Clear the in-use marker on execbuf failure If we fail to unbind the vma (due to a signal on an active buffer that needs to be moved for the next execbuf), then we need to clear the persistent tracking state we setup for this execbuf. Fixes: c7c6e46f913b ("drm/i915: Convert execbuf to use struct-of-array packing for critical fields") Testcase: igt/gem_fenced_exec_thrash/no-spare-fences-busy* Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Cc: # v4.14+ Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180219140144.24004-1-chris@chris-wilson.co.uk (cherry picked from commit ed2f3532321083cf40e4da4e36234880e0136136) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 36fca0e7b4ca..3ab1ace2a6bd 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -505,6 +505,8 @@ eb_add_vma(struct i915_execbuffer *eb, unsigned int i, struct i915_vma *vma) list_add_tail(&vma->exec_link, &eb->unbound); if (drm_mm_node_allocated(&vma->node)) err = i915_vma_unbind(vma); + if (unlikely(err)) + vma->exec_flags = NULL; } return err; } -- cgit v1.2.3 From fa89782b4f9c40d40e3f7d9ad7ef14e0bb0c3ca0 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 20 Feb 2018 10:47:42 +0000 Subject: drm/i915: Make global seqno known in i915_gem_request_execute tracepoint Commit fe49789fab97 ("drm/i915: Deconstruct execute fence") re-arranged the code and moved the i915_gem_request_execute tracepoint to before the global seqno is assigned to the request. We need to move the tracepoint a bit later so this information is once again available. Signed-off-by: Tvrtko Ursulin Fixes: fe49789fab97 ("drm/i915: Deconstruct execute fence") Cc: Chris Wilson Cc: Tvrtko Ursulin Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: intel-gfx@lists.freedesktop.org Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180220104742.565-1-tvrtko.ursulin@linux.intel.com (cherry picked from commit 158863fb50968c0ae85e87a401221425c941b9f0) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_gem_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c index e09d18df8b7f..a3e93d46316a 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.c +++ b/drivers/gpu/drm/i915/i915_gem_request.c @@ -476,8 +476,6 @@ void __i915_gem_request_submit(struct drm_i915_gem_request *request) GEM_BUG_ON(!irqs_disabled()); lockdep_assert_held(&engine->timeline->lock); - trace_i915_gem_request_execute(request); - /* Transfer from per-context onto the global per-engine timeline */ timeline = engine->timeline; GEM_BUG_ON(timeline == request->timeline); @@ -501,6 +499,8 @@ void __i915_gem_request_submit(struct drm_i915_gem_request *request) list_move_tail(&request->link, &timeline->requests); spin_unlock(&request->timeline->lock); + trace_i915_gem_request_execute(request); + wake_up_all(&request->execute); } -- cgit v1.2.3 From 73469585510d5161368c899b7eacd58c824b2b24 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Fri, 29 Dec 2017 17:06:41 +0800 Subject: drm/amdgpu: fix&cleanups for wb_clear fix: should do right shift on wb before clearing cleanups: 1,should memset all wb buffer 2,set max wb number to 128 (total 4KB) is big enough Signed-off-by: Monk Liu Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 3e6f27d363e9..f281fa8cc831 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1072,7 +1072,7 @@ static inline void amdgpu_set_ib_value(struct amdgpu_cs_parser *p, /* * Writeback */ -#define AMDGPU_MAX_WB 512 /* Reserve at most 512 WB slots for amdgpu-owned rings. */ +#define AMDGPU_MAX_WB 128 /* Reserve at most 128 WB slots for amdgpu-owned rings. */ struct amdgpu_wb { struct amdgpu_bo *wb_obj; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index d2a5f48c5767..5b7443313231 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -492,7 +492,7 @@ static int amdgpu_device_wb_init(struct amdgpu_device *adev) memset(&adev->wb.used, 0, sizeof(adev->wb.used)); /* clear wb memory */ - memset((char *)adev->wb.wb, 0, AMDGPU_MAX_WB * sizeof(uint32_t)); + memset((char *)adev->wb.wb, 0, AMDGPU_MAX_WB * sizeof(uint32_t) * 8); } return 0; @@ -530,8 +530,9 @@ int amdgpu_device_wb_get(struct amdgpu_device *adev, u32 *wb) */ void amdgpu_device_wb_free(struct amdgpu_device *adev, u32 wb) { + wb >>= 3; if (wb < adev->wb.num_wb) - __clear_bit(wb >> 3, adev->wb.used); + __clear_bit(wb, adev->wb.used); } /** -- cgit v1.2.3 From 7b6cbae2b15b13378995aa8ec049083713d4fbcc Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Thu, 18 Jan 2018 16:58:04 +0800 Subject: drm/amdgpu: skip ECC for SRIOV in gmc late_init Signed-off-by: Monk Liu Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 4dd469188e2b..9538f941b000 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -673,7 +673,7 @@ static int gmc_v9_0_late_init(void *handle) for(i = 0; i < AMDGPU_MAX_VMHUBS; ++i) BUG_ON(vm_inv_eng[i] > 16); - if (adev->asic_type == CHIP_VEGA10) { + if (adev->asic_type == CHIP_VEGA10 && !amdgpu_sriov_vf(adev)) { r = gmc_v9_0_ecc_available(adev); if (r == 1) { DRM_INFO("ECC is active.\n"); -- cgit v1.2.3 From 6ec956f5f57e81523a787eede9d82357465d639e Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Fri, 19 Jan 2018 19:02:16 +0800 Subject: drm/amdgpu: only flush hotplug work without DC since hotplug_work is initialized under the case of no dc support Signed-off-by: Monk Liu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c index f6f2a662bb8f..11dfe57bd8bb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c @@ -208,7 +208,8 @@ int amdgpu_irq_init(struct amdgpu_device *adev) r = drm_irq_install(adev->ddev, adev->ddev->pdev->irq); if (r) { adev->irq.installed = false; - flush_work(&adev->hotplug_work); + if (!amdgpu_device_has_dc_support(adev)) + flush_work(&adev->hotplug_work); cancel_work_sync(&adev->reset_work); return r; } @@ -234,7 +235,8 @@ void amdgpu_irq_fini(struct amdgpu_device *adev) adev->irq.installed = false; if (adev->irq.msi_enabled) pci_disable_msi(adev->pdev); - flush_work(&adev->hotplug_work); + if (!amdgpu_device_has_dc_support(adev)) + flush_work(&adev->hotplug_work); cancel_work_sync(&adev->reset_work); } -- cgit v1.2.3 From 113890ee99575a5340ab8729b207e48aaac2eb06 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Fri, 19 Jan 2018 19:06:31 +0800 Subject: drm/amdgpu: cond_exec only for schedule with a job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit issue: under SR-IOV sometimes the iB test will fail on gfx ring fix: with cond_exec inserted in RB the gfx engine would skip part packets if RLCV issue PREEMPT on gfx engine if gfx engine is prior to COND_EXEC packet, this is okay for regular command from UMD, but for the ib test since the whole dma format doesn't support PREEMPT so must remove the COND_EXEC from it. Signed-off-by: Monk Liu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index 8ea342dc6376..7f2c314581d4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -181,7 +181,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, } } - if (ring->funcs->init_cond_exec) + if (job && ring->funcs->init_cond_exec) patch_offset = amdgpu_ring_init_cond_exec(ring); #ifdef CONFIG_X86_64 -- cgit v1.2.3 From ed9324afc0ec1ebe5dcef632eee6381f6ebf8fd5 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Tue, 23 Jan 2018 18:29:22 +0800 Subject: drm/amdgpu: change gfx9 ib test to use WB two reasons to switch SCRATCH reg method to WB method: 1)Because when doing IB test we don't want to involve KIQ health status affect, and since SCRATCH register access is go through KIQ that way GFX IB test would failed due to KIQ fail. 2)acccessing SCRATCH register cost much more time than WB method because SCRATCH register access runs through KIQ which at least could begin after GPU world switch back to current Guest VF Signed-off-by: Monk Liu Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 107 ++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 848008ef46b8..e9cc03e78bb0 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -271,58 +271,65 @@ static int gfx_v9_0_ring_test_ring(struct amdgpu_ring *ring) static int gfx_v9_0_ring_test_ib(struct amdgpu_ring *ring, long timeout) { - struct amdgpu_device *adev = ring->adev; - struct amdgpu_ib ib; - struct dma_fence *f = NULL; - uint32_t scratch; - uint32_t tmp = 0; - long r; - - r = amdgpu_gfx_scratch_get(adev, &scratch); - if (r) { - DRM_ERROR("amdgpu: failed to get scratch reg (%ld).\n", r); - return r; - } - WREG32(scratch, 0xCAFEDEAD); - memset(&ib, 0, sizeof(ib)); - r = amdgpu_ib_get(adev, NULL, 256, &ib); - if (r) { - DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r); - goto err1; - } - ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); - ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START)); - ib.ptr[2] = 0xDEADBEEF; - ib.length_dw = 3; - - r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f); - if (r) - goto err2; - - r = dma_fence_wait_timeout(f, false, timeout); - if (r == 0) { - DRM_ERROR("amdgpu: IB test timed out.\n"); - r = -ETIMEDOUT; - goto err2; - } else if (r < 0) { - DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r); - goto err2; - } - tmp = RREG32(scratch); - if (tmp == 0xDEADBEEF) { - DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx); - r = 0; - } else { - DRM_ERROR("amdgpu: ib test failed (scratch(0x%04X)=0x%08X)\n", - scratch, tmp); - r = -EINVAL; - } + struct amdgpu_device *adev = ring->adev; + struct amdgpu_ib ib; + struct dma_fence *f = NULL; + + unsigned index; + uint64_t gpu_addr; + uint32_t tmp; + long r; + + r = amdgpu_device_wb_get(adev, &index); + if (r) { + dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r); + return r; + } + + gpu_addr = adev->wb.gpu_addr + (index * 4); + adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD); + memset(&ib, 0, sizeof(ib)); + r = amdgpu_ib_get(adev, NULL, 16, &ib); + if (r) { + DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r); + goto err1; + } + ib.ptr[0] = PACKET3(PACKET3_WRITE_DATA, 3); + ib.ptr[1] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM; + ib.ptr[2] = lower_32_bits(gpu_addr); + ib.ptr[3] = upper_32_bits(gpu_addr); + ib.ptr[4] = 0xDEADBEEF; + ib.length_dw = 5; + + r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f); + if (r) + goto err2; + + r = dma_fence_wait_timeout(f, false, timeout); + if (r == 0) { + DRM_ERROR("amdgpu: IB test timed out.\n"); + r = -ETIMEDOUT; + goto err2; + } else if (r < 0) { + DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r); + goto err2; + } + + tmp = adev->wb.wb[index]; + if (tmp == 0xDEADBEEF) { + DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx); + r = 0; + } else { + DRM_ERROR("ib test on ring %d failed\n", ring->idx); + r = -EINVAL; + } + err2: - amdgpu_ib_free(adev, &ib, NULL); - dma_fence_put(f); + amdgpu_ib_free(adev, &ib, NULL); + dma_fence_put(f); err1: - amdgpu_gfx_scratch_free(adev, scratch); - return r; + amdgpu_device_wb_free(adev, index); + return r; } -- cgit v1.2.3 From c12aba3acde52e2ae7807e4e263dfba34fcdbb0c Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Wed, 24 Jan 2018 12:20:32 +0800 Subject: drm/amdgpu: move WB_FREE to correct place WB_FREE should be put after all engines's hw_fini done, otherwise the invalid wptr/rptr_addr would still be used by engines which trigger abnormal bugs. This fixes couple DMAR reading error in host side for SRIOV after guest kmd is unloaded. Signed-off-by: Monk Liu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 5b7443313231..41244858df64 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1459,11 +1459,6 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.hw) continue; - if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) { - amdgpu_free_static_csa(adev); - amdgpu_device_wb_fini(adev); - amdgpu_device_vram_scratch_fini(adev); - } if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE) { @@ -1493,6 +1488,13 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.sw) continue; + + if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) { + amdgpu_free_static_csa(adev); + amdgpu_device_wb_fini(adev); + amdgpu_device_vram_scratch_fini(adev); + } + r = adev->ip_blocks[i].version->funcs->sw_fini((void *)adev); /* XXX handle errors */ if (r) { -- cgit v1.2.3 From fe19b862f18ec09c34dc09e8134e08dbfd601876 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Tue, 23 Jan 2018 19:17:56 +0800 Subject: drm/amdgpu: increase gart size to 512MB 256MB is too small consider PTE/PDE shadow and TTM eviction activity Signed-off-by: Monk Liu Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 9538f941b000..67cd1fe17649 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -792,7 +792,7 @@ static int gmc_v9_0_mc_init(struct amdgpu_device *adev) switch (adev->asic_type) { case CHIP_VEGA10: /* all engines support GPUVM */ default: - adev->gmc.gart_size = 256ULL << 20; + adev->gmc.gart_size = 512ULL << 20; break; case CHIP_RAVEN: /* DCE SG support */ adev->gmc.gart_size = 1024ULL << 20; -- cgit v1.2.3 From 60b431b5c165514729ad0a47e18b0f99783dfc38 Mon Sep 17 00:00:00 2001 From: James Zhu Date: Tue, 27 Feb 2018 09:55:17 -0500 Subject: drm/amdgpu:Fixed wrong emit frame size for enc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Emit frame size should match with corresponding function, uvd_v6_0_enc_ring_emit_vm_flush has 5 amdgpu_ring_write Signed-off-by: James Zhu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index a3e64e22c93c..f26f515db2fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -1580,7 +1580,7 @@ static const struct amdgpu_ring_funcs uvd_v6_0_enc_ring_vm_funcs = { .set_wptr = uvd_v6_0_enc_ring_set_wptr, .emit_frame_size = 4 + /* uvd_v6_0_enc_ring_emit_pipeline_sync */ - 6 + /* uvd_v6_0_enc_ring_emit_vm_flush */ + 5 + /* uvd_v6_0_enc_ring_emit_vm_flush */ 5 + 5 + /* uvd_v6_0_enc_ring_emit_fence x2 vm fence */ 1, /* uvd_v6_0_enc_ring_insert_end */ .emit_ib_size = 5, /* uvd_v6_0_enc_ring_emit_ib */ -- cgit v1.2.3 From a0a73b950d0b2618690488ad067f96ab703e05c2 Mon Sep 17 00:00:00 2001 From: Eric Huang Date: Mon, 26 Feb 2018 17:36:19 -0500 Subject: drm/amd/powerplay: fix power over limit on Fiji power containment disabled only on Fiji and compute power profile. It violates PCIe spec and may cause power supply failed. Enabling it will fix the issue, even the fix will drop performance of some compute tests. Signed-off-by: Eric Huang Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 535d786b79ae..731475b06be7 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -4630,13 +4630,6 @@ static int smu7_set_power_profile_state(struct pp_hwmgr *hwmgr, int tmp_result, result = 0; uint32_t sclk_mask = 0, mclk_mask = 0; - if (hwmgr->chip_id == CHIP_FIJI) { - if (request->type == AMD_PP_GFX_PROFILE) - smu7_enable_power_containment(hwmgr); - else if (request->type == AMD_PP_COMPUTE_PROFILE) - smu7_disable_power_containment(hwmgr); - } - if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_AUTO) return -EINVAL; -- cgit v1.2.3 From 63b2b08b57d978833db36a047179404c40a52b09 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Sat, 24 Feb 2018 14:29:12 +0800 Subject: drm/amd/pp: Print more smu failed info on Vega10 Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c index 70dd5f8906db..99ad0a25300c 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c @@ -168,7 +168,7 @@ int vega10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, ret = vega10_wait_for_response(hwmgr); if (ret != 1) - pr_err("Failed to send message: 0x%x, ret value: 0x%x\n", msg, ret); + pr_err("Failed message: 0x%x, input parameter: 0x%x, error code: 0x%x\n", msg, parameter, ret); return 0; } -- cgit v1.2.3 From 14a8032aac5f6c5e903dcb22e177132c15c51c25 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Fri, 19 Jan 2018 20:29:17 +0800 Subject: drm/amdgpu: don't use MM idle_work for SRIOV(v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SRIOV doesn't give VF cg/pg feature so the MM's idle_work is skipped for SR-IOV v2: remove superfluous changes since idle_work is not scheduled for SR-IOV so the condition check for SR-IOV inside idle_work also can be dropped v3: drop the SRIOV check in amdgpu_vce/uvd_suspend Signed-off-by: Monk Liu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 9 ++++----- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 6 ++---- 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 9cd5517a4fa9..7ad814d0a487 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -1116,9 +1116,6 @@ static void amdgpu_uvd_idle_work_handler(struct work_struct *work) container_of(work, struct amdgpu_device, uvd.idle_work.work); unsigned fences = amdgpu_fence_count_emitted(&adev->uvd.ring); - if (amdgpu_sriov_vf(adev)) - return; - if (fences == 0) { if (adev->pm.dpm_enabled) { amdgpu_dpm_enable_uvd(adev, false); @@ -1138,11 +1135,12 @@ static void amdgpu_uvd_idle_work_handler(struct work_struct *work) void amdgpu_uvd_ring_begin_use(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - bool set_clocks = !cancel_delayed_work_sync(&adev->uvd.idle_work); + bool set_clocks; if (amdgpu_sriov_vf(adev)) return; + set_clocks = !cancel_delayed_work_sync(&adev->uvd.idle_work); if (set_clocks) { if (adev->pm.dpm_enabled) { amdgpu_dpm_enable_uvd(adev, true); @@ -1158,7 +1156,8 @@ void amdgpu_uvd_ring_begin_use(struct amdgpu_ring *ring) void amdgpu_uvd_ring_end_use(struct amdgpu_ring *ring) { - schedule_delayed_work(&ring->adev->uvd.idle_work, UVD_IDLE_TIMEOUT); + if (!amdgpu_sriov_vf(ring->adev)) + schedule_delayed_work(&ring->adev->uvd.idle_work, UVD_IDLE_TIMEOUT); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index d274ae535530..9152478d7528 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -300,9 +300,6 @@ static void amdgpu_vce_idle_work_handler(struct work_struct *work) container_of(work, struct amdgpu_device, vce.idle_work.work); unsigned i, count = 0; - if (amdgpu_sriov_vf(adev)) - return; - for (i = 0; i < adev->vce.num_rings; i++) count += amdgpu_fence_count_emitted(&adev->vce.ring[i]); @@ -362,7 +359,8 @@ void amdgpu_vce_ring_begin_use(struct amdgpu_ring *ring) */ void amdgpu_vce_ring_end_use(struct amdgpu_ring *ring) { - schedule_delayed_work(&ring->adev->vce.idle_work, VCE_IDLE_TIMEOUT); + if (!amdgpu_sriov_vf(ring->adev)) + schedule_delayed_work(&ring->adev->vce.idle_work, VCE_IDLE_TIMEOUT); } /** -- cgit v1.2.3 From dbf797655a43c6318ebb90b899e6583fcadc6472 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Tue, 23 Jan 2018 18:26:20 +0800 Subject: drm/amdgpu: adjust timeout for ib_ring_tests(v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit issue: sometime GFX/MM ib test hit timeout under SRIOV env, root cause is that engine doesn't come back soon enough so the current IB test considered as timed out. fix: for SRIOV GFX IB test wait time need to be expanded a lot during SRIOV runtimei mode since it couldn't really begin before GFX engine come back. for SRIOV MM IB test it always need more time since MM scheduling is not go together with GFX engine, it is controled by h/w MM scheduler so no matter runtime or exclusive mode MM IB test always need more time. v2: use ring type instead of idx to judge Signed-off-by: Monk Liu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index 7f2c314581d4..d7e39827f22a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -322,14 +322,45 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev) { unsigned i; int r, ret = 0; + long tmo_gfx, tmo_mm; + + tmo_mm = tmo_gfx = AMDGPU_IB_TEST_TIMEOUT; + if (amdgpu_sriov_vf(adev)) { + /* for MM engines in hypervisor side they are not scheduled together + * with CP and SDMA engines, so even in exclusive mode MM engine could + * still running on other VF thus the IB TEST TIMEOUT for MM engines + * under SR-IOV should be set to a long time. 8 sec should be enough + * for the MM comes back to this VF. + */ + tmo_mm = 8 * AMDGPU_IB_TEST_TIMEOUT; + } + + if (amdgpu_sriov_runtime(adev)) { + /* for CP & SDMA engines since they are scheduled together so + * need to make the timeout width enough to cover the time + * cost waiting for it coming back under RUNTIME only + */ + tmo_gfx = 8 * AMDGPU_IB_TEST_TIMEOUT; + } for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; + long tmo; if (!ring || !ring->ready) continue; - r = amdgpu_ring_test_ib(ring, AMDGPU_IB_TEST_TIMEOUT); + /* MM engine need more time */ + if (ring->funcs->type == AMDGPU_RING_TYPE_UVD || + ring->funcs->type == AMDGPU_RING_TYPE_VCE || + ring->funcs->type == AMDGPU_RING_TYPE_UVD_ENC || + ring->funcs->type == AMDGPU_RING_TYPE_VCN_DEC || + ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC) + tmo = tmo_mm; + else + tmo = tmo_gfx; + + r = amdgpu_ring_test_ib(ring, tmo); if (r) { ring->ready = false; -- cgit v1.2.3 From 6f31fe6ec6ee77a82dafc4f72efba6272f279b9f Mon Sep 17 00:00:00 2001 From: Emily Deng Date: Wed, 7 Feb 2018 16:17:16 +0800 Subject: drm/amdgpu: Correct sdma_v4 get_wptr(v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the original method will change the wptr value in wb. v2: furthur cleanup Signed-off-by: Emily Deng Signed-off-by: Monk Liu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index 3d5385dda34c..87c01d958703 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -238,31 +238,27 @@ static uint64_t sdma_v4_0_ring_get_rptr(struct amdgpu_ring *ring) static uint64_t sdma_v4_0_ring_get_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - u64 *wptr = NULL; - uint64_t local_wptr = 0; + u64 wptr; if (ring->use_doorbell) { /* XXX check if swapping is necessary on BE */ - wptr = ((u64 *)&adev->wb.wb[ring->wptr_offs]); - DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", *wptr); - *wptr = (*wptr) >> 2; - DRM_DEBUG("wptr/doorbell after shift == 0x%016llx\n", *wptr); + wptr = READ_ONCE(*((u64 *)&adev->wb.wb[ring->wptr_offs])); + DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", wptr); } else { u32 lowbit, highbit; int me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; - wptr = &local_wptr; lowbit = RREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR)) >> 2; highbit = RREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR_HI)) >> 2; DRM_DEBUG("wptr [%i]high== 0x%08x low==0x%08x\n", me, highbit, lowbit); - *wptr = highbit; - *wptr = (*wptr) << 32; - *wptr |= lowbit; + wptr = highbit; + wptr = wptr << 32; + wptr |= lowbit; } - return *wptr; + return wptr >> 2; } /** -- cgit v1.2.3 From bffe07b8b97d7faaf3d291129aafef2ee8a80e90 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Fri, 26 Jan 2018 16:57:25 +0800 Subject: drm/amdgpu: cleanup SA inti and fini(v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit should use bo_create_kernel instead of split to two function that create and pin the SA bo issue: before this patch, there are DMAR read error in host side when running SRIOV test, the DMAR address dropped in the range of SA bo. fix: after this cleanups of SA init and fini, above DMAR eror gone. v2: keep sa_bo's fini instead of suspend, to keep reporting error Signed-off-by: Monk Liu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 6 --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 2 - drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c | 62 ++++++------------------------ 3 files changed, 11 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index d7e39827f22a..311589e02d17 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -279,11 +279,6 @@ int amdgpu_ib_pool_init(struct amdgpu_device *adev) return r; } - r = amdgpu_sa_bo_manager_start(adev, &adev->ring_tmp_bo); - if (r) { - return r; - } - adev->ib_pool_ready = true; if (amdgpu_debugfs_sa_init(adev)) { dev_err(adev->dev, "failed to register debugfs file for SA\n"); @@ -302,7 +297,6 @@ int amdgpu_ib_pool_init(struct amdgpu_device *adev) void amdgpu_ib_pool_fini(struct amdgpu_device *adev) { if (adev->ib_pool_ready) { - amdgpu_sa_bo_manager_suspend(adev, &adev->ring_tmp_bo); amdgpu_sa_bo_manager_fini(adev, &adev->ring_tmp_bo); adev->ib_pool_ready = false; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index c2b02f5c88d2..1cef944ef98d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -281,8 +281,6 @@ void amdgpu_sa_bo_manager_fini(struct amdgpu_device *adev, struct amdgpu_sa_manager *sa_manager); int amdgpu_sa_bo_manager_start(struct amdgpu_device *adev, struct amdgpu_sa_manager *sa_manager); -int amdgpu_sa_bo_manager_suspend(struct amdgpu_device *adev, - struct amdgpu_sa_manager *sa_manager); int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager, struct amdgpu_sa_bo **sa_bo, unsigned size, unsigned align); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index 5ca75a456ad2..fb1667b35daa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -63,21 +63,27 @@ int amdgpu_sa_bo_manager_init(struct amdgpu_device *adev, for (i = 0; i < AMDGPU_SA_NUM_FENCE_LISTS; ++i) INIT_LIST_HEAD(&sa_manager->flist[i]); - r = amdgpu_bo_create(adev, size, align, true, domain, - 0, NULL, NULL, &sa_manager->bo); + r = amdgpu_bo_create_kernel(adev, size, align, domain, &sa_manager->bo, + &sa_manager->gpu_addr, &sa_manager->cpu_ptr); if (r) { dev_err(adev->dev, "(%d) failed to allocate bo for manager\n", r); return r; } + memset(sa_manager->cpu_ptr, 0, sa_manager->size); return r; } void amdgpu_sa_bo_manager_fini(struct amdgpu_device *adev, - struct amdgpu_sa_manager *sa_manager) + struct amdgpu_sa_manager *sa_manager) { struct amdgpu_sa_bo *sa_bo, *tmp; + if (sa_manager->bo == NULL) { + dev_err(adev->dev, "no bo for sa manager\n"); + return; + } + if (!list_empty(&sa_manager->olist)) { sa_manager->hole = &sa_manager->olist, amdgpu_sa_bo_try_free(sa_manager); @@ -88,55 +94,9 @@ void amdgpu_sa_bo_manager_fini(struct amdgpu_device *adev, list_for_each_entry_safe(sa_bo, tmp, &sa_manager->olist, olist) { amdgpu_sa_bo_remove_locked(sa_bo); } - amdgpu_bo_unref(&sa_manager->bo); - sa_manager->size = 0; -} - -int amdgpu_sa_bo_manager_start(struct amdgpu_device *adev, - struct amdgpu_sa_manager *sa_manager) -{ - int r; - - if (sa_manager->bo == NULL) { - dev_err(adev->dev, "no bo for sa manager\n"); - return -EINVAL; - } - /* map the buffer */ - r = amdgpu_bo_reserve(sa_manager->bo, false); - if (r) { - dev_err(adev->dev, "(%d) failed to reserve manager bo\n", r); - return r; - } - r = amdgpu_bo_pin(sa_manager->bo, sa_manager->domain, &sa_manager->gpu_addr); - if (r) { - amdgpu_bo_unreserve(sa_manager->bo); - dev_err(adev->dev, "(%d) failed to pin manager bo\n", r); - return r; - } - r = amdgpu_bo_kmap(sa_manager->bo, &sa_manager->cpu_ptr); - memset(sa_manager->cpu_ptr, 0, sa_manager->size); - amdgpu_bo_unreserve(sa_manager->bo); - return r; -} - -int amdgpu_sa_bo_manager_suspend(struct amdgpu_device *adev, - struct amdgpu_sa_manager *sa_manager) -{ - int r; - - if (sa_manager->bo == NULL) { - dev_err(adev->dev, "no bo for sa manager\n"); - return -EINVAL; - } - - r = amdgpu_bo_reserve(sa_manager->bo, true); - if (!r) { - amdgpu_bo_kunmap(sa_manager->bo); - amdgpu_bo_unpin(sa_manager->bo); - amdgpu_bo_unreserve(sa_manager->bo); - } - return r; + amdgpu_bo_free_kernel(&sa_manager->bo, &sa_manager->gpu_addr, &sa_manager->cpu_ptr); + sa_manager->size = 0; } static void amdgpu_sa_bo_remove_locked(struct amdgpu_sa_bo *sa_bo) -- cgit v1.2.3 From 9f0178fb67699992d38601cb923b434f9986dd68 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Mon, 29 Jan 2018 19:24:32 +0800 Subject: drm/amdgpu: disable GFX ring and disable PQ wptr in hw_fini otherwise there will be DMAR reading error comes out from CP since GFX is still alive and CPC's WPTR_POLL is still enabled, which would lead to DMAR read error. fix: we can hault CPG after hw_fini, but cannot halt CPC becaues KIQ stil need to be alive to let RLCV invoke, but its WPTR_POLL could be disabled. Signed-off-by: Monk Liu Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index e9cc03e78bb0..d73bbb092202 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -2961,7 +2961,13 @@ static int gfx_v9_0_hw_fini(void *handle) gfx_v9_0_kcq_disable(&adev->gfx.kiq.ring, &adev->gfx.compute_ring[i]); if (amdgpu_sriov_vf(adev)) { - pr_debug("For SRIOV client, shouldn't do anything.\n"); + gfx_v9_0_cp_gfx_enable(adev, false); + /* must disable polling for SRIOV when hw finished, otherwise + * CPC engine may still keep fetching WB address which is already + * invalid after sw finished and trigger DMAR reading error in + * hypervisor side. + */ + WREG32_FIELD15(GC, 0, CP_PQ_WPTR_POLL_CNTL, EN, 0); return 0; } gfx_v9_0_cp_enable(adev, false); -- cgit v1.2.3 From 910f8befdf5bccf25287d9f1743e3e546bcb7ce0 Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Wed, 28 Feb 2018 09:19:03 +0000 Subject: xen/pirq: fix error path cleanup when binding MSIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current cleanup in the error path of xen_bind_pirq_msi_to_irq is wrong. First of all there's an off-by-one in the cleanup loop, which can lead to unbinding wrong IRQs. Secondly IRQs not bound won't be freed, thus leaking IRQ numbers. Note that there's no need to differentiate between bound and unbound IRQs when freeing them, __unbind_from_irq will deal with both of them correctly. Fixes: 4892c9b4ada9f9 ("xen: add support for MSI message groups") Reported-by: Hooman Mirhadi Signed-off-by: Roger Pau Monné Reviewed-by: Amit Shah Reviewed-by: Boris Ostrovsky Signed-off-by: Juergen Gross --- drivers/xen/events/events_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 1ab4bd11f5f3..762378f1811c 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -755,8 +755,8 @@ out: mutex_unlock(&irq_mapping_update_lock); return irq; error_irq: - for (; i >= 0; i--) - __unbind_from_irq(irq + i); + while (nvec--) + __unbind_from_irq(irq + nvec); mutex_unlock(&irq_mapping_update_lock); return ret; } -- cgit v1.2.3 From c2d2e6738a209f0f9dffa2dc8e7292fc45360d61 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Wed, 28 Feb 2018 07:23:23 -0500 Subject: xen-netfront: Fix hang on device removal A toolstack may delete the vif frontend and backend xenstore entries while xen-netfront is in the removal code path. In that case, the checks for xenbus_read_driver_state would return XenbusStateUnknown, and xennet_remove would hang indefinitely. This hang prevents system shutdown. xennet_remove must be able to handle XenbusStateUnknown, and netback_changed must also wake up the wake_queue for that state as well. Fixes: 5b5971df3bc2 ("xen-netfront: remove warning when unloading module") Signed-off-by: Jason Andryuk Cc: Eduardo Otubo Reviewed-by: Boris Ostrovsky Signed-off-by: Juergen Gross --- drivers/net/xen-netfront.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 8328d395e332..3127bc8633ca 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -2005,7 +2005,10 @@ static void netback_changed(struct xenbus_device *dev, case XenbusStateInitialised: case XenbusStateReconfiguring: case XenbusStateReconfigured: + break; + case XenbusStateUnknown: + wake_up_all(&module_unload_q); break; case XenbusStateInitWait: @@ -2136,7 +2139,9 @@ static int xennet_remove(struct xenbus_device *dev) xenbus_switch_state(dev, XenbusStateClosing); wait_event(module_unload_q, xenbus_read_driver_state(dev->otherend) == - XenbusStateClosing); + XenbusStateClosing || + xenbus_read_driver_state(dev->otherend) == + XenbusStateUnknown); xenbus_switch_state(dev, XenbusStateClosed); wait_event(module_unload_q, -- cgit v1.2.3 From 7628166d5e2883e4cdd142b99863d29d411a81b2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 28 Feb 2018 14:40:48 +0100 Subject: tinydrm: add backlight dependency Calling devm_of_find_backlight directly means we get a link failure without CONFIG_BACKLIGHT_CLASS_DEVICE: drivers/gpu/drm/tinydrm/mi0283qt.o: In function `mi0283qt_probe': mi0283qt.c:(.text+0x684): undefined reference to `devm_of_find_backlight' This adds an explicit Kconfig dependency for it. While I did not observe that failure for st7735r, I assume the same change is needed there for the same reason. Fixes: d1a2e7004b5e ("drm/tinydrm: Replace tinydrm_of_find_backlight with of_find_backlight") Signed-off-by: Arnd Bergmann Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20180228134111.2042877-1-arnd@arndb.de --- drivers/gpu/drm/tinydrm/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig index 13339be843bc..4592a5e3f20b 100644 --- a/drivers/gpu/drm/tinydrm/Kconfig +++ b/drivers/gpu/drm/tinydrm/Kconfig @@ -23,6 +23,7 @@ config TINYDRM_ILI9225 config TINYDRM_MI0283QT tristate "DRM support for MI0283QT" depends on DRM_TINYDRM && SPI + depends on BACKLIGHT_CLASS_DEVICE select TINYDRM_MIPI_DBI help DRM driver for the Multi-Inno MI0283QT display panel @@ -54,6 +55,7 @@ config TINYDRM_ST7586 config TINYDRM_ST7735R tristate "DRM support for Sitronix ST7735R display panels" depends on DRM_TINYDRM && SPI + depends on BACKLIGHT_CLASS_DEVICE select TINYDRM_MIPI_DBI help DRM driver Sitronix ST7735R with one of the following LCDs: -- cgit v1.2.3 From d6b6669762898dfc99e9273b8d8603bc47014aa9 Mon Sep 17 00:00:00 2001 From: Shirish S Date: Wed, 21 Feb 2018 16:10:33 +0530 Subject: drm/amd/display: check for ipp before calling cursor operations Currently all cursor related functions are made to all pipes that are attached to a particular stream. This is not applicable to pipes that do not have cursor plane initialised like underlay. Hence this patch allows cursor related operations on a pipe only if ipp in available on that particular pipe. The check is added to set_cursor_position & set_cursor_attribute. Signed-off-by: Shirish S Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/display/dc/core/dc_stream.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 261811e0c094..539c3e0a6292 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -197,7 +197,8 @@ bool dc_stream_set_cursor_attributes( for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; - if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp)) + if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && + !pipe_ctx->plane_res.dpp) || !pipe_ctx->plane_res.ipp) continue; if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) continue; @@ -273,7 +274,8 @@ bool dc_stream_set_cursor_position( if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.mi && !pipe_ctx->plane_res.hubp) || !pipe_ctx->plane_state || - (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp)) + (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp) || + !pipe_ctx->plane_res.ipp) continue; if (pipe_ctx->plane_state->address.type -- cgit v1.2.3 From 9f51943c2a434d40f46776369b7a72e0ffb6ea59 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Fri, 19 Jan 2018 19:02:16 +0800 Subject: drm/amdgpu: only flush hotplug work without DC since hotplug_work is initialized under the case of no dc support Signed-off-by: Monk Liu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c index 56bcd59c3399..36483e0d3c97 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c @@ -257,7 +257,8 @@ int amdgpu_irq_init(struct amdgpu_device *adev) r = drm_irq_install(adev->ddev, adev->ddev->pdev->irq); if (r) { adev->irq.installed = false; - flush_work(&adev->hotplug_work); + if (!amdgpu_device_has_dc_support(adev)) + flush_work(&adev->hotplug_work); cancel_work_sync(&adev->reset_work); return r; } @@ -282,7 +283,8 @@ void amdgpu_irq_fini(struct amdgpu_device *adev) adev->irq.installed = false; if (adev->irq.msi_enabled) pci_disable_msi(adev->pdev); - flush_work(&adev->hotplug_work); + if (!amdgpu_device_has_dc_support(adev)) + flush_work(&adev->hotplug_work); cancel_work_sync(&adev->reset_work); } -- cgit v1.2.3 From a4ef6edc8e87bee656a5feaedb0bb167acd9d360 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Wed, 24 Jan 2018 12:20:32 +0800 Subject: drm/amdgpu: move WB_FREE to correct place WB_FREE should be put after all engines's hw_fini done, otherwise the invalid wptr/rptr_addr would still be used by engines which trigger abnormal bugs. This fixes couple DMAR reading error in host side for SRIOV after guest kmd is unloaded. Signed-off-by: Monk Liu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 829dc2edace6..d9f3d54e228f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1455,11 +1455,6 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.hw) continue; - if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) { - amdgpu_free_static_csa(adev); - amdgpu_device_wb_fini(adev); - amdgpu_device_vram_scratch_fini(adev); - } if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE) { @@ -1486,6 +1481,13 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.sw) continue; + + if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) { + amdgpu_free_static_csa(adev); + amdgpu_device_wb_fini(adev); + amdgpu_device_vram_scratch_fini(adev); + } + r = adev->ip_blocks[i].version->funcs->sw_fini((void *)adev); /* XXX handle errors */ if (r) { -- cgit v1.2.3 From 8014e2d3fd640c892ed334e7de7af918e141c8ff Mon Sep 17 00:00:00 2001 From: James Zhu Date: Tue, 27 Feb 2018 09:55:17 -0500 Subject: drm/amdgpu:Fixed wrong emit frame size for enc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Emit frame size should match with corresponding function, uvd_v6_0_enc_ring_emit_vm_flush has 5 amdgpu_ring_write Signed-off-by: James Zhu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index b2bfedaf57f1..9bab4842cd44 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -1618,7 +1618,7 @@ static const struct amdgpu_ring_funcs uvd_v6_0_enc_ring_vm_funcs = { .set_wptr = uvd_v6_0_enc_ring_set_wptr, .emit_frame_size = 4 + /* uvd_v6_0_enc_ring_emit_pipeline_sync */ - 6 + /* uvd_v6_0_enc_ring_emit_vm_flush */ + 5 + /* uvd_v6_0_enc_ring_emit_vm_flush */ 5 + 5 + /* uvd_v6_0_enc_ring_emit_fence x2 vm fence */ 1, /* uvd_v6_0_enc_ring_insert_end */ .emit_ib_size = 5, /* uvd_v6_0_enc_ring_emit_ib */ -- cgit v1.2.3 From a0aaa03062be252aacad60a776f3374dd53e3f98 Mon Sep 17 00:00:00 2001 From: Eric Huang Date: Mon, 26 Feb 2018 17:36:19 -0500 Subject: drm/amd/powerplay: fix power over limit on Fiji power containment disabled only on Fiji and compute power profile. It violates PCIe spec and may cause power supply failed. Enabling it will fix the issue, even the fix will drop performance of some compute tests. Signed-off-by: Eric Huang Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 45be31327340..08e8a793714f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -4537,13 +4537,6 @@ static int smu7_set_power_profile_state(struct pp_hwmgr *hwmgr, int tmp_result, result = 0; uint32_t sclk_mask = 0, mclk_mask = 0; - if (hwmgr->chip_id == CHIP_FIJI) { - if (request->type == AMD_PP_GFX_PROFILE) - smu7_enable_power_containment(hwmgr); - else if (request->type == AMD_PP_COMPUTE_PROFILE) - smu7_disable_power_containment(hwmgr); - } - if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_AUTO) return -EINVAL; -- cgit v1.2.3 From 8d333fe0ad9dcb9651b9b450424a960bac040f96 Mon Sep 17 00:00:00 2001 From: Emily Deng Date: Wed, 7 Feb 2018 16:17:16 +0800 Subject: drm/amdgpu: Correct sdma_v4 get_wptr(v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the original method will change the wptr value in wb. v2: furthur cleanup Signed-off-by: Emily Deng Signed-off-by: Monk Liu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index e92fb372bc99..91cf95a8c39c 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -238,31 +238,27 @@ static uint64_t sdma_v4_0_ring_get_rptr(struct amdgpu_ring *ring) static uint64_t sdma_v4_0_ring_get_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - u64 *wptr = NULL; - uint64_t local_wptr = 0; + u64 wptr; if (ring->use_doorbell) { /* XXX check if swapping is necessary on BE */ - wptr = ((u64 *)&adev->wb.wb[ring->wptr_offs]); - DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", *wptr); - *wptr = (*wptr) >> 2; - DRM_DEBUG("wptr/doorbell after shift == 0x%016llx\n", *wptr); + wptr = READ_ONCE(*((u64 *)&adev->wb.wb[ring->wptr_offs])); + DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", wptr); } else { u32 lowbit, highbit; int me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; - wptr = &local_wptr; lowbit = RREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR)) >> 2; highbit = RREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR_HI)) >> 2; DRM_DEBUG("wptr [%i]high== 0x%08x low==0x%08x\n", me, highbit, lowbit); - *wptr = highbit; - *wptr = (*wptr) << 32; - *wptr |= lowbit; + wptr = highbit; + wptr = wptr << 32; + wptr |= lowbit; } - return *wptr; + return wptr >> 2; } /** -- cgit v1.2.3 From f812dec57d55719f5fe1f6fce193561015369363 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Fri, 29 Dec 2017 17:06:41 +0800 Subject: drm/amdgpu: fix&cleanups for wb_clear fix: should do right shift on wb before clearing cleanups: 1,should memset all wb buffer 2,set max wb number to 128 (total 4KB) is big enough Signed-off-by: Monk Liu Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index d5a2eefd6c3e..74edba18b159 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1156,7 +1156,7 @@ static inline void amdgpu_set_ib_value(struct amdgpu_cs_parser *p, /* * Writeback */ -#define AMDGPU_MAX_WB 512 /* Reserve at most 512 WB slots for amdgpu-owned rings. */ +#define AMDGPU_MAX_WB 128 /* Reserve at most 128 WB slots for amdgpu-owned rings. */ struct amdgpu_wb { struct amdgpu_bo *wb_obj; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index d9f3d54e228f..af1b879a9ee9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -492,7 +492,7 @@ static int amdgpu_device_wb_init(struct amdgpu_device *adev) memset(&adev->wb.used, 0, sizeof(adev->wb.used)); /* clear wb memory */ - memset((char *)adev->wb.wb, 0, AMDGPU_MAX_WB * sizeof(uint32_t)); + memset((char *)adev->wb.wb, 0, AMDGPU_MAX_WB * sizeof(uint32_t) * 8); } return 0; @@ -530,8 +530,9 @@ int amdgpu_device_wb_get(struct amdgpu_device *adev, u32 *wb) */ void amdgpu_device_wb_free(struct amdgpu_device *adev, u32 wb) { + wb >>= 3; if (wb < adev->wb.num_wb) - __clear_bit(wb >> 3, adev->wb.used); + __clear_bit(wb, adev->wb.used); } /** -- cgit v1.2.3 From 82d0ece957bcd0e6d500759b205508dbda1bc265 Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Mon, 26 Feb 2018 09:09:26 -0500 Subject: drm/amd/amdgpu: Correct VRAM width for APUs with GMC9 DDR4 has a 64-bit width not 128-bits. It was reporting twice the width. Tested with my Ryzen 2400G. Signed-off-by: Tom St Denis Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 2719937e09d6..fd6370982c9a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -682,7 +682,10 @@ static int gmc_v9_0_mc_init(struct amdgpu_device *adev) adev->mc.vram_width = amdgpu_atomfirmware_get_vram_width(adev); if (!adev->mc.vram_width) { /* hbm memory channel size */ - chansize = 128; + if (adev->flags & AMD_IS_APU) + chansize = 64; + else + chansize = 128; tmp = RREG32_SOC15(DF, 0, mmDF_CS_AON0_DramBaseAddress0); tmp &= DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK; -- cgit v1.2.3 From fd430a702d37747d79bb5520590ce198df02aaa5 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Thu, 18 Jan 2018 16:58:04 +0800 Subject: drm/amdgpu: skip ECC for SRIOV in gmc late_init Signed-off-by: Monk Liu Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index fd6370982c9a..3b7e7af09ead 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -634,7 +634,7 @@ static int gmc_v9_0_late_init(void *handle) for(i = 0; i < AMDGPU_MAX_VMHUBS; ++i) BUG_ON(vm_inv_eng[i] > 16); - if (adev->asic_type == CHIP_VEGA10) { + if (adev->asic_type == CHIP_VEGA10 && !amdgpu_sriov_vf(adev)) { r = gmc_v9_0_ecc_available(adev); if (r == 1) { DRM_INFO("ECC is active.\n"); -- cgit v1.2.3 From cc195141133ac3e767d930bedd8294ceebf1f10b Mon Sep 17 00:00:00 2001 From: Shirish S Date: Fri, 23 Feb 2018 16:10:13 +0530 Subject: drm/amd/display: make dm_dp_aux_transfer return payload bytes instead of size The drm layer expects aux->transfer() to return the payload bytes read. Currently dm_dp_aux_transfer() returns the payload size which does not gets updated during the read, hence not giving the right data for the drm layer to pars edid. This leads to the drm layer to conclude as the edid is BAD and hence some monitors/devices dont get detected properly. This patch changes the return type of dm_dp_aux_transfer() to actual bytes read during DP_AUX_NATIVE_READ & DP_AUX_I2C_READ. Signed-off-by: Shirish S Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 9 +++++---- drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c | 7 ++++--- drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c | 15 ++------------- drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c | 1 + drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h | 2 +- 5 files changed, 13 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 1e8a21b67df7..39cfe0fbf1b9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -83,17 +83,18 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, enum i2c_mot_mode mot = (msg->request & DP_AUX_I2C_MOT) ? I2C_MOT_TRUE : I2C_MOT_FALSE; enum ddc_result res; + ssize_t read_bytes; switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_NATIVE_READ: - res = dal_ddc_service_read_dpcd_data( + read_bytes = dal_ddc_service_read_dpcd_data( TO_DM_AUX(aux)->ddc_service, false, I2C_MOT_UNDEF, msg->address, msg->buffer, msg->size); - break; + return read_bytes; case DP_AUX_NATIVE_WRITE: res = dal_ddc_service_write_dpcd_data( TO_DM_AUX(aux)->ddc_service, @@ -104,14 +105,14 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, msg->size); break; case DP_AUX_I2C_READ: - res = dal_ddc_service_read_dpcd_data( + read_bytes = dal_ddc_service_read_dpcd_data( TO_DM_AUX(aux)->ddc_service, true, mot, msg->address, msg->buffer, msg->size); - break; + return read_bytes; case DP_AUX_I2C_WRITE: res = dal_ddc_service_write_dpcd_data( TO_DM_AUX(aux)->ddc_service, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index d5294798b0a5..49c2face1e7a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -629,7 +629,7 @@ bool dal_ddc_service_query_ddc_data( return ret; } -enum ddc_result dal_ddc_service_read_dpcd_data( +ssize_t dal_ddc_service_read_dpcd_data( struct ddc_service *ddc, bool i2c, enum i2c_mot_mode mot, @@ -660,8 +660,9 @@ enum ddc_result dal_ddc_service_read_dpcd_data( if (dal_i2caux_submit_aux_command( ddc->ctx->i2caux, ddc->ddc_pin, - &command)) - return DDC_RESULT_SUCESSFULL; + &command)) { + return (ssize_t)command.payloads->length; + } return DDC_RESULT_FAILED_OPERATION; } diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c index 0b1db48fef36..9c42fe5a0f27 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c @@ -126,20 +126,8 @@ static void process_read_reply( ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; ctx->operation_succeeded = false; - } else if (ctx->returned_byte < ctx->current_read_length) { - ctx->current_read_length -= ctx->returned_byte; - - ctx->offset += ctx->returned_byte; - - ++ctx->invalid_reply_retry_aux_on_ack; - - if (ctx->invalid_reply_retry_aux_on_ack > - AUX_INVALID_REPLY_RETRY_COUNTER) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; - ctx->operation_succeeded = false; - } } else { + ctx->current_read_length = ctx->returned_byte; ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED; ctx->transaction_complete = true; ctx->operation_succeeded = true; @@ -292,6 +280,7 @@ static bool read_command( ctx.operation_succeeded); } + request->payload.length = ctx.reply.length; return ctx.operation_succeeded; } diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c index e1593ffe5a2b..5cbf6626b8d4 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c @@ -253,6 +253,7 @@ bool dal_i2caux_submit_aux_command( break; } + cmd->payloads->length = request.payload.length; ++index_of_payload; } diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h index 0bf73b742f1f..090b7a8dd67b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h @@ -102,7 +102,7 @@ bool dal_ddc_service_query_ddc_data( uint8_t *read_buf, uint32_t read_size); -enum ddc_result dal_ddc_service_read_dpcd_data( +ssize_t dal_ddc_service_read_dpcd_data( struct ddc_service *ddc, bool i2c, enum i2c_mot_mode mot, -- cgit v1.2.3 From 5d447f09b8d8346c64f4c952a67c61f7ce88d3c1 Mon Sep 17 00:00:00 2001 From: Shirish S Date: Wed, 21 Feb 2018 16:10:33 +0530 Subject: drm/amd/display: check for ipp before calling cursor operations Currently all cursor related functions are made to all pipes that are attached to a particular stream. This is not applicable to pipes that do not have cursor plane initialised like underlay. Hence this patch allows cursor related operations on a pipe only if ipp in available on that particular pipe. The check is added to set_cursor_position & set_cursor_attribute. Signed-off-by: Shirish S Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/display/dc/core/dc_stream.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 87a193ac2883..cd5819789d76 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -198,7 +198,8 @@ bool dc_stream_set_cursor_attributes( for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; - if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp)) + if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && + !pipe_ctx->plane_res.dpp) || !pipe_ctx->plane_res.ipp) continue; if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) continue; @@ -237,7 +238,8 @@ bool dc_stream_set_cursor_position( if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.mi && !pipe_ctx->plane_res.hubp) || !pipe_ctx->plane_state || - (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp)) + (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp) || + !pipe_ctx->plane_res.ipp) continue; core_dc->hwss.set_cursor_position(pipe_ctx); -- cgit v1.2.3 From f8f4b9a679e52298b14358db22c37a135e7086ec Mon Sep 17 00:00:00 2001 From: Amber Lin Date: Tue, 27 Feb 2018 10:01:59 -0500 Subject: drm/amdgpu: Map all visible VRAM at startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using CPU to update page table, we need to kmap all the PDs/PTs after they are allocated and that requires a TLB shot down on each CPU, which is quite heavy. Instead, we map the whole visible VRAM to a kernel address at once. Pages can be obtained from the offset. v2: move the mapping base from gmc to amdgpu_mman structure, and the implementation in amdgpu_ttm_* functions Signed-off-by: Amber Lin Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 17 +++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 1 + 2 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index e38e6db8f760..f126a5ae41b3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -621,6 +621,7 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_ { struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; struct amdgpu_device *adev = amdgpu_ttm_adev(bdev); + struct drm_mm_node *mm_node = mem->mm_node; mem->bus.addr = NULL; mem->bus.offset = 0; @@ -640,6 +641,15 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_ /* check if it's visible */ if ((mem->bus.offset + mem->bus.size) > adev->gmc.visible_vram_size) return -EINVAL; + /* Only physically contiguous buffers apply. In a contiguous + * buffer, size of the first mm_node would match the number of + * pages in ttm_mem_reg. + */ + if (adev->mman.aper_base_kaddr && + (mm_node->size == mem->num_pages)) + mem->bus.addr = (u8 *)adev->mman.aper_base_kaddr + + mem->bus.offset; + mem->bus.base = adev->gmc.aper_base; mem->bus.is_iomem = true; break; @@ -1402,6 +1412,10 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) /* Change the size here instead of the init above so only lpfn is affected */ amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); +#ifdef CONFIG_64BIT + adev->mman.aper_base_kaddr = ioremap_wc(adev->gmc.aper_base, + adev->gmc.visible_vram_size); +#endif /* *The reserved vram for firmware must be pinned to the specified @@ -1494,6 +1508,9 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) amdgpu_ttm_debugfs_fini(adev); amdgpu_bo_free_kernel(&adev->stolen_vga_memory, NULL, NULL); amdgpu_ttm_fw_reserve_vram_fini(adev); + if (adev->mman.aper_base_kaddr) + iounmap(adev->mman.aper_base_kaddr); + adev->mman.aper_base_kaddr = NULL; ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_VRAM); ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_TT); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 1e275c7b006b..d31491069f2f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -44,6 +44,7 @@ struct amdgpu_mman { struct ttm_bo_device bdev; bool mem_global_referenced; bool initialized; + void __iomem *aper_base_kaddr; #if defined(CONFIG_DEBUG_FS) struct dentry *debugfs_entries[8]; -- cgit v1.2.3 From d869ae092e39022c2bba81ea498abe74249a338c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 27 Feb 2018 11:44:31 -0500 Subject: drm/amdgpu: fix module parameter descriptions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some were missing the close parens around options. Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 85ceed702fb2..e6709362994a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -284,10 +284,10 @@ module_param_named(lbpw, amdgpu_lbpw, int, 0444); MODULE_PARM_DESC(compute_multipipe, "Force compute queues to be spread across pipes (1 = enable, 0 = disable, -1 = auto)"); module_param_named(compute_multipipe, amdgpu_compute_multipipe, int, 0444); -MODULE_PARM_DESC(gpu_recovery, "Enable GPU recovery mechanism, (1 = enable, 0 = disable, -1 = auto"); +MODULE_PARM_DESC(gpu_recovery, "Enable GPU recovery mechanism, (1 = enable, 0 = disable, -1 = auto)"); module_param_named(gpu_recovery, amdgpu_gpu_recovery, int, 0444); -MODULE_PARM_DESC(emu_mode, "Emulation mode, (1 = enable, 0 = disable"); +MODULE_PARM_DESC(emu_mode, "Emulation mode, (1 = enable, 0 = disable)"); module_param_named(emu_mode, amdgpu_emu_mode, int, 0444); #ifdef CONFIG_DRM_AMDGPU_SI -- cgit v1.2.3 From d811bcee1f7a379cad893fdee4c8db5775963b7f Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Wed, 28 Feb 2018 18:05:34 -0800 Subject: pvcalls-front: 64-bit align flags We are using test_and_* operations on the status and flag fields of struct sock_mapping. However, these functions require the operand to be 64-bit aligned on arm64. Currently, only status is 64-bit aligned. Make status and flags explicitly 64-bit aligned. Signed-off-by: Stefano Stabellini Reviewed-by: Boris Ostrovsky Signed-off-by: Juergen Gross --- drivers/xen/pvcalls-front.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index aedbee3b2838..2f11ca72a281 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -73,20 +73,25 @@ struct sock_mapping { wait_queue_head_t inflight_conn_req; } active; struct { - /* Socket status */ + /* + * Socket status, needs to be 64-bit aligned due to the + * test_and_* functions which have this requirement on arm64. + */ #define PVCALLS_STATUS_UNINITALIZED 0 #define PVCALLS_STATUS_BIND 1 #define PVCALLS_STATUS_LISTEN 2 - uint8_t status; + uint8_t status __attribute__((aligned(8))); /* * Internal state-machine flags. * Only one accept operation can be inflight for a socket. * Only one poll operation can be inflight for a given socket. + * flags needs to be 64-bit aligned due to the test_and_* + * functions which have this requirement on arm64. */ #define PVCALLS_FLAG_ACCEPT_INFLIGHT 0 #define PVCALLS_FLAG_POLL_INFLIGHT 1 #define PVCALLS_FLAG_POLL_RET 2 - uint8_t flags; + uint8_t flags __attribute__((aligned(8))); uint32_t inflight_req_id; struct sock_mapping *accept_map; wait_queue_head_t inflight_accept_req; -- cgit v1.2.3 From dfe9cfccb264889b025e443ca20e2fbb401295c2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:33 +0200 Subject: drm: omapdrm: Use kernel integer types The standard kernel integer types are [us]{8,16,32}. Use them instead of the u?int{8,16,32}_t types. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_crtc.c | 12 ++++----- drivers/gpu/drm/omapdrm/omap_crtc.h | 2 +- drivers/gpu/drm/omapdrm/omap_dmm_priv.h | 10 +++---- drivers/gpu/drm/omapdrm/omap_dmm_tiler.c | 46 ++++++++++++++++---------------- drivers/gpu/drm/omapdrm/omap_dmm_tiler.h | 22 +++++++-------- drivers/gpu/drm/omapdrm/omap_drv.h | 4 +-- drivers/gpu/drm/omapdrm/omap_fb.c | 18 ++++++------- drivers/gpu/drm/omapdrm/omap_gem.c | 41 +++++++++++++++------------- drivers/gpu/drm/omapdrm/omap_gem.h | 16 +++++------ drivers/gpu/drm/omapdrm/omap_irq.c | 6 ++--- drivers/gpu/drm/omapdrm/omap_irq.h | 2 +- drivers/gpu/drm/omapdrm/omap_plane.c | 4 +-- drivers/gpu/drm/omapdrm/tcm-sita.c | 12 ++++----- drivers/gpu/drm/omapdrm/tcm.h | 4 +-- 14 files changed, 101 insertions(+), 98 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 1b8154e58d18..95615a86e9f7 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -272,7 +272,7 @@ static const struct dss_mgr_ops mgr_ops = { * Setup, Flush and Page Flip */ -void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus) +void omap_crtc_error_irq(struct drm_crtc *crtc, u32 irqstatus) { struct omap_crtc *omap_crtc = to_omap_crtc(crtc); @@ -492,7 +492,7 @@ static int omap_crtc_atomic_check(struct drm_crtc *crtc, struct drm_plane_state *pri_state; if (state->color_mgmt_changed && state->gamma_lut) { - uint length = state->gamma_lut->length / + unsigned int length = state->gamma_lut->length / sizeof(struct drm_color_lut); if (length < 2) @@ -526,7 +526,7 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, if (crtc->state->color_mgmt_changed) { struct drm_color_lut *lut = NULL; - uint length = 0; + unsigned int length = 0; if (crtc->state->gamma_lut) { lut = (struct drm_color_lut *) @@ -557,7 +557,7 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, static int omap_crtc_atomic_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, - uint64_t val) + u64 val) { struct omap_drm_private *priv = crtc->dev->dev_private; struct drm_plane_state *plane_state; @@ -585,7 +585,7 @@ static int omap_crtc_atomic_set_property(struct drm_crtc *crtc, static int omap_crtc_atomic_get_property(struct drm_crtc *crtc, const struct drm_crtc_state *state, struct drm_property *property, - uint64_t *val) + u64 *val) { struct omap_drm_private *priv = crtc->dev->dev_private; struct omap_crtc_state *omap_state = to_omap_crtc_state(state); @@ -732,7 +732,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, * gamma table is not supprted. */ if (priv->dispc_ops->mgr_gamma_size(channel)) { - uint gamma_lut_size = 256; + unsigned int gamma_lut_size = 256; drm_crtc_enable_color_mgmt(crtc, 0, false, gamma_lut_size); drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size); diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.h b/drivers/gpu/drm/omapdrm/omap_crtc.h index ad7b007c6174..7f01e730a050 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.h +++ b/drivers/gpu/drm/omapdrm/omap_crtc.h @@ -37,7 +37,7 @@ void omap_crtc_pre_uninit(void); struct drm_crtc *omap_crtc_init(struct drm_device *dev, struct drm_plane *plane, struct omap_dss_device *dssdev); int omap_crtc_wait_pending(struct drm_crtc *crtc); -void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus); +void omap_crtc_error_irq(struct drm_crtc *crtc, u32 irqstatus); void omap_crtc_vblank_irq(struct drm_crtc *crtc); #endif /* __OMAPDRM_CRTC_H__ */ diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_priv.h b/drivers/gpu/drm/omapdrm/omap_dmm_priv.h index 600064d5c25b..c2785cc98dc9 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_priv.h +++ b/drivers/gpu/drm/omapdrm/omap_dmm_priv.h @@ -102,10 +102,10 @@ struct pat_ctrl { }; struct pat { - uint32_t next_pa; + u32 next_pa; struct pat_area area; struct pat_ctrl ctrl; - uint32_t data_pa; + u32 data_pa; }; #define DMM_FIXED_RETRY_COUNT 1000 @@ -129,7 +129,7 @@ struct dmm_txn { void *engine_handle; struct tcm *tcm; - uint8_t *current_va; + u8 *current_va; dma_addr_t current_pa; struct pat *last_pat; @@ -140,7 +140,7 @@ struct refill_engine { struct dmm *dmm; struct tcm *tcm; - uint8_t *refill_va; + u8 *refill_va; dma_addr_t refill_pa; /* only one trans per engine for now */ @@ -154,7 +154,7 @@ struct refill_engine { }; struct dmm_platform_data { - uint32_t cpu_cache_flags; + u32 cpu_cache_flags; }; struct dmm { diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index 4be0c94673f5..f9fa1c90b35c 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -58,11 +58,11 @@ static DEFINE_SPINLOCK(list_lock); } static const struct { - uint32_t x_shft; /* unused X-bits (as part of bpp) */ - uint32_t y_shft; /* unused Y-bits (as part of bpp) */ - uint32_t cpp; /* bytes/chars per pixel */ - uint32_t slot_w; /* width of each slot (in pixels) */ - uint32_t slot_h; /* height of each slot (in pixels) */ + u32 x_shft; /* unused X-bits (as part of bpp) */ + u32 y_shft; /* unused Y-bits (as part of bpp) */ + u32 cpp; /* bytes/chars per pixel */ + u32 slot_w; /* width of each slot (in pixels) */ + u32 slot_h; /* height of each slot (in pixels) */ } geom[TILFMT_NFORMATS] = { [TILFMT_8BIT] = GEOM(0, 0, 1), [TILFMT_16BIT] = GEOM(0, 1, 2), @@ -72,7 +72,7 @@ static const struct { /* lookup table for registers w/ per-engine instances */ -static const uint32_t reg[][4] = { +static const u32 reg[][4] = { [PAT_STATUS] = {DMM_PAT_STATUS__0, DMM_PAT_STATUS__1, DMM_PAT_STATUS__2, DMM_PAT_STATUS__3}, [PAT_DESCR] = {DMM_PAT_DESCR__0, DMM_PAT_DESCR__1, @@ -111,10 +111,10 @@ static void *alloc_dma(struct dmm_txn *txn, size_t sz, dma_addr_t *pa) } /* check status and spin until wait_mask comes true */ -static int wait_status(struct refill_engine *engine, uint32_t wait_mask) +static int wait_status(struct refill_engine *engine, u32 wait_mask) { struct dmm *dmm = engine->dmm; - uint32_t r = 0, err, i; + u32 r = 0, err, i; i = DMM_FIXED_RETRY_COUNT; while (true) { @@ -158,7 +158,7 @@ static void release_engine(struct refill_engine *engine) static irqreturn_t omap_dmm_irq_handler(int irq, void *arg) { struct dmm *dmm = arg; - uint32_t status = dmm_read(dmm, DMM_PAT_IRQSTATUS); + u32 status = dmm_read(dmm, DMM_PAT_IRQSTATUS); int i; /* ack IRQ */ @@ -226,10 +226,10 @@ static struct dmm_txn *dmm_txn_init(struct dmm *dmm, struct tcm *tcm) * corresponding slot is cleared (ie. dummy_pa is programmed) */ static void dmm_txn_append(struct dmm_txn *txn, struct pat_area *area, - struct page **pages, uint32_t npages, uint32_t roll) + struct page **pages, u32 npages, u32 roll) { dma_addr_t pat_pa = 0, data_pa = 0; - uint32_t *data; + u32 *data; struct pat *pat; struct refill_engine *engine = txn->engine_handle; int columns = (1 + area->x1 - area->x0); @@ -239,7 +239,7 @@ static void dmm_txn_append(struct dmm_txn *txn, struct pat_area *area, pat = alloc_dma(txn, sizeof(*pat), &pat_pa); if (txn->last_pat) - txn->last_pat->next_pa = (uint32_t)pat_pa; + txn->last_pat->next_pa = (u32)pat_pa; pat->area = *area; @@ -330,7 +330,7 @@ cleanup: * DMM programming */ static int fill(struct tcm_area *area, struct page **pages, - uint32_t npages, uint32_t roll, bool wait) + u32 npages, u32 roll, bool wait) { int ret = 0; struct tcm_area slice, area_s; @@ -378,7 +378,7 @@ static int fill(struct tcm_area *area, struct page **pages, /* note: slots for which pages[i] == NULL are filled w/ dummy page */ int tiler_pin(struct tiler_block *block, struct page **pages, - uint32_t npages, uint32_t roll, bool wait) + u32 npages, u32 roll, bool wait) { int ret; @@ -398,8 +398,8 @@ int tiler_unpin(struct tiler_block *block) /* * Reserve/release */ -struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w, - uint16_t h, uint16_t align) +struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, u16 w, + u16 h, u16 align) { struct tiler_block *block = kzalloc(sizeof(*block), GFP_KERNEL); u32 min_align = 128; @@ -542,8 +542,8 @@ dma_addr_t tiler_ssptr(struct tiler_block *block) block->area.p0.y * geom[block->fmt].slot_h); } -dma_addr_t tiler_tsptr(struct tiler_block *block, uint32_t orient, - uint32_t x, uint32_t y) +dma_addr_t tiler_tsptr(struct tiler_block *block, u32 orient, + u32 x, u32 y) { struct tcm_pt *p = &block->area.p0; BUG_ON(!validfmt(block->fmt)); @@ -553,14 +553,14 @@ dma_addr_t tiler_tsptr(struct tiler_block *block, uint32_t orient, (p->y * geom[block->fmt].slot_h) + y); } -void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h) +void tiler_align(enum tiler_fmt fmt, u16 *w, u16 *h) { BUG_ON(!validfmt(fmt)); *w = round_up(*w, geom[fmt].slot_w); *h = round_up(*h, geom[fmt].slot_h); } -uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient) +u32 tiler_stride(enum tiler_fmt fmt, u32 orient) { BUG_ON(!validfmt(fmt)); @@ -570,19 +570,19 @@ uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient) return 1 << (CONT_WIDTH_BITS + geom[fmt].y_shft); } -size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h) +size_t tiler_size(enum tiler_fmt fmt, u16 w, u16 h) { tiler_align(fmt, &w, &h); return geom[fmt].cpp * w * h; } -size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h) +size_t tiler_vsize(enum tiler_fmt fmt, u16 w, u16 h) { BUG_ON(!validfmt(fmt)); return round_up(geom[fmt].cpp * w, PAGE_SIZE) * h; } -uint32_t tiler_get_cpu_cache_flags(void) +u32 tiler_get_cpu_cache_flags(void) { return omap_dmm->plat_data->cpu_cache_flags; } diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.h b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.h index cc78ba4fe6ab..835e6654fa82 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.h +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.h @@ -88,30 +88,30 @@ int tiler_map_show(struct seq_file *s, void *arg); /* pin/unpin */ int tiler_pin(struct tiler_block *block, struct page **pages, - uint32_t npages, uint32_t roll, bool wait); + u32 npages, u32 roll, bool wait); int tiler_unpin(struct tiler_block *block); /* reserve/release */ -struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w, uint16_t h, - uint16_t align); +struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, u16 w, u16 h, + u16 align); struct tiler_block *tiler_reserve_1d(size_t size); int tiler_release(struct tiler_block *block); /* utilities */ dma_addr_t tiler_ssptr(struct tiler_block *block); -dma_addr_t tiler_tsptr(struct tiler_block *block, uint32_t orient, - uint32_t x, uint32_t y); -uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient); -size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h); -size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h); -void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h); -uint32_t tiler_get_cpu_cache_flags(void); +dma_addr_t tiler_tsptr(struct tiler_block *block, u32 orient, + u32 x, u32 y); +u32 tiler_stride(enum tiler_fmt fmt, u32 orient); +size_t tiler_size(enum tiler_fmt fmt, u16 w, u16 h); +size_t tiler_vsize(enum tiler_fmt fmt, u16 w, u16 h); +void tiler_align(enum tiler_fmt fmt, u16 *w, u16 *h); +u32 tiler_get_cpu_cache_flags(void); bool dmm_is_available(void); extern struct platform_driver omap_dmm_driver; /* GEM bo flags -> tiler fmt */ -static inline enum tiler_fmt gem2fmt(uint32_t flags) +static inline enum tiler_fmt gem2fmt(u32 flags) { switch (flags & OMAP_BO_TILED) { case OMAP_BO_TILED_8: diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 0ac97fe09f9b..ba322c519999 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -46,7 +46,7 @@ struct omap_drm_usergart; struct omap_drm_private { - uint32_t omaprev; + u32 omaprev; const struct dispc_ops *dispc_ops; @@ -81,7 +81,7 @@ struct omap_drm_private { /* irq handling: */ spinlock_t wait_lock; /* protects the wait_list */ struct list_head wait_list; /* list of omap_irq_wait */ - uint32_t irq_mask; /* enabled irqs in addition to wait_list */ + u32 irq_mask; /* enabled irqs in addition to wait_list */ /* memory bandwidth limit if it is needed on the platform */ unsigned int max_bandwidth; diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index b2539a90e1a4..5fd22ca73913 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -52,8 +52,8 @@ static const u32 formats[] = { /* per-plane info for the fb: */ struct plane { struct drm_gem_object *bo; - uint32_t pitch; - uint32_t offset; + u32 pitch; + u32 offset; dma_addr_t dma_addr; }; @@ -100,10 +100,10 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { .destroy = omap_framebuffer_destroy, }; -static uint32_t get_linear_addr(struct plane *plane, +static u32 get_linear_addr(struct plane *plane, const struct drm_format_info *format, int n, int x, int y) { - uint32_t offset; + u32 offset; offset = plane->offset + (x * format->cpp[n] / (n == 0 ? 1 : format->hsub)) @@ -121,9 +121,9 @@ bool omap_framebuffer_supports_rotation(struct drm_framebuffer *fb) } /* Note: DRM rotates counter-clockwise, TILER & DSS rotates clockwise */ -static uint32_t drm_rotation_to_tiler(unsigned int drm_rot) +static u32 drm_rotation_to_tiler(unsigned int drm_rot) { - uint32_t orient; + u32 orient; switch (drm_rot & DRM_MODE_ROTATE_MASK) { default: @@ -158,7 +158,7 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); const struct drm_format_info *format = omap_fb->format; struct plane *plane = &omap_fb->planes[0]; - uint32_t x, y, orient = 0; + u32 x, y, orient = 0; info->fourcc = fb->format->format; @@ -177,8 +177,8 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, y = state->src_y >> 16; if (omap_gem_flags(plane->bo) & OMAP_BO_TILED) { - uint32_t w = state->src_w >> 16; - uint32_t h = state->src_h >> 16; + u32 w = state->src_w >> 16; + u32 h = state->src_h >> 16; orient = drm_rotation_to_tiler(state->rotation); diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 443469d4fa46..0faf042b82e1 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -39,13 +39,13 @@ struct omap_gem_object { struct list_head mm_list; - uint32_t flags; + u32 flags; /** width/height for tiled formats (rounded up to slot boundaries) */ - uint16_t width, height; + u16 width, height; /** roll applied when mapping to DMM */ - uint32_t roll; + u32 roll; /** * dma_addr contains the buffer DMA address. It is valid for @@ -73,7 +73,7 @@ struct omap_gem_object { /** * # of users of dma_addr */ - uint32_t dma_addr_cnt; + u32 dma_addr_cnt; /** * If the buffer has been imported from a dmabuf the OMAP_DB_DMABUF flag @@ -137,7 +137,7 @@ struct omap_drm_usergart { */ /** get mmap offset */ -static uint64_t mmap_offset(struct drm_gem_object *obj) +static u64 mmap_offset(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; int ret; @@ -331,14 +331,15 @@ static void omap_gem_detach_pages(struct drm_gem_object *obj) } /* get buffer flags */ -uint32_t omap_gem_flags(struct drm_gem_object *obj) +u32 omap_gem_flags(struct drm_gem_object *obj) { return to_omap_bo(obj)->flags; } -uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj) +u64 omap_gem_mmap_offset(struct drm_gem_object *obj) { - uint64_t offset; + u64 offset; + mutex_lock(&obj->dev->struct_mutex); offset = mmap_offset(obj); mutex_unlock(&obj->dev->struct_mutex); @@ -649,7 +650,7 @@ int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev, * into user memory. We don't have to do much here at the moment. */ int omap_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, - uint32_t handle, uint64_t *offset) + u32 handle, u64 *offset) { struct drm_gem_object *obj; int ret = 0; @@ -675,10 +676,10 @@ fail: * * Call only from non-atomic contexts. */ -int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll) +int omap_gem_roll(struct drm_gem_object *obj, u32 roll) { struct omap_gem_object *omap_obj = to_omap_bo(obj); - uint32_t npages = obj->size >> PAGE_SHIFT; + u32 npages = obj->size >> PAGE_SHIFT; int ret = 0; if (roll > npages) { @@ -808,7 +809,7 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) if (!is_contiguous(omap_obj) && priv->has_dmm) { if (omap_obj->dma_addr_cnt == 0) { struct page **pages; - uint32_t npages = obj->size >> PAGE_SHIFT; + u32 npages = obj->size >> PAGE_SHIFT; enum tiler_fmt fmt = gem2fmt(omap_obj->flags); struct tiler_block *block; @@ -904,7 +905,7 @@ void omap_gem_unpin(struct drm_gem_object *obj) * specified orientation and x,y offset from top-left corner of buffer * (only valid for tiled 2d buffers) */ -int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, uint32_t orient, +int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, u32 orient, int x, int y, dma_addr_t *dma_addr) { struct omap_gem_object *omap_obj = to_omap_bo(obj); @@ -921,7 +922,7 @@ int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, uint32_t orient, } /* Get tiler stride for the buffer (only valid for 2d tiled buffers) */ -int omap_gem_tiled_stride(struct drm_gem_object *obj, uint32_t orient) +int omap_gem_tiled_stride(struct drm_gem_object *obj, u32 orient) { struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret = -EINVAL; @@ -1003,7 +1004,8 @@ int omap_gem_resume(struct drm_device *dev) list_for_each_entry(omap_obj, &priv->obj_list, mm_list) { if (omap_obj->block) { struct drm_gem_object *obj = &omap_obj->base; - uint32_t npages = obj->size >> PAGE_SHIFT; + u32 npages = obj->size >> PAGE_SHIFT; + WARN_ON(!omap_obj->pages); /* this can't happen */ ret = tiler_pin(omap_obj->block, omap_obj->pages, npages, @@ -1027,7 +1029,7 @@ int omap_gem_resume(struct drm_device *dev) void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) { struct omap_gem_object *omap_obj = to_omap_bo(obj); - uint64_t off; + u64 off; off = drm_vma_node_start(&obj->vma_node); @@ -1115,7 +1117,7 @@ void omap_gem_free_object(struct drm_gem_object *obj) /* GEM buffer object constructor */ struct drm_gem_object *omap_gem_new(struct drm_device *dev, - union omap_gem_size gsize, uint32_t flags) + union omap_gem_size gsize, u32 flags) { struct omap_drm_private *priv = dev->dev_private; struct omap_gem_object *omap_obj; @@ -1280,7 +1282,7 @@ done: /* convenience method to construct a GEM buffer object, and userspace handle */ int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file, - union omap_gem_size gsize, uint32_t flags, uint32_t *handle) + union omap_gem_size gsize, u32 flags, u32 *handle) { struct drm_gem_object *obj; int ret; @@ -1327,7 +1329,8 @@ void omap_gem_init(struct drm_device *dev) /* reserve 4k aligned/wide regions for userspace mappings: */ for (i = 0; i < ARRAY_SIZE(fmts); i++) { - uint16_t h = 1, w = PAGE_SIZE >> i; + u16 h = 1, w = PAGE_SIZE >> i; + tiler_align(fmts[i], &w, &h); /* note: since each region is 1 4kb page wide, and minimum * number of rows, the height ends up being the same as the diff --git a/drivers/gpu/drm/omapdrm/omap_gem.h b/drivers/gpu/drm/omapdrm/omap_gem.h index 35fa690b3d90..a78bde05193a 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.h +++ b/drivers/gpu/drm/omapdrm/omap_gem.h @@ -53,17 +53,17 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); /* GEM Object Creation and Deletion */ struct drm_gem_object *omap_gem_new(struct drm_device *dev, - union omap_gem_size gsize, uint32_t flags); + union omap_gem_size gsize, u32 flags); struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, struct sg_table *sgt); int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file, - union omap_gem_size gsize, uint32_t flags, uint32_t *handle); + union omap_gem_size gsize, u32 flags, u32 *handle); void omap_gem_free_object(struct drm_gem_object *obj); void *omap_gem_vaddr(struct drm_gem_object *obj); /* Dumb Buffers Interface */ int omap_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, - uint32_t handle, uint64_t *offset); + u32 handle, u64 *offset); int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); @@ -71,7 +71,7 @@ int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev, int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma); int omap_gem_mmap_obj(struct drm_gem_object *obj, struct vm_area_struct *vma); -uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj); +u64 omap_gem_mmap_offset(struct drm_gem_object *obj); size_t omap_gem_mmap_size(struct drm_gem_object *obj); /* PRIME Interface */ @@ -81,7 +81,7 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, struct dma_buf *buffer); int omap_gem_fault(struct vm_fault *vmf); -int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll); +int omap_gem_roll(struct drm_gem_object *obj, u32 roll); void omap_gem_cpu_sync_page(struct drm_gem_object *obj, int pgoff); void omap_gem_dma_sync_buffer(struct drm_gem_object *obj, enum dma_data_direction dir); @@ -91,9 +91,9 @@ int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages, bool remap); int omap_gem_put_pages(struct drm_gem_object *obj); -uint32_t omap_gem_flags(struct drm_gem_object *obj); -int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, uint32_t orient, +u32 omap_gem_flags(struct drm_gem_object *obj); +int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, u32 orient, int x, int y, dma_addr_t *dma_addr); -int omap_gem_tiled_stride(struct drm_gem_object *obj, uint32_t orient); +int omap_gem_tiled_stride(struct drm_gem_object *obj, u32 orient); #endif /* __OMAPDRM_GEM_H__ */ diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c index 53ba424823b2..976dc0e44482 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/drivers/gpu/drm/omapdrm/omap_irq.c @@ -20,7 +20,7 @@ struct omap_irq_wait { struct list_head node; wait_queue_head_t wq; - uint32_t irqmask; + u32 irqmask; int count; }; @@ -29,7 +29,7 @@ static void omap_irq_update(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_irq_wait *wait; - uint32_t irqmask = priv->irq_mask; + u32 irqmask = priv->irq_mask; assert_spin_locked(&priv->wait_lock); @@ -48,7 +48,7 @@ static void omap_irq_wait_handler(struct omap_irq_wait *wait) } struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, - uint32_t irqmask, int count) + u32 irqmask, int count) { struct omap_drm_private *priv = dev->dev_private; struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL); diff --git a/drivers/gpu/drm/omapdrm/omap_irq.h b/drivers/gpu/drm/omapdrm/omap_irq.h index 606c09932bc0..9d5441468eca 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.h +++ b/drivers/gpu/drm/omapdrm/omap_irq.h @@ -32,7 +32,7 @@ void omap_drm_irq_uninstall(struct drm_device *dev); int omap_drm_irq_install(struct drm_device *dev); struct omap_irq_wait *omap_irq_wait_init(struct drm_device *dev, - uint32_t irqmask, int count); + u32 irqmask, int count); int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, unsigned long timeout); diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 7d789d1551a1..0665ed9fe395 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -201,7 +201,7 @@ static void omap_plane_reset(struct drm_plane *plane) static int omap_plane_atomic_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, - uint64_t val) + u64 val) { struct omap_drm_private *priv = plane->dev->dev_private; @@ -216,7 +216,7 @@ static int omap_plane_atomic_set_property(struct drm_plane *plane, static int omap_plane_atomic_get_property(struct drm_plane *plane, const struct drm_plane_state *state, struct drm_property *property, - uint64_t *val) + u64 *val) { struct omap_drm_private *priv = plane->dev->dev_private; diff --git a/drivers/gpu/drm/omapdrm/tcm-sita.c b/drivers/gpu/drm/omapdrm/tcm-sita.c index 661362d072f7..d7f7bc9f061a 100644 --- a/drivers/gpu/drm/omapdrm/tcm-sita.c +++ b/drivers/gpu/drm/omapdrm/tcm-sita.c @@ -33,8 +33,8 @@ static unsigned long mask[8]; * map ptr to bitmap * stride slots in a row */ -static void free_slots(unsigned long pos, uint16_t w, uint16_t h, - unsigned long *map, uint16_t stride) +static void free_slots(unsigned long pos, u16 w, u16 h, + unsigned long *map, u16 stride) { int i; @@ -48,7 +48,7 @@ static void free_slots(unsigned long pos, uint16_t w, uint16_t h, * map ptr to bitmap * num_bits number of bits in bitmap */ -static int r2l_b2t_1d(uint16_t w, unsigned long *pos, unsigned long *map, +static int r2l_b2t_1d(u16 w, unsigned long *pos, unsigned long *map, size_t num_bits) { unsigned long search_count = 0; @@ -84,7 +84,7 @@ static int r2l_b2t_1d(uint16_t w, unsigned long *pos, unsigned long *map, * num_bits = size of bitmap * stride = bits in one row of container */ -static int l2r_t2b(uint16_t w, uint16_t h, uint16_t a, int16_t offset, +static int l2r_t2b(u16 w, u16 h, u16 a, s16 offset, unsigned long *pos, unsigned long slot_bytes, unsigned long *map, size_t num_bits, size_t slot_stride) { @@ -179,7 +179,7 @@ static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots, } static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u16 align, - int16_t offset, uint16_t slot_bytes, + s16 offset, u16 slot_bytes, struct tcm_area *area) { unsigned long pos; @@ -208,7 +208,7 @@ static void sita_deinit(struct tcm *tcm) static s32 sita_free(struct tcm *tcm, struct tcm_area *area) { unsigned long pos; - uint16_t w, h; + u16 w, h; pos = area->p0.x + area->p0.y * tcm->width; if (area->is2d) { diff --git a/drivers/gpu/drm/omapdrm/tcm.h b/drivers/gpu/drm/omapdrm/tcm.h index d8a369a4f269..8efcda93c50d 100644 --- a/drivers/gpu/drm/omapdrm/tcm.h +++ b/drivers/gpu/drm/omapdrm/tcm.h @@ -65,7 +65,7 @@ struct tcm { /* function table */ s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u16 align, - int16_t offset, uint16_t slot_bytes, + s16 offset, u16 slot_bytes, struct tcm_area *area); s32 (*reserve_1d)(struct tcm *tcm, u32 slots, struct tcm_area *area); s32 (*free)(struct tcm *tcm, struct tcm_area *area); @@ -129,7 +129,7 @@ static inline void tcm_deinit(struct tcm *tcm) * allocation. */ static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height, - u16 align, int16_t offset, uint16_t slot_bytes, + u16 align, s16 offset, u16 slot_bytes, struct tcm_area *area) { /* perform rudimentary error checking */ -- cgit v1.2.3 From d11e5c827a4dbbb4174087669e3c7d231570985b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:34 +0200 Subject: drm: omapdrm: Use unsigned int type The kernel favours 'unsigned int' over plain 'unsigned'. Replace all occurences of the latter by the former. This avoid lots of checkpatch complaints in patches that touch lines where a plain 'unsigned' is used. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 8 +- .../drm/omapdrm/displays/panel-sony-acx565akm.c | 6 +- drivers/gpu/drm/omapdrm/dss/dispc.c | 25 +++--- drivers/gpu/drm/omapdrm/dss/dpi.c | 2 +- drivers/gpu/drm/omapdrm/dss/dsi.c | 98 +++++++++++----------- drivers/gpu/drm/omapdrm/dss/dss.c | 12 +-- drivers/gpu/drm/omapdrm/dss/dss.h | 12 +-- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 2 +- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 2 +- drivers/gpu/drm/omapdrm/dss/hdmi5_core.c | 24 +++--- drivers/gpu/drm/omapdrm/dss/hdmi_phy.c | 2 +- drivers/gpu/drm/omapdrm/dss/hdmi_wp.c | 2 +- drivers/gpu/drm/omapdrm/dss/omapdss.h | 4 +- drivers/gpu/drm/omapdrm/dss/pll.c | 4 +- 14 files changed, 102 insertions(+), 101 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index 15399a1a666b..fb83f757b113 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -86,7 +86,7 @@ struct panel_drv_data { struct workqueue_struct *workqueue; bool ulps_enabled; - unsigned ulps_timeout; + unsigned int ulps_timeout; struct delayed_work ulps_work; }; @@ -513,7 +513,7 @@ static ssize_t dsicm_show_ulps(struct device *dev, { struct platform_device *pdev = to_platform_device(dev); struct panel_drv_data *ddata = platform_get_drvdata(pdev); - unsigned t; + unsigned int t; mutex_lock(&ddata->lock); t = ddata->ulps_enabled; @@ -560,7 +560,7 @@ static ssize_t dsicm_show_ulps_timeout(struct device *dev, { struct platform_device *pdev = to_platform_device(dev); struct panel_drv_data *ddata = platform_get_drvdata(pdev); - unsigned t; + unsigned int t; mutex_lock(&ddata->lock); t = ddata->ulps_timeout; @@ -1064,7 +1064,7 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev, int r; int first = 1; int plen; - unsigned buf_used = 0; + unsigned int buf_used = 0; if (size < w * h * 3) return -ENOMEM; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c index 8e5bff4e5226..06d7d8362a73 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c @@ -289,7 +289,7 @@ static void enable_backlight_ctrl(struct panel_drv_data *ddata, int enable) acx565akm_write(ddata, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2); } -static void set_cabc_mode(struct panel_drv_data *ddata, unsigned mode) +static void set_cabc_mode(struct panel_drv_data *ddata, unsigned int mode) { u16 cabc_ctrl; @@ -303,12 +303,12 @@ static void set_cabc_mode(struct panel_drv_data *ddata, unsigned mode) acx565akm_write(ddata, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2); } -static unsigned get_cabc_mode(struct panel_drv_data *ddata) +static unsigned int get_cabc_mode(struct panel_drv_data *ddata) { return ddata->cabc_mode; } -static unsigned get_hw_cabc_mode(struct panel_drv_data *ddata) +static unsigned int get_hw_cabc_mode(struct panel_drv_data *ddata) { u8 cabc_ctrl; diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 4e8f68efd169..86d18f2d48ba 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -969,7 +969,7 @@ static void dispc_ovl_set_pre_mult_alpha(enum omap_plane_id plane, static void dispc_ovl_setup_global_alpha(enum omap_plane_id plane, enum omap_overlay_caps caps, u8 global_alpha) { - static const unsigned shifts[] = { 0, 8, 16, 24, }; + static const unsigned int shifts[] = { 0, 8, 16, 24, }; int shift; if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) @@ -1197,7 +1197,7 @@ void dispc_wb_set_channel_in(enum dss_writeback_channel channel) static void dispc_ovl_set_burst_size(enum omap_plane_id plane, enum omap_burst_size burst_size) { - static const unsigned shifts[] = { 6, 14, 14, 14, 14, }; + static const unsigned int shifts[] = { 6, 14, 14, 14, 14, }; int shift; shift = shifts[plane]; @@ -1285,7 +1285,7 @@ static void dispc_ovl_set_vid_color_conv(enum omap_plane_id plane, static void dispc_ovl_enable_replication(enum omap_plane_id plane, enum omap_overlay_caps caps, bool enable) { - static const unsigned shifts[] = { 5, 10, 10, 10 }; + static const unsigned int shifts[] = { 5, 10, 10, 10 }; int shift; if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0) @@ -1450,9 +1450,8 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, * All sizes are in bytes. Both the buffer and burst are made of * buffer_units, and the fifo thresholds must be buffer_unit aligned. */ - - unsigned buf_unit = dispc.feat->buffer_size_unit; - unsigned ovl_fifo_size, total_fifo_size, burst_size; + unsigned int buf_unit = dispc.feat->buffer_size_unit; + unsigned int ovl_fifo_size, total_fifo_size, burst_size; int i; burst_size = dispc_ovl_get_burst_size(plane); @@ -2006,8 +2005,8 @@ static s32 pixinc(int pixels, u8 ps) } static void calc_offset(u16 screen_width, u16 width, - u32 fourcc, bool fieldmode, - unsigned int field_offset, unsigned *offset0, unsigned *offset1, + u32 fourcc, bool fieldmode, unsigned int field_offset, + unsigned int *offset0, unsigned int *offset1, s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim, enum omap_dss_rotation_type rotation_type, u8 rotation) { @@ -2477,7 +2476,7 @@ static int dispc_ovl_setup_common(enum omap_plane_id plane, bool five_taps = true; bool fieldmode = false; int r, cconv = 0; - unsigned offset0, offset1; + unsigned int offset0, offset1; s32 row_inc; s32 pix_inc; u16 frame_width, frame_height; @@ -3040,7 +3039,7 @@ static int vm_flag_to_int(enum display_flags flags, enum display_flags high, static void dispc_mgr_set_timings(enum omap_channel channel, const struct videomode *vm) { - unsigned xtot, ytot; + unsigned int xtot, ytot; unsigned long ht, vt; struct videomode t = *vm; @@ -3119,7 +3118,7 @@ static unsigned long dispc_fclk_rate(void) r = dss_get_dispc_clk_rate(); } else { struct dss_pll *pll; - unsigned clkout_idx; + unsigned int clkout_idx; pll = dss_pll_find_by_src(src); clkout_idx = dss_pll_get_clkout_idx_for_src(src); @@ -3146,7 +3145,7 @@ static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) r = dss_get_dispc_clk_rate(); } else { struct dss_pll *pll; - unsigned clkout_idx; + unsigned int clkout_idx; pll = dss_pll_find_by_src(src); clkout_idx = dss_pll_get_clkout_idx_for_src(src); @@ -3487,7 +3486,7 @@ bool dispc_div_calc(unsigned long dispc_freq, unsigned long pck, lck; unsigned long lck_max; unsigned long pckd_hw_min, pckd_hw_max; - unsigned min_fck_per_pck; + unsigned int min_fck_per_pck; unsigned long fck; #ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index ea44137ed08c..0a6eb39be444 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -141,7 +141,7 @@ static enum dss_clk_source dpi_get_clk_src(struct dpi_data *dpi) struct dpi_clk_calc_ctx { struct dss_pll *pll; - unsigned clkout_idx; + unsigned int clkout_idx; /* inputs */ diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 80f1f3679a3c..86bd47f23424 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -269,10 +269,10 @@ enum dsi_vc_source { struct dsi_irq_stats { unsigned long last_reset; - unsigned irq_count; - unsigned dsi_irqs[32]; - unsigned vc_irqs[4][32]; - unsigned cio_irqs[32]; + unsigned int irq_count; + unsigned int dsi_irqs[32]; + unsigned int vc_irqs[4][32]; + unsigned int cio_irqs[32]; }; struct dsi_isr_tables { @@ -373,7 +373,7 @@ struct dsi_data { int update_channel; #ifdef DSI_PERF_MEASURE - unsigned update_bytes; + unsigned int update_bytes; #endif bool te_enabled; @@ -406,13 +406,13 @@ struct dsi_data { struct dsi_irq_stats irq_stats; #endif - unsigned num_lanes_supported; - unsigned line_buffer_size; + unsigned int num_lanes_supported; + unsigned int line_buffer_size; struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; - unsigned num_lanes_used; + unsigned int num_lanes_used; - unsigned scp_clk_refcount; + unsigned int scp_clk_refcount; struct dss_lcd_mgr_config mgr_config; struct videomode vm; @@ -782,7 +782,7 @@ static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus, } static void dsi_call_isrs(struct dsi_isr_data *isr_array, - unsigned isr_array_size, u32 irqstatus) + unsigned int isr_array_size, u32 irqstatus) { struct dsi_isr_data *isr_data; int i; @@ -891,7 +891,7 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) /* dsi->irq_lock has to be locked by the caller */ static void _omap_dsi_configure_irqs(struct platform_device *dsidev, struct dsi_isr_data *isr_array, - unsigned isr_array_size, u32 default_mask, + unsigned int isr_array_size, u32 default_mask, const struct dsi_reg enable_reg, const struct dsi_reg status_reg) { @@ -975,7 +975,7 @@ static void _dsi_initialize_irq(struct platform_device *dsidev) } static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask, - struct dsi_isr_data *isr_array, unsigned isr_array_size) + struct dsi_isr_data *isr_array, unsigned int isr_array_size) { struct dsi_isr_data *isr_data; int free_idx; @@ -1009,7 +1009,7 @@ static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask, } static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask, - struct dsi_isr_data *isr_array, unsigned isr_array_size) + struct dsi_isr_data *isr_array, unsigned int isr_array_size) { struct dsi_isr_data *isr_data; int i; @@ -1301,7 +1301,7 @@ static int dsi_lp_clock_calc(unsigned long dsi_fclk, unsigned long lp_clk_min, unsigned long lp_clk_max, struct dsi_lp_clock_info *lp_cinfo) { - unsigned lp_clk_div; + unsigned int lp_clk_div; unsigned long lp_clk; lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2); @@ -1320,9 +1320,9 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long dsi_fclk; - unsigned lp_clk_div; + unsigned int lp_clk_div; unsigned long lp_clk; - unsigned lpdiv_max = dsi->data->max_pll_lpdiv; + unsigned int lpdiv_max = dsi->data->max_pll_lpdiv; lp_clk_div = dsi->user_lp_cinfo.lp_clk_div; @@ -1798,7 +1798,7 @@ static int dsi_cio_power(struct platform_device *dsidev, return 0; } -static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) +static unsigned int dsi_get_line_buf_size(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int val; @@ -1850,9 +1850,9 @@ static int dsi_set_lane_config(struct platform_device *dsidev) r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); for (i = 0; i < dsi->num_lanes_used; ++i) { - unsigned offset = offsets[i]; - unsigned polarity, lane_number; - unsigned t; + unsigned int offset = offsets[i]; + unsigned int polarity, lane_number; + unsigned int t; for (t = 0; t < dsi->num_lanes_supported; ++t) if (dsi->lanes[t].function == functions[i]) @@ -1870,7 +1870,7 @@ static int dsi_set_lane_config(struct platform_device *dsidev) /* clear the unused lanes */ for (; i < dsi->num_lanes_supported; ++i) { - unsigned offset = offsets[i]; + unsigned int offset = offsets[i]; r = FLD_MOD(r, 0, offset + 2, offset); r = FLD_MOD(r, 0, offset + 3, offset + 3); @@ -1881,7 +1881,8 @@ static int dsi_set_lane_config(struct platform_device *dsidev) return 0; } -static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) +static inline unsigned int ns2ddr(struct platform_device *dsidev, + unsigned int ns) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); @@ -1890,7 +1891,8 @@ static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000; } -static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr) +static inline unsigned int ddr2ns(struct platform_device *dsidev, + unsigned int ddr) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); @@ -1978,7 +1980,7 @@ static void dsi_cio_timings(struct platform_device *dsidev) /* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */ static void dsi_cio_enable_lane_override(struct platform_device *dsidev, - unsigned mask_p, unsigned mask_n) + unsigned int mask_p, unsigned int mask_n) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int i; @@ -1988,7 +1990,7 @@ static void dsi_cio_enable_lane_override(struct platform_device *dsidev, l = 0; for (i = 0; i < dsi->num_lanes_supported; ++i) { - unsigned p = dsi->lanes[i].polarity; + unsigned int p = dsi->lanes[i].polarity; if (mask_p & (1 << i)) l |= 1 << (i * 2 + (p ? 0 : 1)); @@ -2075,10 +2077,10 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) } /* return bitmask of enabled lanes, lane0 being the lsb */ -static unsigned dsi_get_lane_mask(struct platform_device *dsidev) +static unsigned int dsi_get_lane_mask(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - unsigned mask = 0; + unsigned int mask = 0; int i; for (i = 0; i < dsi->num_lanes_supported; ++i) { @@ -2204,7 +2206,7 @@ static int dsi_cio_init(struct platform_device *dsidev) dsi_write_reg(dsidev, DSI_TIMING1, l); if (dsi->ulps_enabled) { - unsigned mask_p; + unsigned int mask_p; int i; DSSDBG("manual ulps exit\n"); @@ -3223,7 +3225,7 @@ static int dsi_enter_ulps(struct platform_device *dsidev) struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DECLARE_COMPLETION_ONSTACK(completion); int r, i; - unsigned mask; + unsigned int mask; DSSDBG("Entering ULPS"); @@ -3313,7 +3315,7 @@ err: } static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, - unsigned ticks, bool x4, bool x16) + unsigned int ticks, bool x4, bool x16) { unsigned long fck; unsigned long total_ticks; @@ -3339,8 +3341,8 @@ static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks, - bool x8, bool x16) +static void dsi_set_ta_timeout(struct platform_device *dsidev, + unsigned int ticks, bool x8, bool x16) { unsigned long fck; unsigned long total_ticks; @@ -3367,7 +3369,7 @@ static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks, } static void dsi_set_stop_state_counter(struct platform_device *dsidev, - unsigned ticks, bool x4, bool x16) + unsigned int ticks, bool x4, bool x16) { unsigned long fck; unsigned long total_ticks; @@ -3394,7 +3396,7 @@ static void dsi_set_stop_state_counter(struct platform_device *dsidev, } static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, - unsigned ticks, bool x4, bool x16) + unsigned int ticks, bool x4, bool x16) { unsigned long fck; unsigned long total_ticks; @@ -3740,13 +3742,13 @@ static int dsi_proto_config(struct platform_device *dsidev) static void dsi_proto_timings(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; - unsigned tclk_pre, tclk_post; - unsigned ths_prepare, ths_prepare_ths_zero, ths_zero; - unsigned ths_trail, ths_exit; - unsigned ddr_clk_pre, ddr_clk_post; - unsigned enter_hs_mode_lat, exit_hs_mode_lat; - unsigned ths_eot; + unsigned int tlpx, tclk_zero, tclk_prepare, tclk_trail; + unsigned int tclk_pre, tclk_post; + unsigned int ths_prepare, ths_prepare_ths_zero, ths_zero; + unsigned int ths_trail, ths_exit; + unsigned int ddr_clk_pre, ddr_clk_post; + unsigned int enter_hs_mode_lat, exit_hs_mode_lat; + unsigned int ths_eot; int ndl = dsi->num_lanes_used - 1; u32 r; @@ -4014,16 +4016,16 @@ static void dsi_update_screen_dispc(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); enum omap_channel dispc_channel = dsi->output.dispc_channel; - unsigned bytespp; - unsigned bytespl; - unsigned bytespf; - unsigned total_len; - unsigned packet_payload; - unsigned packet_len; + unsigned int bytespp; + unsigned int bytespl; + unsigned int bytespf; + unsigned int total_len; + unsigned int packet_payload; + unsigned int packet_len; u32 l; int r; const unsigned channel = dsi->update_channel; - const unsigned line_buf_size = dsi->line_buffer_size; + const unsigned int line_buf_size = dsi->line_buffer_size; u16 w = dsi->vm.hactive; u16 h = dsi->vm.vactive; diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 04300b2da1b1..f1c7ef3a2ec3 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -181,8 +181,8 @@ static void dss_restore_context(void) void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable) { - unsigned shift; - unsigned val; + unsigned int shift; + unsigned int val; if (!dss.syscon_pll_ctrl) return; @@ -211,7 +211,7 @@ void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable) static int dss_ctrl_pll_set_control_mux(enum dss_clk_source clk_src, enum omap_channel channel) { - unsigned shift, val; + unsigned int shift, val; if (!dss.syscon_pll_ctrl) return -EINVAL; @@ -620,12 +620,12 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min, unsigned long fck_hw_max; unsigned long fckd_hw_max; unsigned long prate; - unsigned m; + unsigned int m; fck_hw_max = dss.feat->fck_freq_max; if (dss.parent_clk == NULL) { - unsigned pckd; + unsigned int pckd; pckd = fck_hw_max / pck; @@ -694,7 +694,7 @@ static int dss_setup_default_clock(void) { unsigned long max_dss_fck, prate; unsigned long fck; - unsigned fck_div; + unsigned int fck_div; int r; max_dss_fck = dss.feat->fck_freq_max; diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 6374e57ed9da..196f6ddba598 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -167,10 +167,10 @@ struct dss_pll_ops { struct dss_pll_hw { enum dss_pll_type type; - unsigned n_max; - unsigned m_min; - unsigned m_max; - unsigned mX_max; + unsigned int n_max; + unsigned int m_min; + unsigned int m_max; + unsigned int mX_max; unsigned long fint_min, fint_max; unsigned long clkdco_min, clkdco_low, clkdco_max; @@ -390,7 +390,7 @@ int dispc_wb_setup(const struct omap_dss_writeback_info *wi, bool mem_to_mem, const struct videomode *vm); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr) +static inline void dss_collect_irq_stats(u32 irqstatus, unsigned int *irq_arr) { int b; for (b = 0; b < 32; ++b) { @@ -410,7 +410,7 @@ int dss_pll_register(struct dss_pll *pll); void dss_pll_unregister(struct dss_pll *pll); struct dss_pll *dss_pll_find(const char *name); struct dss_pll *dss_pll_find_by_src(enum dss_clk_source src); -unsigned dss_pll_get_clkout_idx_for_src(enum dss_clk_source src); +unsigned int dss_pll_get_clkout_idx_for_src(enum dss_clk_source src); int dss_pll_enable(struct dss_pll *pll); void dss_pll_disable(struct dss_pll *pll); int dss_pll_set_config(struct dss_pll *pll, diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index bf914f2ac99e..ae6401c569c4 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -180,7 +180,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) enum omap_channel channel = dssdev->dispc_channel; struct hdmi_wp_data *wp = &hdmi.wp; struct dss_pll_clock_info hdmi_cinfo = { 0 }; - unsigned pc; + unsigned int pc; r = hdmi_power_on_core(dssdev); if (r) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 689cda41858b..9571be938d81 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -175,7 +175,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) struct videomode *vm; enum omap_channel channel = dssdev->dispc_channel; struct dss_pll_clock_info hdmi_cinfo = { 0 }; - unsigned pc; + unsigned int pc; r = hdmi_power_on_core(dssdev); if (r) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c index 09759f8ea7bc..2282e48574c6 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c @@ -50,14 +50,14 @@ static void hdmi_core_ddc_init(struct hdmi_core_data *core) { void __iomem *base = core->base; const unsigned long long iclk = 266000000; /* DSS L3 ICLK */ - const unsigned ss_scl_high = 4600; /* ns */ - const unsigned ss_scl_low = 5400; /* ns */ - const unsigned fs_scl_high = 600; /* ns */ - const unsigned fs_scl_low = 1300; /* ns */ - const unsigned sda_hold = 1000; /* ns */ - const unsigned sfr_div = 10; + const unsigned int ss_scl_high = 4600; /* ns */ + const unsigned int ss_scl_low = 5400; /* ns */ + const unsigned int fs_scl_high = 600; /* ns */ + const unsigned int fs_scl_low = 1300; /* ns */ + const unsigned int sda_hold = 1000; /* ns */ + const unsigned int sfr_div = 10; unsigned long long sfr; - unsigned v; + unsigned int v; sfr = iclk / sfr_div; /* SFR_DIV */ sfr /= 1000; /* SFR clock in kHz */ @@ -430,11 +430,11 @@ static void hdmi_core_write_avi_infoframe(struct hdmi_core_data *core, void __iomem *base = core->base; u8 data[HDMI_INFOFRAME_SIZE(AVI)]; u8 *ptr; - unsigned y, a, b, s; - unsigned c, m, r; - unsigned itc, ec, q, sc; - unsigned vic; - unsigned yq, cn, pr; + unsigned int y, a, b, s; + unsigned int c, m, r; + unsigned int itc, ec, q, sc; + unsigned int vic; + unsigned int yq, cn, pr; hdmi_avi_infoframe_pack(frame, data, sizeof(data)); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c index 5c14ed851609..9915923a53bd 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c @@ -99,7 +99,7 @@ static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy) u16 lane_cfg = 0; int i; - unsigned lane_cfg_val; + unsigned int lane_cfg_val; u16 pol_val = 0; for (i = 0; i < 4; ++i) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c index 806e5fdcfe52..53bc5f78050c 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c @@ -168,7 +168,7 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp, { u32 timing_h = 0; u32 timing_v = 0; - unsigned hsync_len_offset = 1; + unsigned int hsync_len_offset = 1; DSSDBG("Enter hdmi_wp_video_config_timing\n"); diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index f8f83e826a56..ca769466c4dc 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -198,8 +198,8 @@ enum omap_dss_dsi_trans_mode { struct omap_dss_dsi_videomode_timings { unsigned long hsclk; - unsigned ndl; - unsigned bitspp; + unsigned int ndl; + unsigned int bitspp; /* pixels */ u16 hact; diff --git a/drivers/gpu/drm/omapdrm/dss/pll.c b/drivers/gpu/drm/omapdrm/dss/pll.c index 058714b1eb56..ecb03277d831 100644 --- a/drivers/gpu/drm/omapdrm/dss/pll.c +++ b/drivers/gpu/drm/omapdrm/dss/pll.c @@ -105,7 +105,7 @@ struct dss_pll *dss_pll_find_by_src(enum dss_clk_source src) } } -unsigned dss_pll_get_clkout_idx_for_src(enum dss_clk_source src) +unsigned int dss_pll_get_clkout_idx_for_src(enum dss_clk_source src) { switch (src) { case DSS_CLK_SRC_HDMI_PLL: @@ -277,7 +277,7 @@ bool dss_pll_calc_b(const struct dss_pll *pll, unsigned long clkin, unsigned long fint, clkdco, clkout; unsigned long target_clkdco; unsigned long min_dco; - unsigned n, m, mf, m2, sd; + unsigned int n, m, mf, m2, sd; const struct dss_pll_hw *hw = pll->hw; DSSDBG("clkin %lu, target clkout %lu\n", clkin, target_clkout); -- cgit v1.2.3 From 8cd175778b17bb76b535d13b6e9a1720b35bc474 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:35 +0200 Subject: drm: omapdrm: connector-analog-tv: Remove tvc_of_match forward declaration The tvc_of_match variable is never referenced before its definition. Remove the forward declaration. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c index 95ea6abae914..d3a79d508855 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c @@ -40,8 +40,6 @@ static const struct videomode tvc_pal_vm = { DISPLAY_FLAGS_VSYNC_LOW, }; -static const struct of_device_id tvc_of_match[]; - #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) static int tvc_connect(struct omap_dss_device *dssdev) -- cgit v1.2.3 From ae9f7a57964ecac3314947b26dbf8da20bafe5b3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:36 +0200 Subject: drm: omapdrm: displays: Remove OF node check in connector drivers No connector is instantiated through platform data anymore, there is no need to check for OF node presence. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c | 3 --- drivers/gpu/drm/omapdrm/displays/connector-dvi.c | 3 --- drivers/gpu/drm/omapdrm/displays/connector-hdmi.c | 3 --- 3 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c index d3a79d508855..e6b87adea933 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c @@ -196,9 +196,6 @@ static int tvc_probe(struct platform_device *pdev) struct omap_dss_device *dssdev; int r; - if (!pdev->dev.of_node) - return -ENODEV; - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); if (!ddata) return -ENOMEM; diff --git a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c index 10b4b97d3595..6716aef41c7e 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c @@ -275,9 +275,6 @@ static int dvic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (!pdev->dev.of_node) - return -ENODEV; - r = dvic_probe_of(pdev); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c index 2867476419dc..c152c5dfb4a0 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c @@ -336,9 +336,6 @@ static int hdmic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); ddata->dev = &pdev->dev; - if (!pdev->dev.of_node) - return -ENODEV; - r = hdmic_probe_of(pdev); if (r) return r; -- cgit v1.2.3 From 1a5d98a7de05fe6181aae60ce82591d711f08bc2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:37 +0200 Subject: drm: omapdrm: displays: Remove OF node check in encoder drivers No encoder is instantiated through platform data anymore, there is no need to check for OF node presence. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/displays/encoder-opa362.c | 5 ----- drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c | 3 --- drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c | 3 --- 3 files changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c index d523c67a3ae3..b424db11c6d5 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c @@ -179,11 +179,6 @@ static int opa362_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "probe\n"); - if (node == NULL) { - dev_err(&pdev->dev, "Unable to find device tree\n"); - return -EINVAL; - } - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); if (!ddata) return -ENOMEM; diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c index e01ab3db6d86..e0bc625a5f3a 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c @@ -201,9 +201,6 @@ static int tfp410_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (!pdev->dev.of_node) - return -ENODEV; - r = tfp410_probe_of(pdev); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c index 1fd493e5fa3d..fb8f9ce7e5c2 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c @@ -299,9 +299,6 @@ static int tpd_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (!pdev->dev.of_node) - return -ENODEV; - r = tpd_probe_of(pdev); if (r) return r; -- cgit v1.2.3 From 6b06df832f82946825aa1d81e1e64041d33570f0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:38 +0200 Subject: drm: omapdrm: displays: Remove OF node check in panel drivers No panel is instantiated through platform data anymore, there is no need to check for OF node presence. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/displays/panel-dpi.c | 3 --- drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 3 --- drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c | 3 --- drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c | 3 --- drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c | 3 --- drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c | 3 --- drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c | 3 --- drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c | 3 --- 8 files changed, 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c index 48a03f55610a..bae8fd5357ea 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c @@ -212,9 +212,6 @@ static int panel_dpi_probe(struct platform_device *pdev) struct omap_dss_device *dssdev; int r; - if (!pdev->dev.of_node) - return -ENODEV; - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); if (ddata == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index fb83f757b113..002082ecbbbc 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -1317,9 +1317,6 @@ static int dsicm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); ddata->pdev = pdev; - if (!pdev->dev.of_node) - return -ENODEV; - ddata->vm.hactive = 864; ddata->vm.vactive = 480; ddata->vm.pixelclock = 864 * 480 * 60; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c index 57af22ce87c5..8cb958c0c39d 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c @@ -268,9 +268,6 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi) ddata->spi = spi; - if (!spi->dev.of_node) - return -ENODEV; - r = lb035q02_probe_of(spi); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c index bf53676263ad..3ab4b249e74b 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c @@ -277,9 +277,6 @@ static int nec_8048_probe(struct spi_device *spi) ddata->spi = spi; - if (!spi->dev.of_node) - return -ENODEV; - r = nec_8048_probe_of(spi); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c index 34555801fa4c..124867e35e4b 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c @@ -268,9 +268,6 @@ static int sharp_ls_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - if (!pdev->dev.of_node) - return -ENODEV; - r = sharp_ls_probe_of(pdev); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c index 06d7d8362a73..cc5e9a68726a 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c @@ -720,9 +720,6 @@ static int acx565akm_probe(struct spi_device *spi) dev_dbg(&spi->dev, "%s\n", __func__); - if (!spi->dev.of_node) - return -ENODEV; - spi->mode = SPI_MODE_3; ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c index 2721a86ac5e7..3f6c90db35c4 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c @@ -404,9 +404,6 @@ static int td028ttec1_panel_probe(struct spi_device *spi) ddata->spi_dev = spi; - if (!spi->dev.of_node) - return -ENODEV; - r = td028ttec1_probe_of(spi); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c index ac4a6d4d134c..06fb5a995002 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c @@ -509,9 +509,6 @@ static int tpo_td043_probe(struct spi_device *spi) ddata->spi = spi; - if (!spi->dev.of_node) - return -ENODEV; - r = tpo_td043_probe_of(spi); if (r) return r; -- cgit v1.2.3 From b47e6dcb58becb3e5b0b4f3e05ff3626d5b77437 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:39 +0200 Subject: drm: omapdrm: displays: Get connector source at connect time The connector drivers need a handle to the source they are connected to in order to control the source. All drivers get that handle at probe time, resulting in probe deferral when the source hasn't been probed yet. However they don't need the handle until their connect handler is called. Move retrieval of the source handle to the connect handler to avoid probe deferrals. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- .../gpu/drm/omapdrm/displays/connector-analog-tv.c | 45 ++++++++-------------- drivers/gpu/drm/omapdrm/displays/connector-dvi.c | 31 +++++++-------- drivers/gpu/drm/omapdrm/displays/connector-hdmi.c | 37 ++++++++---------- 3 files changed, 46 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c index e6b87adea933..9eabd7201a12 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c @@ -45,7 +45,7 @@ static const struct videomode tvc_pal_vm = { static int tvc_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; dev_dbg(ddata->dev, "connect\n"); @@ -53,10 +53,19 @@ static int tvc_connect(struct omap_dss_device *dssdev) if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(ddata->dev->of_node); + if (IS_ERR(in)) { + dev_err(ddata->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.atv->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -71,6 +80,9 @@ static void tvc_disconnect(struct omap_dss_device *dssdev) return; in->ops.atv->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int tvc_enable(struct omap_dss_device *dssdev) @@ -173,23 +185,6 @@ static struct omap_dss_driver tvc_driver = { .set_wss = tvc_set_wss, }; -static int tvc_probe_of(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; - - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - - return 0; -} - static int tvc_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -203,10 +198,6 @@ static int tvc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); ddata->dev = &pdev->dev; - r = tvc_probe_of(pdev); - if (r) - return r; - ddata->vm = tvc_pal_vm; dssdev = &ddata->dssdev; @@ -219,28 +210,22 @@ static int tvc_probe(struct platform_device *pdev) r = omapdss_register_display(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int __exit tvc_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_display(&ddata->dssdev); tvc_disable(dssdev); tvc_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c index 6716aef41c7e..391d80364346 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c @@ -51,16 +51,25 @@ struct panel_drv_data { static int dvic_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dvi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -73,6 +82,9 @@ static void dvic_disconnect(struct omap_dss_device *dssdev) return; in->ops.dvi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int dvic_enable(struct omap_dss_device *dssdev) @@ -235,25 +247,15 @@ static int dvic_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; struct device_node *adapter_node; struct i2c_adapter *adapter; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0); if (adapter_node) { adapter = of_get_i2c_adapter_by_node(adapter_node); of_node_put(adapter_node); if (adapter == NULL) { dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n"); - omap_dss_put_device(ddata->in); return -EPROBE_DEFER; } @@ -297,8 +299,6 @@ static int dvic_probe(struct platform_device *pdev) return 0; err_reg: - omap_dss_put_device(ddata->in); - i2c_put_adapter(ddata->i2c_adapter); return r; @@ -308,15 +308,12 @@ static int __exit dvic_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_display(&ddata->dssdev); dvic_disable(dssdev); dvic_disconnect(dssdev); - omap_dss_put_device(in); - i2c_put_adapter(ddata->i2c_adapter); return 0; diff --git a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c index c152c5dfb4a0..ca30ed9da7eb 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c @@ -55,7 +55,7 @@ struct panel_drv_data { static int hdmic_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; dev_dbg(ddata->dev, "connect\n"); @@ -63,10 +63,19 @@ static int hdmic_connect(struct omap_dss_device *dssdev) if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(ddata->dev->of_node); + if (IS_ERR(in)) { + dev_err(ddata->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.hdmi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -81,6 +90,9 @@ static void hdmic_disconnect(struct omap_dss_device *dssdev) return; in->ops.hdmi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int hdmic_enable(struct omap_dss_device *dssdev) @@ -302,7 +314,6 @@ static int hdmic_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; int gpio; /* HPD GPIO */ @@ -312,14 +323,6 @@ static int hdmic_probe_of(struct platform_device *pdev) else ddata->hpd_gpio = -ENODEV; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -346,7 +349,7 @@ static int hdmic_probe(struct platform_device *pdev) r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio, GPIOF_DIR_IN, "hdmi_hpd"); if (r) - goto err_reg; + return r; r = devm_request_threaded_irq(&pdev->dev, gpio_to_irq(ddata->hpd_gpio), @@ -355,7 +358,7 @@ static int hdmic_probe(struct platform_device *pdev) IRQF_ONESHOT, "hdmic hpd", ddata); if (r) - goto err_reg; + return r; } ddata->vm = hdmic_default_vm; @@ -370,28 +373,22 @@ static int hdmic_probe(struct platform_device *pdev) r = omapdss_register_display(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int __exit hdmic_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_display(&ddata->dssdev); hdmic_disable(dssdev); hdmic_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } -- cgit v1.2.3 From 2f8c4a8a9d4b65d296fd5ccd0c5ba7ad5cbcb931 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:40 +0200 Subject: drm: omapdrm: displays: Get panel source at connect time The connector drivers need a handle to the source they are connected to in order to control the source. All drivers get that handle at probe time, resulting in probe deferral when the source hasn't been probed yet. However they don't need the handle until their connect handler is called. Move retrieval of the source handle to the connect handler to avoid probe deferrals. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/displays/panel-dpi.c | 34 +++++++--------- drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 27 +++++++------ .../omapdrm/displays/panel-lgphilips-lb035q02.c | 35 +++++++--------- .../drm/omapdrm/displays/panel-nec-nl8048hl11.c | 39 ++++++++---------- .../drm/omapdrm/displays/panel-sharp-ls037v7dw01.c | 35 +++++++--------- .../drm/omapdrm/displays/panel-sony-acx565akm.c | 26 ++++++------ .../drm/omapdrm/displays/panel-tpo-td028ttec1.c | 46 +++++++--------------- .../drm/omapdrm/displays/panel-tpo-td043mtea1.c | 29 +++++++------- 8 files changed, 119 insertions(+), 152 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c index bae8fd5357ea..6cbf570d6727 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c @@ -38,16 +38,25 @@ struct panel_drv_data { static int panel_dpi_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -60,6 +69,9 @@ static void panel_dpi_disconnect(struct omap_dss_device *dssdev) return; in->ops.dpi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int panel_dpi_enable(struct omap_dss_device *dssdev) @@ -157,7 +169,6 @@ static int panel_dpi_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; int r; struct display_timing timing; struct gpio_desc *gpio; @@ -195,14 +206,6 @@ static int panel_dpi_probe_of(struct platform_device *pdev) videomode_from_timing(&timing, &ddata->vm); - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -232,29 +235,22 @@ static int panel_dpi_probe(struct platform_device *pdev) r = omapdss_register_display(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; - -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int __exit panel_dpi_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_display(dssdev); panel_dpi_disable(dssdev); panel_dpi_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index 002082ecbbbc..f960e55d64ea 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -759,17 +759,23 @@ static int dsicm_panel_reset(struct panel_drv_data *ddata) static int dsicm_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; struct device *dev = &ddata->pdev->dev; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dsi->connect(in, dssdev); if (r) { dev_err(dev, "Failed to connect to video source\n"); - return r; + goto err_connect; } r = in->ops.dsi->request_vc(ddata->in, &ddata->channel); @@ -784,12 +790,15 @@ static int dsicm_connect(struct omap_dss_device *dssdev) goto err_vc_id; } + ddata->in = in; return 0; err_vc_id: in->ops.dsi->release_vc(ddata->in, ddata->channel); err_req_vc: in->ops.dsi->disconnect(in, dssdev); +err_connect: + omap_dss_put_device(in); return r; } @@ -803,6 +812,9 @@ static void dsicm_disconnect(struct omap_dss_device *dssdev) in->ops.dsi->release_vc(in, ddata->channel); in->ops.dsi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int dsicm_enable(struct omap_dss_device *dssdev) @@ -1223,7 +1235,6 @@ static int dsicm_probe_of(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct device_node *backlight; struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct omap_dss_device *in; struct display_timing timing; int err; @@ -1259,12 +1270,6 @@ static int dsicm_probe_of(struct platform_device *pdev) ddata->height_mm = 0; of_property_read_u32(node, "height-mm", &ddata->height_mm); - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - ddata->vpnl = devm_regulator_get_optional(&pdev->dev, "vpnl"); if (IS_ERR(ddata->vpnl)) { err = PTR_ERR(ddata->vpnl); @@ -1281,8 +1286,6 @@ static int dsicm_probe_of(struct platform_device *pdev) ddata->vddi = NULL; } - ddata->in = in; - backlight = of_parse_phandle(node, "backlight", 0); if (backlight) { ddata->extbldev = of_find_backlight_by_node(backlight); @@ -1421,8 +1424,6 @@ static int __exit dsicm_remove(struct platform_device *pdev) if (ddata->extbldev) put_device(&ddata->extbldev->dev); - omap_dss_put_device(ddata->in); - dsicm_cancel_ulps_work(ddata); destroy_workqueue(ddata->workqueue); diff --git a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c index 8cb958c0c39d..754197099440 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c @@ -119,18 +119,27 @@ static void init_lb035q02_panel(struct spi_device *spi) static int lb035q02_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } init_lb035q02_panel(ddata->spi); + ddata->in = in; return 0; } @@ -143,6 +152,9 @@ static void lb035q02_disconnect(struct omap_dss_device *dssdev) return; in->ops.dpi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int lb035q02_enable(struct omap_dss_device *dssdev) @@ -230,9 +242,7 @@ static struct omap_dss_driver lb035q02_ops = { static int lb035q02_probe_of(struct spi_device *spi) { - struct device_node *node = spi->dev.of_node; struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *in; struct gpio_desc *gpio; gpio = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW); @@ -243,14 +253,6 @@ static int lb035q02_probe_of(struct spi_device *spi) ddata->enable_gpio = gpio; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&spi->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -284,29 +286,22 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi) r = omapdss_register_display(dssdev); if (r) { dev_err(&spi->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; - -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int lb035q02_panel_spi_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_display(dssdev); lb035q02_disable(dssdev); lb035q02_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c index 3ab4b249e74b..9a3b27fa5cb5 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c @@ -115,16 +115,25 @@ static int init_nec_8048_wvga_lcd(struct spi_device *spi) static int nec_8048_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -137,6 +146,9 @@ static void nec_8048_disconnect(struct omap_dss_device *dssdev) return; in->ops.dpi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int nec_8048_enable(struct omap_dss_device *dssdev) @@ -226,7 +238,6 @@ static int nec_8048_probe_of(struct spi_device *spi) { struct device_node *node = spi->dev.of_node; struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *in; int gpio; gpio = of_get_named_gpio(node, "reset-gpios", 0); @@ -239,14 +250,6 @@ static int nec_8048_probe_of(struct spi_device *spi) /* XXX the panel spec doesn't mention any QVGA pin?? */ ddata->qvga_gpio = -ENOENT; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&spi->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -285,14 +288,14 @@ static int nec_8048_probe(struct spi_device *spi) r = devm_gpio_request_one(&spi->dev, ddata->qvga_gpio, GPIOF_OUT_INIT_HIGH, "lcd QVGA"); if (r) - goto err_gpio; + return r; } if (gpio_is_valid(ddata->res_gpio)) { r = devm_gpio_request_one(&spi->dev, ddata->res_gpio, GPIOF_OUT_INIT_LOW, "lcd RES"); if (r) - goto err_gpio; + return r; } ddata->vm = nec_8048_panel_vm; @@ -307,22 +310,16 @@ static int nec_8048_probe(struct spi_device *spi) r = omapdss_register_display(dssdev); if (r) { dev_err(&spi->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; - -err_reg: -err_gpio: - omap_dss_put_device(ddata->in); - return r; } static int nec_8048_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; dev_dbg(&ddata->spi->dev, "%s\n", __func__); @@ -331,8 +328,6 @@ static int nec_8048_remove(struct spi_device *spi) nec_8048_disable(dssdev); nec_8048_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c index 124867e35e4b..bb5b680cabfe 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c @@ -61,16 +61,25 @@ static const struct videomode sharp_ls_vm = { static int sharp_ls_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -83,6 +92,9 @@ static void sharp_ls_disconnect(struct omap_dss_device *dssdev) return; in->ops.dpi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int sharp_ls_enable(struct omap_dss_device *dssdev) @@ -210,8 +222,6 @@ static int sharp_ls_get_gpio_of(struct device *dev, int index, int val, static int sharp_ls_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; int r; ddata->vcc = devm_regulator_get(&pdev->dev, "envdd"); @@ -245,14 +255,6 @@ static int sharp_ls_probe_of(struct platform_device *pdev) if (r) return r; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -284,29 +286,22 @@ static int sharp_ls_probe(struct platform_device *pdev) r = omapdss_register_display(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; - -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int __exit sharp_ls_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_display(dssdev); sharp_ls_disable(dssdev); sharp_ls_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c index cc5e9a68726a..c4bb33a247d0 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c @@ -510,16 +510,25 @@ static const struct attribute_group bldev_attr_group = { static int acx565akm_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.sdi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -532,6 +541,9 @@ static void acx565akm_disconnect(struct omap_dss_device *dssdev) return; in->ops.sdi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int acx565akm_panel_power_on(struct omap_dss_device *dssdev) @@ -700,12 +712,6 @@ static int acx565akm_probe_of(struct spi_device *spi) ddata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); - ddata->in = omapdss_of_find_source_for_first_ep(np); - if (IS_ERR(ddata->in)) { - dev_err(&spi->dev, "failed to find video source\n"); - return PTR_ERR(ddata->in); - } - return 0; } @@ -823,7 +829,6 @@ err_sysfs: err_reg_bl: err_detect: err_gpio: - omap_dss_put_device(ddata->in); return r; } @@ -831,7 +836,6 @@ static int acx565akm_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; dev_dbg(&ddata->spi->dev, "%s\n", __func__); @@ -843,8 +847,6 @@ static int acx565akm_remove(struct spi_device *spi) acx565akm_disable(dssdev); acx565akm_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c index 3f6c90db35c4..b5d8a00df811 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c @@ -169,16 +169,25 @@ enum jbt_register { static int td028ttec1_panel_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -191,6 +200,9 @@ static void td028ttec1_panel_disconnect(struct omap_dss_device *dssdev) return; in->ops.dpi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int td028ttec1_panel_enable(struct omap_dss_device *dssdev) @@ -362,23 +374,6 @@ static struct omap_dss_driver td028ttec1_ops = { .check_timings = td028ttec1_panel_check_timings, }; -static int td028ttec1_probe_of(struct spi_device *spi) -{ - struct device_node *node = spi->dev.of_node; - struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *in; - - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&spi->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - - return 0; -} - static int td028ttec1_panel_probe(struct spi_device *spi) { struct panel_drv_data *ddata; @@ -404,10 +399,6 @@ static int td028ttec1_panel_probe(struct spi_device *spi) ddata->spi_dev = spi; - r = td028ttec1_probe_of(spi); - if (r) - return r; - ddata->vm = td028ttec1_panel_vm; dssdev = &ddata->dssdev; @@ -420,21 +411,16 @@ static int td028ttec1_panel_probe(struct spi_device *spi) r = omapdss_register_display(dssdev); if (r) { dev_err(&spi->dev, "Failed to register panel\n"); - goto err_reg; + return r; } return 0; - -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int td028ttec1_panel_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; dev_dbg(&ddata->spi_dev->dev, "%s\n", __func__); @@ -443,8 +429,6 @@ static int td028ttec1_panel_remove(struct spi_device *spi) td028ttec1_panel_disable(dssdev); td028ttec1_panel_disconnect(dssdev); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c index 06fb5a995002..c08e22b43447 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c @@ -340,16 +340,25 @@ static void tpo_td043_power_off(struct panel_drv_data *ddata) static int tpo_td043_connect(struct omap_dss_device *dssdev) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return 0; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } + ddata->in = in; return 0; } @@ -362,6 +371,9 @@ static void tpo_td043_disconnect(struct omap_dss_device *dssdev) return; in->ops.dpi->disconnect(in, dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int tpo_td043_enable(struct omap_dss_device *dssdev) @@ -463,7 +475,6 @@ static int tpo_td043_probe_of(struct spi_device *spi) { struct device_node *node = spi->dev.of_node; struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *in; int gpio; gpio = of_get_named_gpio(node, "reset-gpios", 0); @@ -473,14 +484,6 @@ static int tpo_td043_probe_of(struct spi_device *spi) } ddata->nreset_gpio = gpio; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&spi->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -561,7 +564,6 @@ err_reg: err_sysfs: err_gpio_req: err_regulator: - omap_dss_put_device(ddata->in); return r; } @@ -569,7 +571,6 @@ static int tpo_td043_remove(struct spi_device *spi) { struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; dev_dbg(&ddata->spi->dev, "%s\n", __func__); @@ -578,8 +579,6 @@ static int tpo_td043_remove(struct spi_device *spi) tpo_td043_disable(dssdev); tpo_td043_disconnect(dssdev); - omap_dss_put_device(in); - sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group); return 0; -- cgit v1.2.3 From e28cea0feeda57ce49a8ca84db883814544460d2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:41 +0200 Subject: drm: omapdrm: displays: Get encoder source at connect time The encoder drivers need a handle to the source they are connected to in order to control the source. All drivers get that handle at probe time, resulting in probe deferral when the source hasn't been probed yet. However they don't need the handle until their connect handler is called. Move retrieval of the source handle to the connect handler to avoid probe deferrals. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/displays/encoder-opa362.c | 35 ++++++------ drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c | 36 ++++++------ .../gpu/drm/omapdrm/displays/encoder-tpd12s015.c | 66 ++++++++-------------- 3 files changed, 54 insertions(+), 83 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c index b424db11c6d5..afee1b8b457a 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c @@ -36,7 +36,7 @@ static int opa362_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; dev_dbg(dssdev->dev, "connect\n"); @@ -44,13 +44,22 @@ static int opa362_connect(struct omap_dss_device *dssdev, if (omapdss_device_is_connected(dssdev)) return -EBUSY; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.atv->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } dst->src = dssdev; dssdev->dst = dst; + ddata->in = in; return 0; } @@ -74,6 +83,9 @@ static void opa362_disconnect(struct omap_dss_device *dssdev, dssdev->dst = NULL; in->ops.atv->disconnect(in, &ddata->dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int opa362_enable(struct omap_dss_device *dssdev) @@ -171,9 +183,8 @@ static const struct omapdss_atv_ops opa362_atv_ops = { static int opa362_probe(struct platform_device *pdev) { - struct device_node *node = pdev->dev.of_node; struct panel_drv_data *ddata; - struct omap_dss_device *dssdev, *in; + struct omap_dss_device *dssdev; struct gpio_desc *gpio; int r; @@ -191,14 +202,6 @@ static int opa362_probe(struct platform_device *pdev) ddata->enable_gpio = gpio; - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - dssdev = &ddata->dssdev; dssdev->ops.atv = &opa362_atv_ops; dssdev->dev = &pdev->dev; @@ -209,20 +212,16 @@ static int opa362_probe(struct platform_device *pdev) r = omapdss_register_output(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register output\n"); - goto err_reg; + return r; } return 0; -err_reg: - omap_dss_put_device(ddata->in); - return r; } static int __exit opa362_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_output(&ddata->dssdev); @@ -234,8 +233,6 @@ static int __exit opa362_remove(struct platform_device *pdev) if (omapdss_device_is_connected(dssdev)) opa362_disconnect(dssdev, dssdev->dst); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c index e0bc625a5f3a..ed7ae384c3ed 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c @@ -32,19 +32,28 @@ static int tfp410_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; if (omapdss_device_is_connected(dssdev)) return -EBUSY; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.dpi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } dst->src = dssdev; dssdev->dst = dst; + ddata->in = in; return 0; } @@ -66,6 +75,9 @@ static void tfp410_disconnect(struct omap_dss_device *dssdev, dssdev->dst = NULL; in->ops.dpi->disconnect(in, &ddata->dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int tfp410_enable(struct omap_dss_device *dssdev) @@ -165,7 +177,6 @@ static int tfp410_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; int gpio; gpio = of_get_named_gpio(node, "powerdown-gpios", 0); @@ -178,14 +189,6 @@ static int tfp410_probe_of(struct platform_device *pdev) return gpio; } - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - return 0; } @@ -211,7 +214,7 @@ static int tfp410_probe(struct platform_device *pdev) if (r) { dev_err(&pdev->dev, "Failed to request PD GPIO %d\n", ddata->pd_gpio); - goto err_gpio; + return r; } } @@ -226,21 +229,16 @@ static int tfp410_probe(struct platform_device *pdev) r = omapdss_register_output(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register output\n"); - goto err_reg; + return r; } return 0; -err_reg: -err_gpio: - omap_dss_put_device(ddata->in); - return r; } static int __exit tfp410_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_output(&ddata->dssdev); @@ -252,8 +250,6 @@ static int __exit tfp410_remove(struct platform_device *pdev) if (omapdss_device_is_connected(dssdev)) tfp410_disconnect(dssdev, dssdev->dst); - omap_dss_put_device(in); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c index fb8f9ce7e5c2..d275bf152da5 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c @@ -40,12 +40,20 @@ static int tpd_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct panel_drv_data *ddata = to_panel_data(dssdev); - struct omap_dss_device *in = ddata->in; + struct omap_dss_device *in; int r; + in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node); + if (IS_ERR(in)) { + dev_err(dssdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + r = in->ops.hdmi->connect(in, dssdev); - if (r) + if (r) { + omap_dss_put_device(in); return r; + } dst->src = dssdev; dssdev->dst = dst; @@ -56,6 +64,7 @@ static int tpd_connect(struct omap_dss_device *dssdev, /* DC-DC converter needs at max 300us to get to 90% of 5V */ udelay(300); + ddata->in = in; return 0; } @@ -77,6 +86,9 @@ static void tpd_disconnect(struct omap_dss_device *dssdev, dssdev->dst = NULL; in->ops.hdmi->disconnect(in, &ddata->dssdev); + + omap_dss_put_device(in); + ddata->in = NULL; } static int tpd_enable(struct omap_dss_device *dssdev) @@ -269,23 +281,6 @@ static irqreturn_t tpd_hpd_isr(int irq, void *data) return IRQ_HANDLED; } -static int tpd_probe_of(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct device_node *node = pdev->dev.of_node; - struct omap_dss_device *in; - - in = omapdss_of_find_source_for_first_ep(node); - if (IS_ERR(in)) { - dev_err(&pdev->dev, "failed to find video source\n"); - return PTR_ERR(in); - } - - ddata->in = in; - - return 0; -} - static int tpd_probe(struct platform_device *pdev) { struct omap_dss_device *in, *dssdev; @@ -299,34 +294,24 @@ static int tpd_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - r = tpd_probe_of(pdev); - if (r) - return r; - gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0, GPIOD_OUT_LOW); - if (IS_ERR(gpio)) { - r = PTR_ERR(gpio); - goto err_gpio; - } + if (IS_ERR(gpio)) + return PTR_ERR(gpio); ddata->ct_cp_hpd_gpio = gpio; gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1, GPIOD_OUT_LOW); - if (IS_ERR(gpio)) { - r = PTR_ERR(gpio); - goto err_gpio; - } + if (IS_ERR(gpio)) + return PTR_ERR(gpio); ddata->ls_oe_gpio = gpio; gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2, GPIOD_IN); - if (IS_ERR(gpio)) { - r = PTR_ERR(gpio); - goto err_gpio; - } + if (IS_ERR(gpio)) + return PTR_ERR(gpio); ddata->hpd_gpio = gpio; @@ -337,7 +322,7 @@ static int tpd_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "tpd12s015 hpd", ddata); if (r) - goto err_gpio; + return r; dssdev = &ddata->dssdev; dssdev->ops.hdmi = &tpd_hdmi_ops; @@ -352,21 +337,16 @@ static int tpd_probe(struct platform_device *pdev) r = omapdss_register_output(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register output\n"); - goto err_reg; + return r; } return 0; -err_reg: -err_gpio: - omap_dss_put_device(ddata->in); - return r; } static int __exit tpd_remove(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct omap_dss_device *dssdev = &ddata->dssdev; - struct omap_dss_device *in = ddata->in; omapdss_unregister_output(&ddata->dssdev); @@ -378,8 +358,6 @@ static int __exit tpd_remove(struct platform_device *pdev) if (omapdss_device_is_connected(dssdev)) tpd_disconnect(dssdev, dssdev->dst); - omap_dss_put_device(in); - return 0; } -- cgit v1.2.3 From 8a9a5ac919ae8af9803b41f1693fa1ae636b261b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:42 +0200 Subject: drm: omapdrm: dss: Make omapdss_default_get_timings static The function isn't used outside of its compilation unit, make it static. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/display.c | 5 ++--- drivers/gpu/drm/omapdrm/dss/omapdss.h | 3 --- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index 0c9480ba85c0..424143128cd4 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -28,12 +28,11 @@ #include "omapdss.h" -void omapdss_default_get_timings(struct omap_dss_device *dssdev, - struct videomode *vm) +static void omapdss_default_get_timings(struct omap_dss_device *dssdev, + struct videomode *vm) { *vm = dssdev->panel.vm; } -EXPORT_SYMBOL(omapdss_default_get_timings); static LIST_HEAD(panel_list); static DEFINE_MUTEX(panel_list_mutex); diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index ca769466c4dc..4222661d4c88 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -609,9 +609,6 @@ int omapdss_output_unset_device(struct omap_dss_device *out); struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev); -void omapdss_default_get_timings(struct omap_dss_device *dssdev, - struct videomode *vm); - typedef void (*omap_dispc_isr_t) (void *arg, u32 mask); int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask); int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask); -- cgit v1.2.3 From 00b8cb88e1c2f4df71d0ddcdaf9589c38c5659b3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:43 +0200 Subject: drm: omapdrm: dss: Don't export functions internal to omapdss-base A few functions defined in omapdss-base are internal to the module. Don't export them. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dss-of.c | 2 -- drivers/gpu/drm/omapdrm/dss/output.c | 1 - 2 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dss-of.c b/drivers/gpu/drm/omapdrm/dss/dss-of.c index 967d9e1b34e5..4602a79c6c44 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss-of.c +++ b/drivers/gpu/drm/omapdrm/dss/dss-of.c @@ -44,7 +44,6 @@ struct device_node *dss_of_port_get_parent_device(struct device_node *port) return NULL; } -EXPORT_SYMBOL_GPL(dss_of_port_get_parent_device); u32 dss_of_port_get_port_number(struct device_node *port) { @@ -57,7 +56,6 @@ u32 dss_of_port_get_port_number(struct device_node *port) return reg; } -EXPORT_SYMBOL_GPL(dss_of_port_get_port_number); struct omap_dss_device * omapdss_of_find_source_for_first_ep(struct device_node *node) diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index b9afd80ae385..a28e00c94c05 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -156,7 +156,6 @@ struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *po return NULL; } -EXPORT_SYMBOL(omap_dss_find_output_by_port_node); struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev) { -- cgit v1.2.3 From 215003b4ae1d47035092fef73b6a22aa82037091 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:44 +0200 Subject: drm: omapdrm: dss: Move initialization code from component bind to probe There's no reason to delay initialization of most of the driver (such as mapping memory I/O, getting clocks or enabling runtime PM) to the component master bind handler. This additionally fixes a real PM issue caused enabling runtime PM in the bind handler. The bind handler performs the following sequence of PM operations: pm_runtime_enable(dev); pm_runtime_get_sync(dev); ... (access the hardware to read the device revision) ... pm_runtime_put_sync(dev); If a failure occurs at this point, the error path calls pm_runtime_disable() to balance the pm_runtime_enable() call. To understand the problem, it should be noted that the bind handler is called when one of the component registers itself, which happens in the component's probe handler. Furthermore, as the components are children of the DSS, the device core calls pm_runtime_get_sync() on the DSS platform device before calling the component's probe handler. This increases the DSS power usage count but doesn't runtime resume the device, as runtime PM is disabled at that point. The bind handler is thus called with runtime PM disabled, with the device runtime suspended, but with the power usage count larger than 0. The pm_runtime_get_sync() call will thus further increase the power usage count and runtime resume the device. The pm_runtime_put_sync() handler will decrease the power usage count to a non-zero value and will thus not suspend the device. Finally, the pm_runtime_disable() call will disable runtime PM, preventing the pm_runtime_put() call in the device core from runtime suspending the device. The DSS device is thus left powered on. To fix this, move the initialization code from the bind handler to the probe handler. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dss.c | 193 ++++++++++++++++++++------------------ 1 file changed, 104 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index f1c7ef3a2ec3..d086189263ef 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1300,88 +1300,18 @@ static const struct soc_device_attribute dss_soc_devices[] = { static int dss_bind(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct resource *dss_mem; - u32 rev; int r; - dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); - dss.base = devm_ioremap_resource(&pdev->dev, dss_mem); - if (IS_ERR(dss.base)) - return PTR_ERR(dss.base); - - r = dss_get_clocks(); + r = component_bind_all(dev, NULL); if (r) return r; - r = dss_setup_default_clock(); - if (r) - goto err_setup_clocks; - - r = dss_video_pll_probe(pdev); - if (r) - goto err_pll_init; - - r = dss_init_ports(pdev); - if (r) - goto err_init_ports; - - pm_runtime_enable(&pdev->dev); - - r = dss_runtime_get(); - if (r) - goto err_runtime_get; - - dss.dss_clk_rate = clk_get_rate(dss.dss_clk); - - /* Select DPLL */ - REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); - - dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); - -#ifdef CONFIG_OMAP2_DSS_VENC - REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ - REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ - REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ -#endif - dss.dsi_clk_source[0] = DSS_CLK_SRC_FCK; - dss.dsi_clk_source[1] = DSS_CLK_SRC_FCK; - dss.dispc_clk_source = DSS_CLK_SRC_FCK; - dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; - dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK; - - rev = dss_read_reg(DSS_REVISION); - pr_info("OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - - dss_runtime_put(); - - r = component_bind_all(&pdev->dev, NULL); - if (r) - goto err_component; - - dss_debugfs_create_file("dss", dss_dump_regs); - pm_set_vt_switch(0); omapdss_gather_components(dev); omapdss_set_is_initialized(true); return 0; - -err_component: -err_runtime_get: - pm_runtime_disable(&pdev->dev); - dss_uninit_ports(pdev); -err_init_ports: - if (dss.video1_pll) - dss_video_pll_uninit(dss.video1_pll); - - if (dss.video2_pll) - dss_video_pll_uninit(dss.video2_pll); -err_pll_init: -err_setup_clocks: - dss_put_clocks(); - return r; } static void dss_unbind(struct device *dev) @@ -1391,18 +1321,6 @@ static void dss_unbind(struct device *dev) omapdss_set_is_initialized(false); component_unbind_all(&pdev->dev, NULL); - - if (dss.video1_pll) - dss_video_pll_uninit(dss.video1_pll); - - if (dss.video2_pll) - dss_video_pll_uninit(dss.video2_pll); - - dss_uninit_ports(pdev); - - pm_runtime_disable(&pdev->dev); - - dss_put_clocks(); } static const struct component_master_ops dss_component_ops = { @@ -1434,10 +1352,46 @@ static int dss_add_child_component(struct device *dev, void *data) return 0; } +static int dss_probe_hardware(void) +{ + u32 rev; + int r; + + r = dss_runtime_get(); + if (r) + return r; + + dss.dss_clk_rate = clk_get_rate(dss.dss_clk); + + /* Select DPLL */ + REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); + + dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); + +#ifdef CONFIG_OMAP2_DSS_VENC + REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ + REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ + REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ +#endif + dss.dsi_clk_source[0] = DSS_CLK_SRC_FCK; + dss.dsi_clk_source[1] = DSS_CLK_SRC_FCK; + dss.dispc_clk_source = DSS_CLK_SRC_FCK; + dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; + dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK; + + rev = dss_read_reg(DSS_REVISION); + pr_info("OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); + + dss_runtime_put(); + + return 0; +} + static int dss_probe(struct platform_device *pdev) { const struct soc_device_attribute *soc; struct component_match *match = NULL; + struct resource *dss_mem; int r; dss.pdev = pdev; @@ -1458,20 +1412,69 @@ static int dss_probe(struct platform_device *pdev) else dss.feat = of_match_device(dss_of_match, &pdev->dev)->data; - r = dss_initialize_debugfs(); + /* Map I/O registers, get and setup clocks. */ + dss_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dss.base = devm_ioremap_resource(&pdev->dev, dss_mem); + if (IS_ERR(dss.base)) + return PTR_ERR(dss.base); + + r = dss_get_clocks(); if (r) return r; - /* add all the child devices as components */ + r = dss_setup_default_clock(); + if (r) + goto err_put_clocks; + + /* Setup the video PLLs and the DPI and SDI ports. */ + r = dss_video_pll_probe(pdev); + if (r) + goto err_put_clocks; + + r = dss_init_ports(pdev); + if (r) + goto err_uninit_plls; + + /* Enable runtime PM and probe the hardware. */ + pm_runtime_enable(&pdev->dev); + + r = dss_probe_hardware(); + if (r) + goto err_pm_runtime_disable; + + /* Initialize debugfs. */ + r = dss_initialize_debugfs(); + if (r) + goto err_pm_runtime_disable; + + dss_debugfs_create_file("dss", dss_dump_regs); + + /* Add all the child devices as components. */ device_for_each_child(&pdev->dev, &match, dss_add_child_component); r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match); - if (r) { - dss_uninitialize_debugfs(); - return r; - } + if (r) + goto err_uninit_debugfs; return 0; + +err_uninit_debugfs: + dss_uninitialize_debugfs(); + +err_pm_runtime_disable: + pm_runtime_disable(&pdev->dev); + dss_uninit_ports(pdev); + +err_uninit_plls: + if (dss.video1_pll) + dss_video_pll_uninit(dss.video1_pll); + if (dss.video2_pll) + dss_video_pll_uninit(dss.video2_pll); + +err_put_clocks: + dss_put_clocks(); + + return r; } static int dss_remove(struct platform_device *pdev) @@ -1480,6 +1483,18 @@ static int dss_remove(struct platform_device *pdev) dss_uninitialize_debugfs(); + pm_runtime_disable(&pdev->dev); + + dss_uninit_ports(pdev); + + if (dss.video1_pll) + dss_video_pll_uninit(dss.video1_pll); + + if (dss.video2_pll) + dss_video_pll_uninit(dss.video2_pll); + + dss_put_clocks(); + return 0; } -- cgit v1.2.3 From c581d16fc22d53a44017426399afb4d211d60d16 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:45 +0200 Subject: drm: omapdrm: dss: Remove dss_get_hdmi_venc_clk_source() function The function is unused, remove it. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dss.c | 14 -------------- drivers/gpu/drm/omapdrm/dss/dss.h | 1 - 2 files changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index d086189263ef..d5490336e7c7 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -752,20 +752,6 @@ void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src) REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */ } -enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) -{ - enum omap_dss_output_id outputs; - - outputs = dss.feat->outputs[OMAP_DSS_CHANNEL_DIGIT]; - if ((outputs & OMAP_DSS_OUTPUT_HDMI) == 0) - return DSS_VENC_TV_CLK; - - if ((outputs & OMAP_DSS_OUTPUT_VENC) == 0) - return DSS_HDMI_M_PCLK; - - return REG_GET(DSS_CONTROL, 15, 15); -} - static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel) { if (channel != OMAP_DSS_CHANNEL_LCD) diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 196f6ddba598..287c90608557 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -270,7 +270,6 @@ unsigned long dss_get_max_fck_rate(void); enum omap_dss_output_id dss_get_supported_outputs(enum omap_channel channel); int dss_dpi_select_source(int port, enum omap_channel channel); void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); -enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); const char *dss_get_clk_source_name(enum dss_clk_source clk_src); /* DSS VIDEO PLL */ -- cgit v1.2.3 From eab7579e3570efb1c23cd82ad4559503e5b031f8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:46 +0200 Subject: drm: omapdrm: dss: Remove unused functions prototypes The omap_dss_register_driver(), omap_dss_unregister_driver() and dispc_enable_gamma_table() functions don't exist anymore, remove their prototypes. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dss.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 287c90608557..7f3fa5330408 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -356,7 +356,6 @@ void dispc_disable_sidle(void); void dispc_lcd_enable_signal(bool enable); void dispc_pck_free_enable(bool enable); void dispc_enable_fifomerge(bool enable); -void dispc_enable_gamma_table(bool enable); typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck, unsigned long pck, void *data); -- cgit v1.2.3 From bafa89fcac4fa4950ffde0b4f565482290176450 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 15:07:47 +0200 Subject: drm: omapdrm: dsi: Make wait_for_bit_change() return a status The wait_for_bit_change() function returns the value of the bit it polls. This requires the caller to compare the return value to the expected bit value. As all the existing callers need is to check whether the bit has reached the expected value, it's easier to return a boolean status from the function. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dsi.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 86bd47f23424..41d500eea843 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -524,7 +524,7 @@ static void dsi_completion_handler(void *data, u32 mask) complete((struct completion *)data); } -static inline int wait_for_bit_change(struct platform_device *dsidev, +static inline bool wait_for_bit_change(struct platform_device *dsidev, const struct dsi_reg idx, int bitnum, int value) { unsigned long timeout; @@ -535,21 +535,21 @@ static inline int wait_for_bit_change(struct platform_device *dsidev, t = 100; while (t-- > 0) { if (REG_GET(dsidev, idx, bitnum, bitnum) == value) - return value; + return true; } /* then loop for 500ms, sleeping for 1ms in between */ timeout = jiffies + msecs_to_jiffies(500); while (time_before(jiffies, timeout)) { if (REG_GET(dsidev, idx, bitnum, bitnum) == value) - return value; + return true; wait = ns_to_ktime(1000 * 1000); set_current_state(TASK_UNINTERRUPTIBLE); schedule_hrtimeout(&wait, HRTIMER_MODE_REL); } - return !value; + return false; } static u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) @@ -1252,9 +1252,9 @@ static inline int dsi_if_enable(struct platform_device *dsidev, bool enable) enable = enable ? 1 : 0; REG_FLD_MOD(dsidev, DSI_CTRL, enable, 0, 0); /* IF_EN */ - if (wait_for_bit_change(dsidev, DSI_CTRL, 0, enable) != enable) { - DSSERR("Failed to set dsi_if_enable to %d\n", enable); - return -EIO; + if (!wait_for_bit_change(dsidev, DSI_CTRL, 0, enable)) { + DSSERR("Failed to set dsi_if_enable to %d\n", enable); + return -EIO; } return 0; @@ -1441,7 +1441,7 @@ static int dsi_pll_enable(struct dss_pll *pll) /* XXX PLL does not come out of reset without this... */ dispc_pck_free_enable(1); - if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1) != 1) { + if (!wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1)) { DSSERR("PLL not coming out of reset.\n"); r = -ENODEV; dispc_pck_free_enable(0); @@ -2187,7 +2187,7 @@ static int dsi_cio_init(struct platform_device *dsidev) * I/O. */ dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); - if (wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1) != 1) { + if (!wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1)) { DSSERR("CIO SCP Clock domain not coming out of reset.\n"); r = -EIO; goto err_scp_clk_dom; @@ -2235,7 +2235,7 @@ static int dsi_cio_init(struct platform_device *dsidev) if (r) goto err_cio_pwr; - if (wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1) != 1) { + if (!wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1)) { DSSERR("CIO PWR clock domain not coming out of reset.\n"); r = -ENODEV; goto err_cio_pwr_dom; @@ -2376,7 +2376,7 @@ static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev) r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ dsi_write_reg(dsidev, DSI_TIMING1, r); - if (wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0) != 0) { + if (!wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0)) { DSSERR("TX_STOP bit not going down\n"); return -EIO; } @@ -2518,10 +2518,9 @@ static int dsi_vc_enable(struct platform_device *dsidev, int channel, REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 0, 0); - if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), - 0, enable) != enable) { - DSSERR("Failed to set dsi_vc_enable to %d\n", enable); - return -EIO; + if (!wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 0, enable)) { + DSSERR("Failed to set dsi_vc_enable to %d\n", enable); + return -EIO; } return 0; @@ -2573,7 +2572,7 @@ static int dsi_vc_config_source(struct platform_device *dsidev, int channel, dsi_vc_enable(dsidev, channel, 0); /* VC_BUSY */ - if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) { + if (!wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0)) { DSSERR("vc(%d) busy when trying to config for VP\n", channel); return -EIO; } -- cgit v1.2.3 From a82f034765fa3e9db73b8ca99e8830f3bb31ac90 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:19 +0200 Subject: drm: omapdrm: Split init and cleanup from probe and remove functions When merging the omapdrm and omapdss drivers there will be not omapdrm platform device anymore, and thus no associated probe and remove functions. To prepare for that, split all the initialization code from the probe function to make it usable without a platform device. Similarly, split the cleanup code from the remove function. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/omap_drv.c | 83 +++++++++++++++++++++++--------------- drivers/gpu/drm/omapdrm/omap_drv.h | 2 + 2 files changed, 53 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index dd68b2556f5b..b571cc04e08d 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -510,24 +510,16 @@ static const struct soc_device_attribute omapdrm_soc_devices[] = { { /* sentinel */ } }; -static int pdev_probe(struct platform_device *pdev) +static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) { const struct soc_device_attribute *soc; - struct omap_drm_private *priv; struct drm_device *ddev; unsigned int i; int ret; - DBG("%s", pdev->name); - - if (omapdss_is_initialized() == false) - return -EPROBE_DEFER; + DBG("%s", dev_name(dev)); - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(&pdev->dev, "Failed to set the DMA mask\n"); - return ret; - } + priv->dev = dev; omap_crtc_pre_init(); @@ -535,13 +527,6 @@ static int pdev_probe(struct platform_device *pdev) if (ret) goto err_crtc_uninit; - /* Allocate and initialize the driver private structure. */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_disconnect_dssdevs; - } - priv->dispc_ops = dispc_get_ops(); soc = soc_device_match(omapdrm_soc_devices); @@ -552,14 +537,14 @@ static int pdev_probe(struct platform_device *pdev) INIT_LIST_HEAD(&priv->obj_list); /* Allocate and initialize the DRM device. */ - ddev = drm_dev_alloc(&omap_drm_driver, &pdev->dev); + ddev = drm_dev_alloc(&omap_drm_driver, priv->dev); if (IS_ERR(ddev)) { ret = PTR_ERR(ddev); - goto err_free_priv; + goto err_destroy_wq; } + priv->ddev = ddev; ddev->dev_private = priv; - platform_set_drvdata(pdev, ddev); /* Get memory bandwidth limits */ if (priv->dispc_ops->get_memory_bandwidth_limit) @@ -570,14 +555,14 @@ static int pdev_probe(struct platform_device *pdev) ret = omap_modeset_init(ddev); if (ret) { - dev_err(&pdev->dev, "omap_modeset_init failed: ret=%d\n", ret); + dev_err(priv->dev, "omap_modeset_init failed: ret=%d\n", ret); goto err_free_drm_dev; } /* Initialize vblank handling, start with all CRTCs disabled. */ ret = drm_vblank_init(ddev, priv->num_crtcs); if (ret) { - dev_err(&pdev->dev, "could not init vblank\n"); + dev_err(priv->dev, "could not init vblank\n"); goto err_cleanup_modeset; } @@ -610,20 +595,17 @@ err_cleanup_modeset: err_free_drm_dev: omap_gem_deinit(ddev); drm_dev_unref(ddev); -err_free_priv: +err_destroy_wq: destroy_workqueue(priv->wq); - kfree(priv); -err_disconnect_dssdevs: omap_disconnect_dssdevs(); err_crtc_uninit: omap_crtc_pre_uninit(); return ret; } -static int pdev_remove(struct platform_device *pdev) +static void omapdrm_cleanup(struct omap_drm_private *priv) { - struct drm_device *ddev = platform_get_drvdata(pdev); - struct omap_drm_private *priv = ddev->dev_private; + struct drm_device *ddev = priv->ddev; DBG(""); @@ -645,10 +627,45 @@ static int pdev_remove(struct platform_device *pdev) drm_dev_unref(ddev); destroy_workqueue(priv->wq); - kfree(priv); omap_disconnect_dssdevs(); omap_crtc_pre_uninit(); +} + +static int pdev_probe(struct platform_device *pdev) +{ + struct omap_drm_private *priv; + int ret; + + if (omapdss_is_initialized() == false) + return -EPROBE_DEFER; + + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "Failed to set the DMA mask\n"); + return ret; + } + + /* Allocate and initialize the driver private structure. */ + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + ret = omapdrm_init(priv, &pdev->dev); + if (ret < 0) + kfree(priv); + + return ret; +} + +static int pdev_remove(struct platform_device *pdev) +{ + struct omap_drm_private *priv = platform_get_drvdata(pdev); + + omapdrm_cleanup(priv); + kfree(priv); return 0; } @@ -692,7 +709,8 @@ static int omap_drm_resume_all_displays(void) static int omap_drm_suspend(struct device *dev) { - struct drm_device *drm_dev = dev_get_drvdata(dev); + struct omap_drm_private *priv = dev_get_drvdata(dev); + struct drm_device *drm_dev = priv->ddev; drm_kms_helper_poll_disable(drm_dev); @@ -705,7 +723,8 @@ static int omap_drm_suspend(struct device *dev) static int omap_drm_resume(struct device *dev) { - struct drm_device *drm_dev = dev_get_drvdata(dev); + struct omap_drm_private *priv = dev_get_drvdata(dev); + struct drm_device *drm_dev = priv->ddev; drm_modeset_lock_all(drm_dev); omap_drm_resume_all_displays(); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index ba322c519999..49351bb3731e 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -46,6 +46,8 @@ struct omap_drm_usergart; struct omap_drm_private { + struct drm_device *ddev; + struct device *dev; u32 omaprev; const struct dispc_ops *dispc_ops; -- cgit v1.2.3 From 0e546dfd3fa82c0d78cc12d04af9ee8d7cb07c29 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:20 +0200 Subject: drm: omapdrm: dss: Expose DSS data in a dss_device structure The anoonymous dss structure in dss.c is the top-level component in the omapdss driver. As such it should store all internal instance-specific data that is currently stored in global variables. This however requires both naming the structure to pass it around functions, and accessing it from various locations in the omapdss driver. While we could implement get and set functions for every field that needs to be accessed outside of dss.c, that would introduce overhead and complexity that we could avoid by exposing the structure to internal components of the omapdss driver. Do so to prepare for removal of global variables. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dss.c | 29 +---------------------------- drivers/gpu/drm/omapdrm/dss/dss.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index d5490336e7c7..245d8c0ae461 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -48,8 +48,6 @@ #include "omapdss.h" #include "dss.h" -#define DSS_SZ_REGS SZ_512 - struct dss_reg { u16 idx; }; @@ -90,32 +88,7 @@ struct dss_features { bool has_lcd_clk_src; }; -static struct { - struct platform_device *pdev; - void __iomem *base; - struct regmap *syscon_pll_ctrl; - u32 syscon_pll_ctrl_offset; - - struct clk *parent_clk; - struct clk *dss_clk; - unsigned long dss_clk_rate; - - unsigned long cache_req_pck; - unsigned long cache_prate; - struct dispc_clock_info cache_dispc_cinfo; - - enum dss_clk_source dsi_clk_source[MAX_NUM_DSI]; - enum dss_clk_source dispc_clk_source; - enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS]; - - bool ctx_valid; - u32 ctx[DSS_SZ_REGS / sizeof(u32)]; - - const struct dss_features *feat; - - struct dss_pll *video1_pll; - struct dss_pll *video2_pll; -} dss; +static struct dss_device dss; static const char * const dss_generic_clk_source_names[] = { [DSS_CLK_SRC_FCK] = "FCK", diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 7f3fa5330408..257ff7c62764 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -235,6 +235,35 @@ struct dss_lcd_mgr_config { struct seq_file; struct platform_device; +#define DSS_SZ_REGS SZ_512 + +struct dss_device { + struct platform_device *pdev; + void __iomem *base; + struct regmap *syscon_pll_ctrl; + u32 syscon_pll_ctrl_offset; + + struct clk *parent_clk; + struct clk *dss_clk; + unsigned long dss_clk_rate; + + unsigned long cache_req_pck; + unsigned long cache_prate; + struct dispc_clock_info cache_dispc_cinfo; + + enum dss_clk_source dsi_clk_source[MAX_NUM_DSI]; + enum dss_clk_source dispc_clk_source; + enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS]; + + bool ctx_valid; + u32 ctx[DSS_SZ_REGS / sizeof(u32)]; + + const struct dss_features *feat; + + struct dss_pll *video1_pll; + struct dss_pll *video2_pll; +}; + /* core */ static inline int dss_set_min_bus_tput(struct device *dev, unsigned long tput) { -- cgit v1.2.3 From 7b295257a13d827dac8c71af70e633c7ba722cfe Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:21 +0200 Subject: drm: omapdrm: dss: Pass DSS private structure to runtime PM functions To prepare for the removal of the global variable storing DSS private data, pass its pointer to the dss_runtime_{get,put}() functions. As this requires getting hold of the dss_device structure in the callers, we add a new dss_get_device() function to retrieve it. The function currently returns a pointer to the global data structure, and will later be updated to get the pointer from device driver data when the DSS private structure will be allocated dynamically. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dsi.c | 7 +++-- drivers/gpu/drm/omapdrm/dss/dss.c | 47 +++++++++++++++++++-------------- drivers/gpu/drm/omapdrm/dss/dss.h | 12 ++++++--- drivers/gpu/drm/omapdrm/dss/hdmi.h | 6 +++-- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 3 ++- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 3 ++- drivers/gpu/drm/omapdrm/dss/hdmi_pll.c | 10 ++++--- drivers/gpu/drm/omapdrm/dss/video-pll.c | 12 +++++---- 8 files changed, 61 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 41d500eea843..7ba33fc5d245 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -5322,7 +5322,8 @@ static const struct dss_pll_hw dss_omap5_dsi_pll_hw = { .has_refsel = true, }; -static int dsi_init_pll_data(struct platform_device *dsidev) +static int dsi_init_pll_data(struct dss_device *dss, + struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dss_pll *pll = &dsi->pll; @@ -5341,6 +5342,7 @@ static int dsi_init_pll_data(struct platform_device *dsidev) pll->base = dsi->pll_base; pll->hw = dsi->data->pll_hw; pll->ops = &dsi_pll_ops; + pll->dss = dss; r = dss_pll_register(pll); if (r) @@ -5417,6 +5419,7 @@ static const struct soc_device_attribute dsi_soc_devices[] = { static int dsi_bind(struct device *dev, struct device *master, void *data) { struct platform_device *dsidev = to_platform_device(dev); + struct dss_device *dss = dss_get_device(master); const struct soc_device_attribute *soc; const struct dsi_module_id_data *d; u32 rev; @@ -5525,7 +5528,7 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) if (r) return r; - dsi_init_pll_data(dsidev); + dsi_init_pll_data(dss, dsidev); pm_runtime_enable(&dsidev->dev); diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 245d8c0ae461..6c28e13d9ae0 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -345,7 +345,7 @@ static void dss_dump_clocks(struct seq_file *s) const char *fclk_name; unsigned long fclk_rate; - if (dss_runtime_get()) + if (dss_runtime_get(&dss)) return; seq_printf(s, "- DSS -\n"); @@ -357,7 +357,7 @@ static void dss_dump_clocks(struct seq_file *s) fclk_name, fclk_rate); - dss_runtime_put(); + dss_runtime_put(&dss); } #endif @@ -365,7 +365,7 @@ static void dss_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) - if (dss_runtime_get()) + if (dss_runtime_get(&dss)) return; DUMPREG(DSS_REVISION); @@ -379,7 +379,7 @@ static void dss_dump_regs(struct seq_file *s) DUMPREG(DSS_SDI_STATUS); } - dss_runtime_put(); + dss_runtime_put(&dss); #undef DUMPREG } @@ -837,27 +837,32 @@ static void dss_put_clocks(void) clk_put(dss.parent_clk); } -int dss_runtime_get(void) +int dss_runtime_get(struct dss_device *dss) { int r; DSSDBG("dss_runtime_get\n"); - r = pm_runtime_get_sync(&dss.pdev->dev); + r = pm_runtime_get_sync(&dss->pdev->dev); WARN_ON(r < 0); return r < 0 ? r : 0; } -void dss_runtime_put(void) +void dss_runtime_put(struct dss_device *dss) { int r; DSSDBG("dss_runtime_put\n"); - r = pm_runtime_put_sync(&dss.pdev->dev); + r = pm_runtime_put_sync(&dss->pdev->dev); WARN_ON(r < 0 && r != -ENOSYS && r != -EBUSY); } +struct dss_device *dss_get_device(struct device *dev) +{ + return &dss; +} + /* DEBUGFS */ #if defined(CONFIG_OMAP2_DSS_DEBUGFS) static void dss_debug_dump_clocks(struct seq_file *s) @@ -1223,13 +1228,15 @@ static int dss_video_pll_probe(struct platform_device *pdev) } if (of_property_match_string(np, "reg-names", "pll1") >= 0) { - dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator); + dss.video1_pll = dss_video_pll_init(&dss, pdev, 0, + pll_regulator); if (IS_ERR(dss.video1_pll)) return PTR_ERR(dss.video1_pll); } if (of_property_match_string(np, "reg-names", "pll2") >= 0) { - dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator); + dss.video2_pll = dss_video_pll_init(&dss, pdev, 1, + pll_regulator); if (IS_ERR(dss.video2_pll)) { dss_video_pll_uninit(dss.video1_pll); return PTR_ERR(dss.video2_pll); @@ -1311,16 +1318,16 @@ static int dss_add_child_component(struct device *dev, void *data) return 0; } -static int dss_probe_hardware(void) +static int dss_probe_hardware(struct dss_device *dss) { u32 rev; int r; - r = dss_runtime_get(); + r = dss_runtime_get(dss); if (r) return r; - dss.dss_clk_rate = clk_get_rate(dss.dss_clk); + dss->dss_clk_rate = clk_get_rate(dss->dss_clk); /* Select DPLL */ REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); @@ -1332,16 +1339,16 @@ static int dss_probe_hardware(void) REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ #endif - dss.dsi_clk_source[0] = DSS_CLK_SRC_FCK; - dss.dsi_clk_source[1] = DSS_CLK_SRC_FCK; - dss.dispc_clk_source = DSS_CLK_SRC_FCK; - dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; - dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK; + dss->dsi_clk_source[0] = DSS_CLK_SRC_FCK; + dss->dsi_clk_source[1] = DSS_CLK_SRC_FCK; + dss->dispc_clk_source = DSS_CLK_SRC_FCK; + dss->lcd_clk_source[0] = DSS_CLK_SRC_FCK; + dss->lcd_clk_source[1] = DSS_CLK_SRC_FCK; rev = dss_read_reg(DSS_REVISION); pr_info("OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - dss_runtime_put(); + dss_runtime_put(dss); return 0; } @@ -1397,7 +1404,7 @@ static int dss_probe(struct platform_device *pdev) /* Enable runtime PM and probe the hardware. */ pm_runtime_enable(&pdev->dev); - r = dss_probe_hardware(); + r = dss_probe_hardware(&dss); if (r) goto err_pm_runtime_disable; diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 257ff7c62764..a7aeb0e7e1ae 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -191,6 +191,7 @@ struct dss_pll_hw { struct dss_pll { const char *name; enum dss_pll_id id; + struct dss_device *dss; struct clk *clkin; struct regulator *regulator; @@ -291,8 +292,10 @@ static inline int dss_debugfs_create_file(const char *name, } #endif /* CONFIG_OMAP2_DSS_DEBUGFS */ -int dss_runtime_get(void); -void dss_runtime_put(void); +struct dss_device *dss_get_device(struct device *dev); + +int dss_runtime_get(struct dss_device *dss); +void dss_runtime_put(struct dss_device *dss); unsigned long dss_get_dispc_clk_rate(void); unsigned long dss_get_max_fck_rate(void); @@ -302,8 +305,9 @@ void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); const char *dss_get_clk_source_name(enum dss_clk_source clk_src); /* DSS VIDEO PLL */ -struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id, - struct regulator *regulator); +struct dss_pll *dss_video_pll_init(struct dss_device *dss, + struct platform_device *pdev, int id, + struct regulator *regulator); void dss_video_pll_uninit(struct dss_pll *pll); void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h index c2609c448ddc..02a3ae30bb1d 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h @@ -29,6 +29,8 @@ #include "omapdss.h" #include "dss.h" +struct dss_device; + /* HDMI Wrapper */ #define HDMI_WP_REVISION 0x0 @@ -324,8 +326,8 @@ phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp); /* HDMI PLL funcs */ void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s); -int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll, - struct hdmi_wp_data *wp); +int hdmi_pll_init(struct dss_device *dss, struct platform_device *pdev, + struct hdmi_pll_data *pll, struct hdmi_wp_data *wp); void hdmi_pll_uninit(struct hdmi_pll_data *hpll); /* HDMI PHY funcs */ diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index ae6401c569c4..0a8b52b43a36 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -717,6 +717,7 @@ static int hdmi_audio_register(struct device *dev) static int hdmi4_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); + struct dss_device *dss = dss_get_device(master); int r; int irq; @@ -734,7 +735,7 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data) if (r) return r; - r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp); + r = hdmi_pll_init(dss, pdev, &hdmi.pll, &hdmi.wp); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 9571be938d81..72cf8635caf5 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -718,6 +718,7 @@ static int hdmi_audio_register(struct device *dev) static int hdmi5_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); + struct dss_device *dss = dss_get_device(master); int r; int irq; @@ -735,7 +736,7 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data) if (r) return r; - r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp); + r = hdmi_pll_init(dss, pdev, &hdmi.pll, &hdmi.wp); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c index 08885d7de1e8..8ee9743e6fcf 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c @@ -128,7 +128,8 @@ static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = { .has_refsel = true, }; -static int hdmi_init_pll_data(struct platform_device *pdev, +static int hdmi_init_pll_data(struct dss_device *dss, + struct platform_device *pdev, struct hdmi_pll_data *hpll) { struct dss_pll *pll = &hpll->pll; @@ -145,6 +146,7 @@ static int hdmi_init_pll_data(struct platform_device *pdev, pll->id = DSS_PLL_HDMI; pll->base = hpll->base; pll->clkin = clk; + pll->dss = dss; if (hpll->wp->version == 4) pll->hw = &dss_omap4_hdmi_pll_hw; @@ -160,8 +162,8 @@ static int hdmi_init_pll_data(struct platform_device *pdev, return 0; } -int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll, - struct hdmi_wp_data *wp) +int hdmi_pll_init(struct dss_device *dss, struct platform_device *pdev, + struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) { int r; struct resource *res; @@ -174,7 +176,7 @@ int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll, if (IS_ERR(pll->base)) return PTR_ERR(pll->base); - r = hdmi_init_pll_data(pdev, pll); + r = hdmi_init_pll_data(dss, pdev, pll); if (r) { DSSERR("failed to init HDMI PLL\n"); return r; diff --git a/drivers/gpu/drm/omapdrm/dss/video-pll.c b/drivers/gpu/drm/omapdrm/dss/video-pll.c index bbedac797927..12997668730c 100644 --- a/drivers/gpu/drm/omapdrm/dss/video-pll.c +++ b/drivers/gpu/drm/omapdrm/dss/video-pll.c @@ -64,7 +64,7 @@ static int dss_video_pll_enable(struct dss_pll *pll) struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll); int r; - r = dss_runtime_get(); + r = dss_runtime_get(pll->dss); if (r) return r; @@ -83,7 +83,7 @@ static int dss_video_pll_enable(struct dss_pll *pll) err_reset: dss_dpll_disable_scp_clk(vpll); dss_ctrl_pll_enable(pll->id, false); - dss_runtime_put(); + dss_runtime_put(pll->dss); return r; } @@ -98,7 +98,7 @@ static void dss_video_pll_disable(struct dss_pll *pll) dss_ctrl_pll_enable(pll->id, false); - dss_runtime_put(); + dss_runtime_put(pll->dss); } static const struct dss_pll_ops dss_pll_ops = { @@ -136,8 +136,9 @@ static const struct dss_pll_hw dss_dra7_video_pll_hw = { .errata_i886 = true, }; -struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id, - struct regulator *regulator) +struct dss_pll *dss_video_pll_init(struct dss_device *dss, + struct platform_device *pdev, int id, + struct regulator *regulator) { const char * const reg_name[] = { "pll1", "pll2" }; const char * const clkctrl_name[] = { "pll1_clkctrl", "pll2_clkctrl" }; @@ -189,6 +190,7 @@ struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id, pll->base = pll_base; pll->hw = &dss_dra7_video_pll_hw; pll->ops = &dss_pll_ops; + pll->dss = dss; r = dss_pll_register(pll); if (r) -- cgit v1.2.3 From 2726099921caab2473dca91c9ddc4f4a108f4c15 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:22 +0200 Subject: drm: omapdrm: dss: Pass PLL pointer to dss_ctrl_pll_enable() This will allow accessing the PLL data to get the DSS device pointer, removing the need to access the global DSS private data. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dss.c | 13 +++++++------ drivers/gpu/drm/omapdrm/dss/dss.h | 2 +- drivers/gpu/drm/omapdrm/dss/hdmi_pll.c | 4 ++-- drivers/gpu/drm/omapdrm/dss/video-pll.c | 6 +++--- 4 files changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 6c28e13d9ae0..29c3a0dba698 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -152,17 +152,17 @@ static void dss_restore_context(void) #undef SR #undef RR -void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable) +void dss_ctrl_pll_enable(struct dss_pll *pll, bool enable) { unsigned int shift; unsigned int val; - if (!dss.syscon_pll_ctrl) + if (!pll->dss->syscon_pll_ctrl) return; val = !enable; - switch (pll_id) { + switch (pll->id) { case DSS_PLL_VIDEO1: shift = 0; break; @@ -173,12 +173,13 @@ void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable) shift = 2; break; default: - DSSERR("illegal DSS PLL ID %d\n", pll_id); + DSSERR("illegal DSS PLL ID %d\n", pll->id); return; } - regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset, - 1 << shift, val << shift); + regmap_update_bits(pll->dss->syscon_pll_ctrl, + pll->dss->syscon_pll_ctrl_offset, + 1 << shift, val << shift); } static int dss_ctrl_pll_set_control_mux(enum dss_clk_source clk_src, diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index a7aeb0e7e1ae..ea3eb6b0e7f1 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -310,7 +310,7 @@ struct dss_pll *dss_video_pll_init(struct dss_device *dss, struct regulator *regulator); void dss_video_pll_uninit(struct dss_pll *pll); -void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable); +void dss_ctrl_pll_enable(struct dss_pll *pll, bool enable); void dss_sdi_init(int datapairs); int dss_sdi_enable(void); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c index 8ee9743e6fcf..4fb97cd0cc8d 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c @@ -48,7 +48,7 @@ static int hdmi_pll_enable(struct dss_pll *dsspll) r = pm_runtime_get_sync(&pll->pdev->dev); WARN_ON(r < 0); - dss_ctrl_pll_enable(DSS_PLL_HDMI, true); + dss_ctrl_pll_enable(dsspll, true); r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); if (r) @@ -65,7 +65,7 @@ static void hdmi_pll_disable(struct dss_pll *dsspll) hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); - dss_ctrl_pll_enable(DSS_PLL_HDMI, false); + dss_ctrl_pll_enable(dsspll, false); r = pm_runtime_put_sync(&pll->pdev->dev); WARN_ON(r < 0 && r != -ENOSYS); diff --git a/drivers/gpu/drm/omapdrm/dss/video-pll.c b/drivers/gpu/drm/omapdrm/dss/video-pll.c index 12997668730c..344e7e0bbc4e 100644 --- a/drivers/gpu/drm/omapdrm/dss/video-pll.c +++ b/drivers/gpu/drm/omapdrm/dss/video-pll.c @@ -68,7 +68,7 @@ static int dss_video_pll_enable(struct dss_pll *pll) if (r) return r; - dss_ctrl_pll_enable(pll->id, true); + dss_ctrl_pll_enable(pll, true); dss_dpll_enable_scp_clk(vpll); @@ -82,7 +82,7 @@ static int dss_video_pll_enable(struct dss_pll *pll) err_reset: dss_dpll_disable_scp_clk(vpll); - dss_ctrl_pll_enable(pll->id, false); + dss_ctrl_pll_enable(pll, false); dss_runtime_put(pll->dss); return r; @@ -96,7 +96,7 @@ static void dss_video_pll_disable(struct dss_pll *pll) dss_dpll_disable_scp_clk(vpll); - dss_ctrl_pll_enable(pll->id, false); + dss_ctrl_pll_enable(pll, false); dss_runtime_put(pll->dss); } -- cgit v1.2.3 From d7157dfe0460fb003d41c1a5c36788de9b639ecb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:23 +0200 Subject: drm: omapdrm: dss: Pass DSS pointer to dss_sdi_*() functions This removes the need to access the global DSS private data in those functions (both for the current accesses and the future ones that will be introduced when allocating the DSS device dynamically). Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dss.c | 8 ++++---- drivers/gpu/drm/omapdrm/dss/dss.h | 14 ++++++++------ drivers/gpu/drm/omapdrm/dss/sdi.c | 13 ++++++++----- 3 files changed, 20 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 29c3a0dba698..c6a0b004b545 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -248,7 +248,7 @@ static int dss_ctrl_pll_set_control_mux(enum dss_clk_source clk_src, return 0; } -void dss_sdi_init(int datapairs) +void dss_sdi_init(struct dss_device *dss, int datapairs) { u32 l; @@ -267,7 +267,7 @@ void dss_sdi_init(int datapairs) dss_write_reg(DSS_PLL_CONTROL, l); } -int dss_sdi_enable(void) +int dss_sdi_enable(struct dss_device *dss) { unsigned long timeout; @@ -325,7 +325,7 @@ int dss_sdi_enable(void) return -ETIMEDOUT; } -void dss_sdi_disable(void) +void dss_sdi_disable(struct dss_device *dss) { dispc_lcd_enable_signal(0); @@ -1150,7 +1150,7 @@ static int dss_init_ports(struct platform_device *pdev) dpi_init_port(pdev, port, dss.feat->model); break; case OMAP_DISPLAY_TYPE_SDI: - sdi_init_port(pdev, port); + sdi_init_port(&dss, pdev, port); break; default: break; diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index ea3eb6b0e7f1..e560803b5127 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -312,9 +312,9 @@ void dss_video_pll_uninit(struct dss_pll *pll); void dss_ctrl_pll_enable(struct dss_pll *pll, bool enable); -void dss_sdi_init(int datapairs); -int dss_sdi_enable(void); -void dss_sdi_disable(void); +void dss_sdi_init(struct dss_device *dss, int datapairs); +int dss_sdi_enable(struct dss_device *dss); +void dss_sdi_disable(struct dss_device *dss); void dss_select_dsi_clk_source(int dsi_module, enum dss_clk_source clk_src); @@ -335,11 +335,13 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min, /* SDI */ #ifdef CONFIG_OMAP2_DSS_SDI -int sdi_init_port(struct platform_device *pdev, struct device_node *port); +int sdi_init_port(struct dss_device *dss, struct platform_device *pdev, + struct device_node *port); void sdi_uninit_port(struct device_node *port); #else -static inline int sdi_init_port(struct platform_device *pdev, - struct device_node *port) +static inline int sdi_init_port(struct dss_device *dss, + struct platform_device *pdev, + struct device_node *port) { return 0; } diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index d8ab31f3a813..f0564daa3831 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -31,6 +31,7 @@ static struct { struct platform_device *pdev; + struct dss_device *dss; bool update_enabled; struct regulator *vdds_sdi_reg; @@ -187,8 +188,8 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) */ dispc_mgr_set_clock_div(channel, &sdi.mgr_config.clock_info); - dss_sdi_init(sdi.datapairs); - r = dss_sdi_enable(); + dss_sdi_init(sdi.dss, sdi.datapairs); + r = dss_sdi_enable(sdi.dss); if (r) goto err_sdi_enable; mdelay(2); @@ -200,7 +201,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) return 0; err_mgr_enable: - dss_sdi_disable(); + dss_sdi_disable(sdi.dss); err_sdi_enable: err_set_dss_clock_div: err_calc_clock_div: @@ -217,7 +218,7 @@ static void sdi_display_disable(struct omap_dss_device *dssdev) dss_mgr_disable(channel); - dss_sdi_disable(); + dss_sdi_disable(sdi.dss); dispc_runtime_put(); @@ -345,7 +346,8 @@ static void sdi_uninit_output(struct platform_device *pdev) omapdss_unregister_output(out); } -int sdi_init_port(struct platform_device *pdev, struct device_node *port) +int sdi_init_port(struct dss_device *dss, struct platform_device *pdev, + struct device_node *port) { struct device_node *ep; u32 datapairs; @@ -362,6 +364,7 @@ int sdi_init_port(struct platform_device *pdev, struct device_node *port) } sdi.datapairs = datapairs; + sdi.dss = dss; of_node_put(ep); -- cgit v1.2.3 From 8aea8e6a79e77f4c4af4edc45db744f28f6fe008 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:24 +0200 Subject: drm: omapdrm: dss: Pass DSS pointer to dss_ops operations This removes the need to access the global DSS private data in those functions (both for the current accesses and the future ones that will be introduced when allocating the DSS device dynamically). Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dpi.c | 12 ++++--- drivers/gpu/drm/omapdrm/dss/dsi.c | 18 +++++----- drivers/gpu/drm/omapdrm/dss/dss.c | 68 ++++++++++++++++++++++--------------- drivers/gpu/drm/omapdrm/dss/dss.h | 25 ++++++++------ drivers/gpu/drm/omapdrm/dss/hdmi.h | 1 + drivers/gpu/drm/omapdrm/dss/hdmi4.c | 3 +- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 3 +- 7 files changed, 77 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 0a6eb39be444..e7f50fabca6f 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -38,6 +38,7 @@ struct dpi_data { struct platform_device *pdev; enum dss_model dss_model; + struct dss_device *dss; struct regulator *vdds_dsi_reg; enum dss_clk_source clk_src; @@ -302,7 +303,7 @@ static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel, if (r) return r; - dss_select_lcd_clk_source(channel, dpi->clk_src); + dss_select_lcd_clk_source(dpi->dss, channel, dpi->clk_src); dpi->mgr_config.clock_info = ctx.dispc_cinfo; @@ -412,7 +413,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_get_dispc; - r = dss_dpi_select_source(out->port_num, channel); + r = dss_dpi_select_source(dpi->dss, out->port_num, channel); if (r) goto err_src_sel; @@ -464,7 +465,7 @@ static void dpi_display_disable(struct omap_dss_device *dssdev) dss_mgr_disable(channel); if (dpi->pll) { - dss_select_lcd_clk_source(channel, DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(dpi->dss, channel, DSS_CLK_SRC_FCK); dss_pll_disable(dpi->pll); } @@ -748,8 +749,8 @@ static void dpi_uninit_output_port(struct device_node *port) omapdss_unregister_output(out); } -int dpi_init_port(struct platform_device *pdev, struct device_node *port, - enum dss_model dss_model) +int dpi_init_port(struct dss_device *dss, struct platform_device *pdev, + struct device_node *port, enum dss_model dss_model) { struct dpi_data *dpi; struct device_node *ep; @@ -776,6 +777,7 @@ int dpi_init_port(struct platform_device *pdev, struct device_node *port, dpi->pdev = pdev; dpi->dss_model = dss_model; + dpi->dss = dss; port->data = dpi; mutex_init(&dpi->lock); diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 7ba33fc5d245..71f86a5d4029 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -343,6 +343,7 @@ struct dsi_data { struct clk *dss_clk; struct regmap *syscon; + struct dss_device *dss; struct dispc_clock_info user_dispc_cinfo; struct dss_pll_clock_info user_dsi_cinfo; @@ -4206,7 +4207,7 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; - dss_select_lcd_clk_source(channel, dsi->module_id == 0 ? + dss_select_lcd_clk_source(dsi->dss, channel, dsi->module_id == 0 ? DSS_CLK_SRC_PLL1_1 : DSS_CLK_SRC_PLL2_1); @@ -4260,7 +4261,7 @@ err1: dss_mgr_unregister_framedone_handler(channel, dsi_framedone_irq_callback, dsidev); err: - dss_select_lcd_clk_source(channel, DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(dsi->dss, channel, DSS_CLK_SRC_FCK); return r; } @@ -4273,7 +4274,7 @@ static void dsi_display_uninit_dispc(struct platform_device *dsidev, dss_mgr_unregister_framedone_handler(channel, dsi_framedone_irq_callback, dsidev); - dss_select_lcd_clk_source(channel, DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(dsi->dss, channel, DSS_CLK_SRC_FCK); } static int dsi_configure_dsi_clocks(struct platform_device *dsidev) @@ -4306,9 +4307,9 @@ static int dsi_display_init_dsi(struct platform_device *dsidev) if (r) goto err1; - dss_select_dsi_clk_source(dsi->module_id, dsi->module_id == 0 ? - DSS_CLK_SRC_PLL1_2 : - DSS_CLK_SRC_PLL2_2); + dss_select_dsi_clk_source(dsi->dss, dsi->module_id, + dsi->module_id == 0 ? + DSS_CLK_SRC_PLL1_2 : DSS_CLK_SRC_PLL2_2); DSSDBG("PLL OK\n"); @@ -4340,7 +4341,7 @@ static int dsi_display_init_dsi(struct platform_device *dsidev) err3: dsi_cio_uninit(dsidev); err2: - dss_select_dsi_clk_source(dsi->module_id, DSS_CLK_SRC_FCK); + dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); err1: dss_pll_disable(&dsi->pll); err0: @@ -4362,7 +4363,7 @@ static void dsi_display_uninit_dsi(struct platform_device *dsidev, dsi_vc_enable(dsidev, 2, 0); dsi_vc_enable(dsidev, 3, 0); - dss_select_dsi_clk_source(dsi->module_id, DSS_CLK_SRC_FCK); + dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); dsi_cio_uninit(dsidev); dsi_pll_uninit(dsidev, disconnect_lanes); } @@ -5432,6 +5433,7 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) if (!dsi) return -ENOMEM; + dsi->dss = dss; dsi->pdev = dsidev; dev_set_drvdata(&dsidev->dev, dsi); diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index c6a0b004b545..73698a497e4a 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -69,9 +69,11 @@ struct dss_reg { dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) struct dss_ops { - int (*dpi_select_source)(int port, enum omap_channel channel); - int (*select_lcd_source)(enum omap_channel channel, - enum dss_clk_source clk_src); + int (*dpi_select_source)(struct dss_device *dss, int port, + enum omap_channel channel); + int (*select_lcd_source)(struct dss_device *dss, + enum omap_channel channel, + enum dss_clk_source clk_src); }; struct dss_features { @@ -432,8 +434,8 @@ static void dss_select_dispc_clk_source(enum dss_clk_source clk_src) dss.dispc_clk_source = clk_src; } -void dss_select_dsi_clk_source(int dsi_module, - enum dss_clk_source clk_src) +void dss_select_dsi_clk_source(struct dss_device *dss, int dsi_module, + enum dss_clk_source clk_src) { int b, pos; @@ -457,11 +459,12 @@ void dss_select_dsi_clk_source(int dsi_module, pos = dsi_module == 0 ? 1 : 10; REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* DSIx_CLK_SWITCH */ - dss.dsi_clk_source[dsi_module] = clk_src; + dss->dsi_clk_source[dsi_module] = clk_src; } -static int dss_lcd_clk_mux_dra7(enum omap_channel channel, - enum dss_clk_source clk_src) +static int dss_lcd_clk_mux_dra7(struct dss_device *dss, + enum omap_channel channel, + enum dss_clk_source clk_src) { const u8 ctrl_bits[] = { [OMAP_DSS_CHANNEL_LCD] = 0, @@ -487,8 +490,9 @@ static int dss_lcd_clk_mux_dra7(enum omap_channel channel, return 0; } -static int dss_lcd_clk_mux_omap5(enum omap_channel channel, - enum dss_clk_source clk_src) +static int dss_lcd_clk_mux_omap5(struct dss_device *dss, + enum omap_channel channel, + enum dss_clk_source clk_src) { const u8 ctrl_bits[] = { [OMAP_DSS_CHANNEL_LCD] = 0, @@ -517,8 +521,9 @@ static int dss_lcd_clk_mux_omap5(enum omap_channel channel, return 0; } -static int dss_lcd_clk_mux_omap4(enum omap_channel channel, - enum dss_clk_source clk_src) +static int dss_lcd_clk_mux_omap4(struct dss_device *dss, + enum omap_channel channel, + enum dss_clk_source clk_src) { const u8 ctrl_bits[] = { [OMAP_DSS_CHANNEL_LCD] = 0, @@ -545,23 +550,24 @@ static int dss_lcd_clk_mux_omap4(enum omap_channel channel, return 0; } -void dss_select_lcd_clk_source(enum omap_channel channel, - enum dss_clk_source clk_src) +void dss_select_lcd_clk_source(struct dss_device *dss, + enum omap_channel channel, + enum dss_clk_source clk_src) { int idx = dss_get_channel_index(channel); int r; - if (!dss.feat->has_lcd_clk_src) { + if (!dss->feat->has_lcd_clk_src) { dss_select_dispc_clk_source(clk_src); - dss.lcd_clk_source[idx] = clk_src; + dss->lcd_clk_source[idx] = clk_src; return; } - r = dss.feat->ops->select_lcd_source(channel, clk_src); + r = dss->feat->ops->select_lcd_source(dss, channel, clk_src); if (r) return; - dss.lcd_clk_source[idx] = clk_src; + dss->lcd_clk_source[idx] = clk_src; } enum dss_clk_source dss_get_dispc_clk_source(void) @@ -710,11 +716,12 @@ void dss_set_dac_pwrdn_bgz(bool enable) REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ } -void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src) +void dss_select_hdmi_venc_clk_source(struct dss_device *dss, + enum dss_hdmi_venc_clk_source_select src) { enum omap_dss_output_id outputs; - outputs = dss.feat->outputs[OMAP_DSS_CHANNEL_DIGIT]; + outputs = dss->feat->outputs[OMAP_DSS_CHANNEL_DIGIT]; /* Complain about invalid selections */ WARN_ON((src == DSS_VENC_TV_CLK) && !(outputs & OMAP_DSS_OUTPUT_VENC)); @@ -726,7 +733,8 @@ void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src) REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */ } -static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel) +static int dss_dpi_select_source_omap2_omap3(struct dss_device *dss, int port, + enum omap_channel channel) { if (channel != OMAP_DSS_CHANNEL_LCD) return -EINVAL; @@ -734,7 +742,8 @@ static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel return 0; } -static int dss_dpi_select_source_omap4(int port, enum omap_channel channel) +static int dss_dpi_select_source_omap4(struct dss_device *dss, int port, + enum omap_channel channel) { int val; @@ -754,7 +763,8 @@ static int dss_dpi_select_source_omap4(int port, enum omap_channel channel) return 0; } -static int dss_dpi_select_source_omap5(int port, enum omap_channel channel) +static int dss_dpi_select_source_omap5(struct dss_device *dss, int port, + enum omap_channel channel) { int val; @@ -780,11 +790,12 @@ static int dss_dpi_select_source_omap5(int port, enum omap_channel channel) return 0; } -static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel) +static int dss_dpi_select_source_dra7xx(struct dss_device *dss, int port, + enum omap_channel channel) { switch (port) { case 0: - return dss_dpi_select_source_omap5(port, channel); + return dss_dpi_select_source_omap5(dss, port, channel); case 1: if (channel != OMAP_DSS_CHANNEL_LCD2) return -EINVAL; @@ -800,9 +811,10 @@ static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel) return 0; } -int dss_dpi_select_source(int port, enum omap_channel channel) +int dss_dpi_select_source(struct dss_device *dss, int port, + enum omap_channel channel) { - return dss.feat->ops->dpi_select_source(port, channel); + return dss->feat->ops->dpi_select_source(dss, port, channel); } static int dss_get_clocks(void) @@ -1147,7 +1159,7 @@ static int dss_init_ports(struct platform_device *pdev) switch (dss.feat->ports[i]) { case OMAP_DISPLAY_TYPE_DPI: - dpi_init_port(pdev, port, dss.feat->model); + dpi_init_port(&dss, pdev, port, dss.feat->model); break; case OMAP_DISPLAY_TYPE_SDI: sdi_init_port(&dss, pdev, port); diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index e560803b5127..e3122e6ea043 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -300,8 +300,10 @@ void dss_runtime_put(struct dss_device *dss); unsigned long dss_get_dispc_clk_rate(void); unsigned long dss_get_max_fck_rate(void); enum omap_dss_output_id dss_get_supported_outputs(enum omap_channel channel); -int dss_dpi_select_source(int port, enum omap_channel channel); -void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); +int dss_dpi_select_source(struct dss_device *dss, int port, + enum omap_channel channel); +void dss_select_hdmi_venc_clk_source(struct dss_device *dss, + enum dss_hdmi_venc_clk_source_select src); const char *dss_get_clk_source_name(enum dss_clk_source clk_src); /* DSS VIDEO PLL */ @@ -316,10 +318,11 @@ void dss_sdi_init(struct dss_device *dss, int datapairs); int dss_sdi_enable(struct dss_device *dss); void dss_sdi_disable(struct dss_device *dss); -void dss_select_dsi_clk_source(int dsi_module, - enum dss_clk_source clk_src); -void dss_select_lcd_clk_source(enum omap_channel channel, - enum dss_clk_source clk_src); +void dss_select_dsi_clk_source(struct dss_device *dss, int dsi_module, + enum dss_clk_source clk_src); +void dss_select_lcd_clk_source(struct dss_device *dss, + enum omap_channel channel, + enum dss_clk_source clk_src); enum dss_clk_source dss_get_dispc_clk_source(void); enum dss_clk_source dss_get_dsi_clk_source(int dsi_module); enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel); @@ -365,12 +368,14 @@ void dsi_irq_handler(void); /* DPI */ #ifdef CONFIG_OMAP2_DSS_DPI -int dpi_init_port(struct platform_device *pdev, struct device_node *port, - enum dss_model dss_model); +int dpi_init_port(struct dss_device *dss, struct platform_device *pdev, + struct device_node *port, enum dss_model dss_model); void dpi_uninit_port(struct device_node *port); #else -static inline int dpi_init_port(struct platform_device *pdev, - struct device_node *port, enum dss_model dss_model) +static inline int dpi_init_port(struct dss_device *port, + struct platform_device *pdev, + struct device_node *port, + enum dss_model dss_model) { return 0; } diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h index 02a3ae30bb1d..0563e1955048 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h @@ -359,6 +359,7 @@ static inline bool hdmi_mode_has_audio(struct hdmi_config *cfg) struct omap_hdmi { struct mutex lock; struct platform_device *pdev; + struct dss_device *dss; struct hdmi_wp_data wp; struct hdmi_pll_data pll; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 0a8b52b43a36..3e4a5cf2d06f 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -148,7 +148,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) hdmi4_core_powerdown_disable(&hdmi.core); /* Make selection of HDMI in DSS */ - dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); + dss_select_hdmi_venc_clk_source(hdmi.dss, DSS_HDMI_M_PCLK); hdmi.core_enabled = true; @@ -722,6 +722,7 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data) int irq; hdmi.pdev = pdev; + hdmi.dss = dss; dev_set_drvdata(&pdev->dev, &hdmi); mutex_init(&hdmi.lock); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 72cf8635caf5..e7a71012b1cd 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -149,7 +149,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) goto err_runtime_get; /* Make selection of HDMI in DSS */ - dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); + dss_select_hdmi_venc_clk_source(hdmi.dss, DSS_HDMI_M_PCLK); hdmi.core_enabled = true; @@ -723,6 +723,7 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data) int irq; hdmi.pdev = pdev; + hdmi.dss = dss; dev_set_drvdata(&pdev->dev, &hdmi); mutex_init(&hdmi.lock); -- cgit v1.2.3 From 3cc62aadf414102785adbfc3dd2f2f3be85d60db Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:25 +0200 Subject: drm: omapdrm: dss: Pass DSS pointer to dss_get_*_clk_source() This removes the need to access the global DSS private data in those functions (both for the current accesses and the future ones that will be introduced when allocating the DSS device dynamically). Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dispc.c | 11 +++++++---- drivers/gpu/drm/omapdrm/dss/dsi.c | 8 +++++--- drivers/gpu/drm/omapdrm/dss/dss.c | 18 ++++++++++-------- drivers/gpu/drm/omapdrm/dss/dss.h | 8 +++++--- 4 files changed, 27 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 86d18f2d48ba..048b2e4d1f40 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -165,6 +165,7 @@ struct dispc_features { static struct { struct platform_device *pdev; void __iomem *base; + struct dss_device *dss; int irq; irq_handler_t user_handler; @@ -3112,7 +3113,7 @@ static unsigned long dispc_fclk_rate(void) unsigned long r; enum dss_clk_source src; - src = dss_get_dispc_clk_source(); + src = dss_get_dispc_clk_source(dispc.dss); if (src == DSS_CLK_SRC_FCK) { r = dss_get_dispc_clk_rate(); @@ -3139,7 +3140,7 @@ static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) if (!dss_mgr_is_lcd(channel)) return dispc_fclk_rate(); - src = dss_get_lcd_clk_source(channel); + src = dss_get_lcd_clk_source(dispc.dss, channel); if (src == DSS_CLK_SRC_FCK) { r = dss_get_dispc_clk_rate(); @@ -3219,7 +3220,7 @@ static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel chan seq_printf(s, "- %s -\n", mgr_desc[channel].name); - lcd_clk_src = dss_get_lcd_clk_source(channel); + lcd_clk_src = dss_get_lcd_clk_source(dispc.dss, channel); seq_printf(s, "%s clk source = %s\n", mgr_desc[channel].name, dss_get_clk_source_name(lcd_clk_src)); @@ -3236,7 +3237,7 @@ void dispc_dump_clocks(struct seq_file *s) { int lcd; u32 l; - enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); + enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(dispc.dss); if (dispc_runtime_get()) return; @@ -4549,12 +4550,14 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); const struct soc_device_attribute *soc; + struct dss_device *dss = dss_get_device(master); u32 rev; int r = 0; struct resource *dispc_mem; struct device_node *np = pdev->dev.of_node; dispc.pdev = pdev; + dispc.dss = dss; spin_lock_init(&dispc.control_lock); diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 71f86a5d4029..26f4122f6784 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -1286,8 +1286,10 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev) { unsigned long r; struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + enum dss_clk_source source; - if (dss_get_dsi_clk_source(dsi->module_id) == DSS_CLK_SRC_FCK) { + source = dss_get_dsi_clk_source(dsi->dss, dsi->module_id); + if (source == DSS_CLK_SRC_FCK) { /* DSI FCLK source is DSS_CLK_FCK */ r = clk_get_rate(dsi->dss_clk); } else { @@ -1506,8 +1508,8 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, int dsi_module = dsi->module_id; struct dss_pll *pll = &dsi->pll; - dispc_clk_src = dss_get_dispc_clk_source(); - dsi_clk_src = dss_get_dsi_clk_source(dsi_module); + dispc_clk_src = dss_get_dispc_clk_source(dsi->dss); + dsi_clk_src = dss_get_dsi_clk_source(dsi->dss, dsi_module); if (dsi_runtime_get(dsidev)) return; diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 73698a497e4a..bdf8f66002b6 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -570,25 +570,27 @@ void dss_select_lcd_clk_source(struct dss_device *dss, dss->lcd_clk_source[idx] = clk_src; } -enum dss_clk_source dss_get_dispc_clk_source(void) +enum dss_clk_source dss_get_dispc_clk_source(struct dss_device *dss) { - return dss.dispc_clk_source; + return dss->dispc_clk_source; } -enum dss_clk_source dss_get_dsi_clk_source(int dsi_module) +enum dss_clk_source dss_get_dsi_clk_source(struct dss_device *dss, + int dsi_module) { - return dss.dsi_clk_source[dsi_module]; + return dss->dsi_clk_source[dsi_module]; } -enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) +enum dss_clk_source dss_get_lcd_clk_source(struct dss_device *dss, + enum omap_channel channel) { - if (dss.feat->has_lcd_clk_src) { + if (dss->feat->has_lcd_clk_src) { int idx = dss_get_channel_index(channel); - return dss.lcd_clk_source[idx]; + return dss->lcd_clk_source[idx]; } else { /* LCD_CLK source is the same as DISPC_FCLK source for * OMAP2 and OMAP3 */ - return dss.dispc_clk_source; + return dss->dispc_clk_source; } } diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index e3122e6ea043..fc70c3c5ef11 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -323,9 +323,11 @@ void dss_select_dsi_clk_source(struct dss_device *dss, int dsi_module, void dss_select_lcd_clk_source(struct dss_device *dss, enum omap_channel channel, enum dss_clk_source clk_src); -enum dss_clk_source dss_get_dispc_clk_source(void); -enum dss_clk_source dss_get_dsi_clk_source(int dsi_module); -enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel); +enum dss_clk_source dss_get_dispc_clk_source(struct dss_device *dss); +enum dss_clk_source dss_get_dsi_clk_source(struct dss_device *dss, + int dsi_module); +enum dss_clk_source dss_get_lcd_clk_source(struct dss_device *dss, + enum omap_channel channel); void dss_set_venc_output(enum omap_dss_venc_type type); void dss_set_dac_pwrdn_bgz(bool enable); -- cgit v1.2.3 From 60f9c59fc1e2ced4a02e91088c367395edacc7fe Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:26 +0200 Subject: drm: omapdrm: dss: Pass DSS pointer to dss clock functions This removes the need to access the global DSS private data in those functions (both for the current accesses and the future ones that will be introduced when allocating the DSS device dynamically). Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dispc.c | 8 ++++---- drivers/gpu/drm/omapdrm/dss/dpi.c | 14 ++++++++------ drivers/gpu/drm/omapdrm/dss/dss.c | 37 ++++++++++++++++++------------------- drivers/gpu/drm/omapdrm/dss/dss.h | 10 +++++----- drivers/gpu/drm/omapdrm/dss/sdi.c | 5 +++-- 5 files changed, 38 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 048b2e4d1f40..8d0de1b790b7 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -3116,7 +3116,7 @@ static unsigned long dispc_fclk_rate(void) src = dss_get_dispc_clk_source(dispc.dss); if (src == DSS_CLK_SRC_FCK) { - r = dss_get_dispc_clk_rate(); + r = dss_get_dispc_clk_rate(dispc.dss); } else { struct dss_pll *pll; unsigned int clkout_idx; @@ -3143,7 +3143,7 @@ static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) src = dss_get_lcd_clk_source(dispc.dss, channel); if (src == DSS_CLK_SRC_FCK) { - r = dss_get_dispc_clk_rate(); + r = dss_get_dispc_clk_rate(dispc.dss); } else { struct dss_pll *pll; unsigned int clkout_idx; @@ -3499,7 +3499,7 @@ bool dispc_div_calc(unsigned long dispc_freq, pckd_hw_min = dispc.feat->min_pcd; pckd_hw_max = 255; - lck_max = dss_get_max_fck_rate(); + lck_max = dss_get_max_fck_rate(dispc.dss); pck_min = pck_min ? pck_min : 1; pck_max = pck_max ? pck_max : ULONG_MAX; @@ -4460,7 +4460,7 @@ static void dispc_errata_i734_wa(void) /* Set up and enable display manager for LCD1 */ dispc_mgr_setup(OMAP_DSS_CHANNEL_LCD, &i734.mgri); - dispc_calc_clock_rates(dss_get_dispc_clk_rate(), + dispc_calc_clock_rates(dss_get_dispc_clk_rate(dispc.dss), &lcd_conf.clock_info); dispc_mgr_set_lcd_config(OMAP_DSS_CHANNEL_LCD, &lcd_conf); dispc_mgr_set_timings(OMAP_DSS_CHANNEL_LCD, &i734.vm); diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index e7f50fabca6f..ba5adfb7ee70 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -207,7 +207,7 @@ static bool dpi_calc_pll_cb(int n, int m, unsigned long fint, ctx->pll_cinfo.clkdco = clkdco; return dss_pll_hsdiv_calc_a(ctx->pll, clkdco, - ctx->pck_min, dss_get_max_fck_rate(), + ctx->pck_min, dss_get_max_fck_rate(ctx->pll->dss), dpi_calc_hsdiv_cb, ctx); } @@ -256,7 +256,8 @@ static bool dpi_pll_clk_calc(struct dpi_data *dpi, unsigned long pck, } } -static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) +static bool dpi_dss_clk_calc(struct dpi_data *dpi, unsigned long pck, + struct dpi_clk_calc_ctx *ctx) { int i; @@ -277,7 +278,8 @@ static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) ctx->pck_min = 0; ctx->pck_max = pck + 1000 * i * i * i; - ok = dss_div_calc(pck, ctx->pck_min, dpi_calc_dss_cb, ctx); + ok = dss_div_calc(dpi->dss, pck, ctx->pck_min, + dpi_calc_dss_cb, ctx); if (ok) return ok; } @@ -321,11 +323,11 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, int r; bool ok; - ok = dpi_dss_clk_calc(pck_req, &ctx); + ok = dpi_dss_clk_calc(dpi, pck_req, &ctx); if (!ok) return -EINVAL; - r = dss_set_fck_rate(ctx.fck); + r = dss_set_fck_rate(dpi->dss, ctx.fck); if (r) return r; @@ -530,7 +532,7 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; } else { - ok = dpi_dss_clk_calc(vm->pixelclock, &ctx); + ok = dpi_dss_clk_calc(dpi, vm->pixelclock, &ctx); if (!ok) return -EINVAL; diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index bdf8f66002b6..0d292da6757d 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -594,8 +594,8 @@ enum dss_clk_source dss_get_lcd_clk_source(struct dss_device *dss, } } -bool dss_div_calc(unsigned long pck, unsigned long fck_min, - dss_div_calc_func func, void *data) +bool dss_div_calc(struct dss_device *dss, unsigned long pck, + unsigned long fck_min, dss_div_calc_func func, void *data) { int fckd, fckd_start, fckd_stop; unsigned long fck; @@ -604,24 +604,24 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min, unsigned long prate; unsigned int m; - fck_hw_max = dss.feat->fck_freq_max; + fck_hw_max = dss->feat->fck_freq_max; - if (dss.parent_clk == NULL) { + if (dss->parent_clk == NULL) { unsigned int pckd; pckd = fck_hw_max / pck; fck = pck * pckd; - fck = clk_round_rate(dss.dss_clk, fck); + fck = clk_round_rate(dss->dss_clk, fck); return func(fck, data); } - fckd_hw_max = dss.feat->fck_div_max; + fckd_hw_max = dss->feat->fck_div_max; - m = dss.feat->dss_fck_multiplier; - prate = clk_get_rate(dss.parent_clk); + m = dss->feat->dss_fck_multiplier; + prate = clk_get_rate(dss->parent_clk); fck_min = fck_min ? fck_min : 1; @@ -638,33 +638,32 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min, return false; } -int dss_set_fck_rate(unsigned long rate) +int dss_set_fck_rate(struct dss_device *dss, unsigned long rate) { int r; DSSDBG("set fck to %lu\n", rate); - r = clk_set_rate(dss.dss_clk, rate); + r = clk_set_rate(dss->dss_clk, rate); if (r) return r; - dss.dss_clk_rate = clk_get_rate(dss.dss_clk); + dss->dss_clk_rate = clk_get_rate(dss->dss_clk); - WARN_ONCE(dss.dss_clk_rate != rate, - "clk rate mismatch: %lu != %lu", dss.dss_clk_rate, - rate); + WARN_ONCE(dss->dss_clk_rate != rate, "clk rate mismatch: %lu != %lu", + dss->dss_clk_rate, rate); return 0; } -unsigned long dss_get_dispc_clk_rate(void) +unsigned long dss_get_dispc_clk_rate(struct dss_device *dss) { - return dss.dss_clk_rate; + return dss->dss_clk_rate; } -unsigned long dss_get_max_fck_rate(void) +unsigned long dss_get_max_fck_rate(struct dss_device *dss) { - return dss.feat->fck_freq_max; + return dss->feat->fck_freq_max; } enum omap_dss_output_id dss_get_supported_outputs(enum omap_channel channel) @@ -691,7 +690,7 @@ static int dss_setup_default_clock(void) fck = DIV_ROUND_UP(prate, fck_div) * dss.feat->dss_fck_multiplier; } - r = dss_set_fck_rate(fck); + r = dss_set_fck_rate(&dss, fck); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index fc70c3c5ef11..1d0edf2d145e 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -297,8 +297,8 @@ struct dss_device *dss_get_device(struct device *dev); int dss_runtime_get(struct dss_device *dss); void dss_runtime_put(struct dss_device *dss); -unsigned long dss_get_dispc_clk_rate(void); -unsigned long dss_get_max_fck_rate(void); +unsigned long dss_get_dispc_clk_rate(struct dss_device *dss); +unsigned long dss_get_max_fck_rate(struct dss_device *dss); enum omap_dss_output_id dss_get_supported_outputs(enum omap_channel channel); int dss_dpi_select_source(struct dss_device *dss, int port, enum omap_channel channel); @@ -332,11 +332,11 @@ enum dss_clk_source dss_get_lcd_clk_source(struct dss_device *dss, void dss_set_venc_output(enum omap_dss_venc_type type); void dss_set_dac_pwrdn_bgz(bool enable); -int dss_set_fck_rate(unsigned long rate); +int dss_set_fck_rate(struct dss_device *dss, unsigned long rate); typedef bool (*dss_div_calc_func)(unsigned long fck, void *data); -bool dss_div_calc(unsigned long pck, unsigned long fck_min, - dss_div_calc_func func, void *data); +bool dss_div_calc(struct dss_device *dss, unsigned long pck, + unsigned long fck_min, dss_div_calc_func func, void *data); /* SDI */ #ifdef CONFIG_OMAP2_DSS_SDI diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index f0564daa3831..6f39e0ff3055 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -99,7 +99,8 @@ static int sdi_calc_clock_div(unsigned long pclk, ctx.pck_min = 0; ctx.pck_max = pclk + 1000 * i * i * i; - ok = dss_div_calc(pclk, ctx.pck_min, dpi_calc_dss_cb, &ctx); + ok = dss_div_calc(sdi.dss, pclk, ctx.pck_min, + dpi_calc_dss_cb, &ctx); if (ok) { *fck = ctx.fck; *dispc_cinfo = ctx.dispc_cinfo; @@ -169,7 +170,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) dss_mgr_set_timings(channel, vm); - r = dss_set_fck_rate(fck); + r = dss_set_fck_rate(sdi.dss, fck); if (r) goto err_set_dss_clock_div; -- cgit v1.2.3 From 1ef904e1e4f05d32331783d413e341c6353ae9aa Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:27 +0200 Subject: drm: omapdrm: dss: Pass DSS pointer to remaining dss functions This removes the need to access the global DSS private data in those functions (both for the current accesses and the future ones that will be introduced when allocating the DSS device dynamically). Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dispc.c | 2 +- drivers/gpu/drm/omapdrm/dss/dss.c | 9 +++++---- drivers/gpu/drm/omapdrm/dss/dss.h | 7 ++++--- drivers/gpu/drm/omapdrm/dss/venc.c | 11 +++++++---- 4 files changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 8d0de1b790b7..867887151565 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -2733,7 +2733,7 @@ static int dispc_ovl_enable(enum omap_plane_id plane, bool enable) static enum omap_dss_output_id dispc_mgr_get_supported_outputs(enum omap_channel channel) { - return dss_get_supported_outputs(channel); + return dss_get_supported_outputs(dispc.dss, channel); } static void dispc_lcd_enable_signal_polarity(bool act_high) diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 0d292da6757d..7820b04c43e2 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -666,9 +666,10 @@ unsigned long dss_get_max_fck_rate(struct dss_device *dss) return dss->feat->fck_freq_max; } -enum omap_dss_output_id dss_get_supported_outputs(enum omap_channel channel) +enum omap_dss_output_id dss_get_supported_outputs(struct dss_device *dss, + enum omap_channel channel) { - return dss.feat->outputs[channel]; + return dss->feat->outputs[channel]; } static int dss_setup_default_clock(void) @@ -697,7 +698,7 @@ static int dss_setup_default_clock(void) return 0; } -void dss_set_venc_output(enum omap_dss_venc_type type) +void dss_set_venc_output(struct dss_device *dss, enum omap_dss_venc_type type) { int l = 0; @@ -712,7 +713,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type) REG_FLD_MOD(DSS_CONTROL, l, 6, 6); } -void dss_set_dac_pwrdn_bgz(bool enable) +void dss_set_dac_pwrdn_bgz(struct dss_device *dss, bool enable) { REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ } diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 1d0edf2d145e..89d708e8e970 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -299,7 +299,8 @@ void dss_runtime_put(struct dss_device *dss); unsigned long dss_get_dispc_clk_rate(struct dss_device *dss); unsigned long dss_get_max_fck_rate(struct dss_device *dss); -enum omap_dss_output_id dss_get_supported_outputs(enum omap_channel channel); +enum omap_dss_output_id dss_get_supported_outputs(struct dss_device *dss, + enum omap_channel channel); int dss_dpi_select_source(struct dss_device *dss, int port, enum omap_channel channel); void dss_select_hdmi_venc_clk_source(struct dss_device *dss, @@ -329,8 +330,8 @@ enum dss_clk_source dss_get_dsi_clk_source(struct dss_device *dss, enum dss_clk_source dss_get_lcd_clk_source(struct dss_device *dss, enum omap_channel channel); -void dss_set_venc_output(enum omap_dss_venc_type type); -void dss_set_dac_pwrdn_bgz(bool enable); +void dss_set_venc_output(struct dss_device *dss, enum omap_dss_venc_type type); +void dss_set_dac_pwrdn_bgz(struct dss_device *dss, bool enable); int dss_set_fck_rate(struct dss_device *dss, unsigned long rate); diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 6de9d734ddb9..08bae18be188 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -325,6 +325,7 @@ static struct { struct mutex venc_lock; u32 wss_data; struct regulator *vdda_dac_reg; + struct dss_device *dss; struct clk *tv_dac_clk; @@ -468,8 +469,8 @@ static int venc_power_on(struct omap_dss_device *dssdev) venc_reset(); venc_write_config(venc_timings_to_config(&venc.vm)); - dss_set_venc_output(venc.type); - dss_set_dac_pwrdn_bgz(1); + dss_set_venc_output(venc.dss, venc.type); + dss_set_dac_pwrdn_bgz(venc.dss, 1); l = 0; @@ -499,7 +500,7 @@ err2: regulator_disable(venc.vdda_dac_reg); err1: venc_write_reg(VENC_OUTPUT_CONTROL, 0); - dss_set_dac_pwrdn_bgz(0); + dss_set_dac_pwrdn_bgz(venc.dss, 0); venc_runtime_put(); err0: @@ -511,7 +512,7 @@ static void venc_power_off(struct omap_dss_device *dssdev) enum omap_channel channel = dssdev->dispc_channel; venc_write_reg(VENC_OUTPUT_CONTROL, 0); - dss_set_dac_pwrdn_bgz(0); + dss_set_dac_pwrdn_bgz(venc.dss, 0); dss_mgr_disable(channel); @@ -871,11 +872,13 @@ static const struct soc_device_attribute venc_soc_devices[] = { static int venc_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); + struct dss_device *dss = dss_get_device(master); u8 rev_id; struct resource *venc_mem; int r; venc.pdev = pdev; + venc.dss = dss; /* The OMAP34xx, OMAP35xx and AM35xx VENC require the TV DAC clock. */ if (soc_device_match(venc_soc_devices)) -- cgit v1.2.3 From 360c21533ce79981bd9802622dd0b7a0dcd81395 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:28 +0200 Subject: drm: omapdrm: dss: Allocate the DSS private data structure dynamically The DSS private data structure is currently stored as a global variable. While no platform with multiple DSS devices currently exists nor is planned, this doesn't comply with the kernel device model and should thus be fixed. Allocate the DSS private data structure dynamically for each DSS instance and remove the global variable. All code that need access to the structure now retrieves it dynamically so we can remove the global variable. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dss.c | 341 +++++++++++++++++++++----------------- 1 file changed, 186 insertions(+), 155 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 7820b04c43e2..4b00faa1a8cc 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -62,11 +62,12 @@ struct dss_reg { #define DSS_PLL_CONTROL DSS_REG(0x0048) #define DSS_SDI_STATUS DSS_REG(0x005C) -#define REG_GET(idx, start, end) \ - FLD_GET(dss_read_reg(idx), start, end) +#define REG_GET(dss, idx, start, end) \ + FLD_GET(dss_read_reg(dss, idx), start, end) -#define REG_FLD_MOD(idx, val, start, end) \ - dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) +#define REG_FLD_MOD(dss, idx, val, start, end) \ + dss_write_reg(dss, idx, \ + FLD_MOD(dss_read_reg(dss, idx), val, start, end)) struct dss_ops { int (*dpi_select_source)(struct dss_device *dss, int port, @@ -90,8 +91,6 @@ struct dss_features { bool has_lcd_clk_src; }; -static struct dss_device dss; - static const char * const dss_generic_clk_source_names[] = { [DSS_CLK_SRC_FCK] = "FCK", [DSS_CLK_SRC_PLL1_1] = "PLL1:1", @@ -103,49 +102,50 @@ static const char * const dss_generic_clk_source_names[] = { [DSS_CLK_SRC_HDMI_PLL] = "HDMI PLL", }; -static inline void dss_write_reg(const struct dss_reg idx, u32 val) +static inline void dss_write_reg(struct dss_device *dss, + const struct dss_reg idx, u32 val) { - __raw_writel(val, dss.base + idx.idx); + __raw_writel(val, dss->base + idx.idx); } -static inline u32 dss_read_reg(const struct dss_reg idx) +static inline u32 dss_read_reg(struct dss_device *dss, const struct dss_reg idx) { - return __raw_readl(dss.base + idx.idx); + return __raw_readl(dss->base + idx.idx); } -#define SR(reg) \ - dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg) -#define RR(reg) \ - dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)]) +#define SR(dss, reg) \ + dss->ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(dss, DSS_##reg) +#define RR(dss, reg) \ + dss_write_reg(dss, DSS_##reg, dss->ctx[(DSS_##reg).idx / sizeof(u32)]) -static void dss_save_context(void) +static void dss_save_context(struct dss_device *dss) { DSSDBG("dss_save_context\n"); - SR(CONTROL); + SR(dss, CONTROL); - if (dss.feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) { - SR(SDI_CONTROL); - SR(PLL_CONTROL); + if (dss->feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) { + SR(dss, SDI_CONTROL); + SR(dss, PLL_CONTROL); } - dss.ctx_valid = true; + dss->ctx_valid = true; DSSDBG("context saved\n"); } -static void dss_restore_context(void) +static void dss_restore_context(struct dss_device *dss) { DSSDBG("dss_restore_context\n"); - if (!dss.ctx_valid) + if (!dss->ctx_valid) return; - RR(CONTROL); + RR(dss, CONTROL); - if (dss.feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) { - RR(SDI_CONTROL); - RR(PLL_CONTROL); + if (dss->feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) { + RR(dss, SDI_CONTROL); + RR(dss, PLL_CONTROL); } DSSDBG("context restored\n"); @@ -184,12 +184,13 @@ void dss_ctrl_pll_enable(struct dss_pll *pll, bool enable) 1 << shift, val << shift); } -static int dss_ctrl_pll_set_control_mux(enum dss_clk_source clk_src, - enum omap_channel channel) +static int dss_ctrl_pll_set_control_mux(struct dss_device *dss, + enum dss_clk_source clk_src, + enum omap_channel channel) { unsigned int shift, val; - if (!dss.syscon_pll_ctrl) + if (!dss->syscon_pll_ctrl) return -EINVAL; switch (channel) { @@ -244,7 +245,7 @@ static int dss_ctrl_pll_set_control_mux(enum dss_clk_source clk_src, return -EINVAL; } - regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset, + regmap_update_bits(dss->syscon_pll_ctrl, dss->syscon_pll_ctrl_offset, 0x3 << shift, val << shift); return 0; @@ -256,17 +257,17 @@ void dss_sdi_init(struct dss_device *dss, int datapairs) BUG_ON(datapairs > 3 || datapairs < 1); - l = dss_read_reg(DSS_SDI_CONTROL); + l = dss_read_reg(dss, DSS_SDI_CONTROL); l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */ l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */ l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */ - dss_write_reg(DSS_SDI_CONTROL, l); + dss_write_reg(dss, DSS_SDI_CONTROL, l); - l = dss_read_reg(DSS_PLL_CONTROL); + l = dss_read_reg(dss, DSS_PLL_CONTROL); l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */ l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */ l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */ - dss_write_reg(DSS_PLL_CONTROL, l); + dss_write_reg(dss, DSS_PLL_CONTROL, l); } int dss_sdi_enable(struct dss_device *dss) @@ -276,15 +277,15 @@ int dss_sdi_enable(struct dss_device *dss) dispc_pck_free_enable(1); /* Reset SDI PLL */ - REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */ + REG_FLD_MOD(dss, DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */ udelay(1); /* wait 2x PCLK */ /* Lock SDI PLL */ - REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */ + REG_FLD_MOD(dss, DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */ /* Waiting for PLL lock request to complete */ timeout = jiffies + msecs_to_jiffies(500); - while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) { + while (dss_read_reg(dss, DSS_SDI_STATUS) & (1 << 6)) { if (time_after_eq(jiffies, timeout)) { DSSERR("PLL lock request timed out\n"); goto err1; @@ -292,11 +293,11 @@ int dss_sdi_enable(struct dss_device *dss) } /* Clearing PLL_GO bit */ - REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28); + REG_FLD_MOD(dss, DSS_PLL_CONTROL, 0, 28, 28); /* Waiting for PLL to lock */ timeout = jiffies + msecs_to_jiffies(500); - while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) { + while (!(dss_read_reg(dss, DSS_SDI_STATUS) & (1 << 5))) { if (time_after_eq(jiffies, timeout)) { DSSERR("PLL lock timed out\n"); goto err1; @@ -307,7 +308,7 @@ int dss_sdi_enable(struct dss_device *dss) /* Waiting for SDI reset to complete */ timeout = jiffies + msecs_to_jiffies(500); - while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) { + while (!(dss_read_reg(dss, DSS_SDI_STATUS) & (1 << 2))) { if (time_after_eq(jiffies, timeout)) { DSSERR("SDI reset timed out\n"); goto err2; @@ -320,7 +321,7 @@ int dss_sdi_enable(struct dss_device *dss) dispc_lcd_enable_signal(0); err1: /* Reset SDI PLL */ - REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ + REG_FLD_MOD(dss, DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ dispc_pck_free_enable(0); @@ -334,7 +335,7 @@ void dss_sdi_disable(struct dss_device *dss) dispc_pck_free_enable(0); /* Reset SDI PLL */ - REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ + REG_FLD_MOD(dss, DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ } const char *dss_get_clk_source_name(enum dss_clk_source clk_src) @@ -343,46 +344,48 @@ const char *dss_get_clk_source_name(enum dss_clk_source clk_src) } #if defined(CONFIG_OMAP2_DSS_DEBUGFS) -static void dss_dump_clocks(struct seq_file *s) +static void dss_dump_clocks(struct dss_device *dss, struct seq_file *s) { const char *fclk_name; unsigned long fclk_rate; - if (dss_runtime_get(&dss)) + if (dss_runtime_get(dss)) return; seq_printf(s, "- DSS -\n"); fclk_name = dss_get_clk_source_name(DSS_CLK_SRC_FCK); - fclk_rate = clk_get_rate(dss.dss_clk); + fclk_rate = clk_get_rate(dss->dss_clk); seq_printf(s, "%s = %lu\n", fclk_name, fclk_rate); - dss_runtime_put(&dss); + dss_runtime_put(dss); } #endif static void dss_dump_regs(struct seq_file *s) { -#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) + struct dss_device *dss = s->private; + +#define DUMPREG(dss, r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(dss, r)) - if (dss_runtime_get(&dss)) + if (dss_runtime_get(dss)) return; - DUMPREG(DSS_REVISION); - DUMPREG(DSS_SYSCONFIG); - DUMPREG(DSS_SYSSTATUS); - DUMPREG(DSS_CONTROL); + DUMPREG(dss, DSS_REVISION); + DUMPREG(dss, DSS_SYSCONFIG); + DUMPREG(dss, DSS_SYSSTATUS); + DUMPREG(dss, DSS_CONTROL); - if (dss.feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) { - DUMPREG(DSS_SDI_CONTROL); - DUMPREG(DSS_PLL_CONTROL); - DUMPREG(DSS_SDI_STATUS); + if (dss->feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) { + DUMPREG(dss, DSS_SDI_CONTROL); + DUMPREG(dss, DSS_PLL_CONTROL); + DUMPREG(dss, DSS_SDI_STATUS); } - dss_runtime_put(&dss); + dss_runtime_put(dss); #undef DUMPREG } @@ -401,7 +404,8 @@ static int dss_get_channel_index(enum omap_channel channel) } } -static void dss_select_dispc_clk_source(enum dss_clk_source clk_src) +static void dss_select_dispc_clk_source(struct dss_device *dss, + enum dss_clk_source clk_src) { int b; @@ -409,7 +413,7 @@ static void dss_select_dispc_clk_source(enum dss_clk_source clk_src) * We always use PRCM clock as the DISPC func clock, except on DSS3, * where we don't have separate DISPC and LCD clock sources. */ - if (WARN_ON(dss.feat->has_lcd_clk_src && clk_src != DSS_CLK_SRC_FCK)) + if (WARN_ON(dss->feat->has_lcd_clk_src && clk_src != DSS_CLK_SRC_FCK)) return; switch (clk_src) { @@ -427,11 +431,11 @@ static void dss_select_dispc_clk_source(enum dss_clk_source clk_src) return; } - REG_FLD_MOD(DSS_CONTROL, b, /* DISPC_CLK_SWITCH */ - dss.feat->dispc_clk_switch.start, - dss.feat->dispc_clk_switch.end); + REG_FLD_MOD(dss, DSS_CONTROL, b, /* DISPC_CLK_SWITCH */ + dss->feat->dispc_clk_switch.start, + dss->feat->dispc_clk_switch.end); - dss.dispc_clk_source = clk_src; + dss->dispc_clk_source = clk_src; } void dss_select_dsi_clk_source(struct dss_device *dss, int dsi_module, @@ -457,7 +461,7 @@ void dss_select_dsi_clk_source(struct dss_device *dss, int dsi_module, } pos = dsi_module == 0 ? 1 : 10; - REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* DSIx_CLK_SWITCH */ + REG_FLD_MOD(dss, DSS_CONTROL, b, pos, pos); /* DSIx_CLK_SWITCH */ dss->dsi_clk_source[dsi_module] = clk_src; } @@ -477,15 +481,15 @@ static int dss_lcd_clk_mux_dra7(struct dss_device *dss, if (clk_src == DSS_CLK_SRC_FCK) { /* LCDx_CLK_SWITCH */ - REG_FLD_MOD(DSS_CONTROL, 0, ctrl_bit, ctrl_bit); + REG_FLD_MOD(dss, DSS_CONTROL, 0, ctrl_bit, ctrl_bit); return -EINVAL; } - r = dss_ctrl_pll_set_control_mux(clk_src, channel); + r = dss_ctrl_pll_set_control_mux(dss, clk_src, channel); if (r) return r; - REG_FLD_MOD(DSS_CONTROL, 1, ctrl_bit, ctrl_bit); + REG_FLD_MOD(dss, DSS_CONTROL, 1, ctrl_bit, ctrl_bit); return 0; } @@ -509,14 +513,14 @@ static int dss_lcd_clk_mux_omap5(struct dss_device *dss, if (clk_src == DSS_CLK_SRC_FCK) { /* LCDx_CLK_SWITCH */ - REG_FLD_MOD(DSS_CONTROL, 0, ctrl_bit, ctrl_bit); + REG_FLD_MOD(dss, DSS_CONTROL, 0, ctrl_bit, ctrl_bit); return -EINVAL; } if (WARN_ON(allowed_plls[channel] != clk_src)) return -EINVAL; - REG_FLD_MOD(DSS_CONTROL, 1, ctrl_bit, ctrl_bit); + REG_FLD_MOD(dss, DSS_CONTROL, 1, ctrl_bit, ctrl_bit); return 0; } @@ -538,14 +542,14 @@ static int dss_lcd_clk_mux_omap4(struct dss_device *dss, if (clk_src == DSS_CLK_SRC_FCK) { /* LCDx_CLK_SWITCH */ - REG_FLD_MOD(DSS_CONTROL, 0, ctrl_bit, ctrl_bit); + REG_FLD_MOD(dss, DSS_CONTROL, 0, ctrl_bit, ctrl_bit); return 0; } if (WARN_ON(allowed_plls[channel] != clk_src)) return -EINVAL; - REG_FLD_MOD(DSS_CONTROL, 1, ctrl_bit, ctrl_bit); + REG_FLD_MOD(dss, DSS_CONTROL, 1, ctrl_bit, ctrl_bit); return 0; } @@ -558,7 +562,7 @@ void dss_select_lcd_clk_source(struct dss_device *dss, int r; if (!dss->feat->has_lcd_clk_src) { - dss_select_dispc_clk_source(clk_src); + dss_select_dispc_clk_source(dss, clk_src); dss->lcd_clk_source[idx] = clk_src; return; } @@ -672,26 +676,27 @@ enum omap_dss_output_id dss_get_supported_outputs(struct dss_device *dss, return dss->feat->outputs[channel]; } -static int dss_setup_default_clock(void) +static int dss_setup_default_clock(struct dss_device *dss) { unsigned long max_dss_fck, prate; unsigned long fck; unsigned int fck_div; int r; - max_dss_fck = dss.feat->fck_freq_max; + max_dss_fck = dss->feat->fck_freq_max; - if (dss.parent_clk == NULL) { - fck = clk_round_rate(dss.dss_clk, max_dss_fck); + if (dss->parent_clk == NULL) { + fck = clk_round_rate(dss->dss_clk, max_dss_fck); } else { - prate = clk_get_rate(dss.parent_clk); + prate = clk_get_rate(dss->parent_clk); - fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier, + fck_div = DIV_ROUND_UP(prate * dss->feat->dss_fck_multiplier, max_dss_fck); - fck = DIV_ROUND_UP(prate, fck_div) * dss.feat->dss_fck_multiplier; + fck = DIV_ROUND_UP(prate, fck_div) + * dss->feat->dss_fck_multiplier; } - r = dss_set_fck_rate(&dss, fck); + r = dss_set_fck_rate(dss, fck); if (r) return r; @@ -710,12 +715,13 @@ void dss_set_venc_output(struct dss_device *dss, enum omap_dss_venc_type type) BUG(); /* venc out selection. 0 = comp, 1 = svideo */ - REG_FLD_MOD(DSS_CONTROL, l, 6, 6); + REG_FLD_MOD(dss, DSS_CONTROL, l, 6, 6); } void dss_set_dac_pwrdn_bgz(struct dss_device *dss, bool enable) { - REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ + /* DAC Power-Down Control */ + REG_FLD_MOD(dss, DSS_CONTROL, enable, 5, 5); } void dss_select_hdmi_venc_clk_source(struct dss_device *dss, @@ -732,7 +738,8 @@ void dss_select_hdmi_venc_clk_source(struct dss_device *dss, /* Select only if we have options */ if ((outputs & OMAP_DSS_OUTPUT_VENC) && (outputs & OMAP_DSS_OUTPUT_HDMI)) - REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */ + /* VENC_HDMI_SWITCH */ + REG_FLD_MOD(dss, DSS_CONTROL, src, 15, 15); } static int dss_dpi_select_source_omap2_omap3(struct dss_device *dss, int port, @@ -760,7 +767,7 @@ static int dss_dpi_select_source_omap4(struct dss_device *dss, int port, return -EINVAL; } - REG_FLD_MOD(DSS_CONTROL, val, 17, 17); + REG_FLD_MOD(dss, DSS_CONTROL, val, 17, 17); return 0; } @@ -787,7 +794,7 @@ static int dss_dpi_select_source_omap5(struct dss_device *dss, int port, return -EINVAL; } - REG_FLD_MOD(DSS_CONTROL, val, 17, 16); + REG_FLD_MOD(dss, DSS_CONTROL, val, 17, 16); return 0; } @@ -819,37 +826,38 @@ int dss_dpi_select_source(struct dss_device *dss, int port, return dss->feat->ops->dpi_select_source(dss, port, channel); } -static int dss_get_clocks(void) +static int dss_get_clocks(struct dss_device *dss) { struct clk *clk; - clk = devm_clk_get(&dss.pdev->dev, "fck"); + clk = devm_clk_get(&dss->pdev->dev, "fck"); if (IS_ERR(clk)) { DSSERR("can't get clock fck\n"); return PTR_ERR(clk); } - dss.dss_clk = clk; + dss->dss_clk = clk; - if (dss.feat->parent_clk_name) { - clk = clk_get(NULL, dss.feat->parent_clk_name); + if (dss->feat->parent_clk_name) { + clk = clk_get(NULL, dss->feat->parent_clk_name); if (IS_ERR(clk)) { - DSSERR("Failed to get %s\n", dss.feat->parent_clk_name); + DSSERR("Failed to get %s\n", + dss->feat->parent_clk_name); return PTR_ERR(clk); } } else { clk = NULL; } - dss.parent_clk = clk; + dss->parent_clk = clk; return 0; } -static void dss_put_clocks(void) +static void dss_put_clocks(struct dss_device *dss) { - if (dss.parent_clk) - clk_put(dss.parent_clk); + if (dss->parent_clk) + clk_put(dss->parent_clk); } int dss_runtime_get(struct dss_device *dss) @@ -875,14 +883,16 @@ void dss_runtime_put(struct dss_device *dss) struct dss_device *dss_get_device(struct device *dev) { - return &dss; + return dev_get_drvdata(dev); } /* DEBUGFS */ #if defined(CONFIG_OMAP2_DSS_DEBUGFS) static void dss_debug_dump_clocks(struct seq_file *s) { - dss_dump_clocks(s); + struct dss_device *dss = s->private; + + dss_dump_clocks(dss, s); dispc_dump_clocks(s); #ifdef CONFIG_OMAP2_DSS_DSI dsi_dump_clocks(s); @@ -911,7 +921,7 @@ static const struct file_operations dss_debug_fops = { static struct dentry *dss_debugfs_dir; -static int dss_initialize_debugfs(void) +static int dss_initialize_debugfs(struct dss_device *dss) { dss_debugfs_dir = debugfs_create_dir("omapdss", NULL); if (IS_ERR(dss_debugfs_dir)) { @@ -943,7 +953,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) return PTR_ERR_OR_ZERO(d); } #else /* CONFIG_OMAP2_DSS_DEBUGFS */ -static inline int dss_initialize_debugfs(void) +static inline int dss_initialize_debugfs(struct dss_device *dss) { return 0; } @@ -1148,23 +1158,24 @@ static const struct dss_features dra7xx_dss_feats = { .has_lcd_clk_src = true, }; -static int dss_init_ports(struct platform_device *pdev) +static int dss_init_ports(struct dss_device *dss) { + struct platform_device *pdev = dss->pdev; struct device_node *parent = pdev->dev.of_node; struct device_node *port; int i; - for (i = 0; i < dss.feat->num_ports; i++) { + for (i = 0; i < dss->feat->num_ports; i++) { port = of_graph_get_port_by_id(parent, i); if (!port) continue; - switch (dss.feat->ports[i]) { + switch (dss->feat->ports[i]) { case OMAP_DISPLAY_TYPE_DPI: - dpi_init_port(&dss, pdev, port, dss.feat->model); + dpi_init_port(dss, pdev, port, dss->feat->model); break; case OMAP_DISPLAY_TYPE_SDI: - sdi_init_port(&dss, pdev, port); + sdi_init_port(dss, pdev, port); break; default: break; @@ -1174,18 +1185,19 @@ static int dss_init_ports(struct platform_device *pdev) return 0; } -static void dss_uninit_ports(struct platform_device *pdev) +static void dss_uninit_ports(struct dss_device *dss) { + struct platform_device *pdev = dss->pdev; struct device_node *parent = pdev->dev.of_node; struct device_node *port; int i; - for (i = 0; i < dss.feat->num_ports; i++) { + for (i = 0; i < dss->feat->num_ports; i++) { port = of_graph_get_port_by_id(parent, i); if (!port) continue; - switch (dss.feat->ports[i]) { + switch (dss->feat->ports[i]) { case OMAP_DISPLAY_TYPE_DPI: dpi_uninit_port(port); break; @@ -1198,8 +1210,9 @@ static void dss_uninit_ports(struct platform_device *pdev) } } -static int dss_video_pll_probe(struct platform_device *pdev) +static int dss_video_pll_probe(struct dss_device *dss) { + struct platform_device *pdev = dss->pdev; struct device_node *np = pdev->dev.of_node; struct regulator *pll_regulator; int r; @@ -1208,16 +1221,16 @@ static int dss_video_pll_probe(struct platform_device *pdev) return 0; if (of_property_read_bool(np, "syscon-pll-ctrl")) { - dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np, + dss->syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np, "syscon-pll-ctrl"); - if (IS_ERR(dss.syscon_pll_ctrl)) { + if (IS_ERR(dss->syscon_pll_ctrl)) { dev_err(&pdev->dev, "failed to get syscon-pll-ctrl regmap\n"); - return PTR_ERR(dss.syscon_pll_ctrl); + return PTR_ERR(dss->syscon_pll_ctrl); } if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1, - &dss.syscon_pll_ctrl_offset)) { + &dss->syscon_pll_ctrl_offset)) { dev_err(&pdev->dev, "failed to get syscon-pll-ctrl offset\n"); return -EINVAL; @@ -1243,18 +1256,18 @@ static int dss_video_pll_probe(struct platform_device *pdev) } if (of_property_match_string(np, "reg-names", "pll1") >= 0) { - dss.video1_pll = dss_video_pll_init(&dss, pdev, 0, - pll_regulator); - if (IS_ERR(dss.video1_pll)) - return PTR_ERR(dss.video1_pll); + dss->video1_pll = dss_video_pll_init(dss, pdev, 0, + pll_regulator); + if (IS_ERR(dss->video1_pll)) + return PTR_ERR(dss->video1_pll); } if (of_property_match_string(np, "reg-names", "pll2") >= 0) { - dss.video2_pll = dss_video_pll_init(&dss, pdev, 1, - pll_regulator); - if (IS_ERR(dss.video2_pll)) { - dss_video_pll_uninit(dss.video1_pll); - return PTR_ERR(dss.video2_pll); + dss->video2_pll = dss_video_pll_init(dss, pdev, 1, + pll_regulator); + if (IS_ERR(dss->video2_pll)) { + dss_video_pll_uninit(dss->video1_pll); + return PTR_ERR(dss->video2_pll); } } @@ -1345,14 +1358,14 @@ static int dss_probe_hardware(struct dss_device *dss) dss->dss_clk_rate = clk_get_rate(dss->dss_clk); /* Select DPLL */ - REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); + REG_FLD_MOD(dss, DSS_CONTROL, 0, 0, 0); - dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); + dss_select_dispc_clk_source(dss, DSS_CLK_SRC_FCK); #ifdef CONFIG_OMAP2_DSS_VENC - REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ - REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ - REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ + REG_FLD_MOD(dss, DSS_CONTROL, 1, 4, 4); /* venc dac demen */ + REG_FLD_MOD(dss, DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ + REG_FLD_MOD(dss, DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ #endif dss->dsi_clk_source[0] = DSS_CLK_SRC_FCK; dss->dsi_clk_source[1] = DSS_CLK_SRC_FCK; @@ -1360,7 +1373,7 @@ static int dss_probe_hardware(struct dss_device *dss) dss->lcd_clk_source[0] = DSS_CLK_SRC_FCK; dss->lcd_clk_source[1] = DSS_CLK_SRC_FCK; - rev = dss_read_reg(DSS_REVISION); + rev = dss_read_reg(dss, DSS_REVISION); pr_info("OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); dss_runtime_put(dss); @@ -1373,14 +1386,20 @@ static int dss_probe(struct platform_device *pdev) const struct soc_device_attribute *soc; struct component_match *match = NULL; struct resource *dss_mem; + struct dss_device *dss; int r; - dss.pdev = pdev; + dss = kzalloc(sizeof(*dss), GFP_KERNEL); + if (!dss) + return -ENOMEM; + + dss->pdev = pdev; + platform_set_drvdata(pdev, dss); r = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (r) { dev_err(&pdev->dev, "Failed to set the DMA mask\n"); - return r; + goto err_free_dss; } /* @@ -1389,42 +1408,44 @@ static int dss_probe(struct platform_device *pdev) */ soc = soc_device_match(dss_soc_devices); if (soc) - dss.feat = soc->data; + dss->feat = soc->data; else - dss.feat = of_match_device(dss_of_match, &pdev->dev)->data; + dss->feat = of_match_device(dss_of_match, &pdev->dev)->data; /* Map I/O registers, get and setup clocks. */ dss_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dss.base = devm_ioremap_resource(&pdev->dev, dss_mem); - if (IS_ERR(dss.base)) - return PTR_ERR(dss.base); + dss->base = devm_ioremap_resource(&pdev->dev, dss_mem); + if (IS_ERR(dss->base)) { + r = PTR_ERR(dss->base); + goto err_free_dss; + } - r = dss_get_clocks(); + r = dss_get_clocks(dss); if (r) - return r; + goto err_free_dss; - r = dss_setup_default_clock(); + r = dss_setup_default_clock(dss); if (r) goto err_put_clocks; /* Setup the video PLLs and the DPI and SDI ports. */ - r = dss_video_pll_probe(pdev); + r = dss_video_pll_probe(dss); if (r) goto err_put_clocks; - r = dss_init_ports(pdev); + r = dss_init_ports(dss); if (r) goto err_uninit_plls; /* Enable runtime PM and probe the hardware. */ pm_runtime_enable(&pdev->dev); - r = dss_probe_hardware(&dss); + r = dss_probe_hardware(dss); if (r) goto err_pm_runtime_disable; /* Initialize debugfs. */ - r = dss_initialize_debugfs(); + r = dss_initialize_debugfs(dss); if (r) goto err_pm_runtime_disable; @@ -1444,37 +1465,44 @@ err_uninit_debugfs: err_pm_runtime_disable: pm_runtime_disable(&pdev->dev); - dss_uninit_ports(pdev); + dss_uninit_ports(dss); err_uninit_plls: - if (dss.video1_pll) - dss_video_pll_uninit(dss.video1_pll); - if (dss.video2_pll) - dss_video_pll_uninit(dss.video2_pll); + if (dss->video1_pll) + dss_video_pll_uninit(dss->video1_pll); + if (dss->video2_pll) + dss_video_pll_uninit(dss->video2_pll); err_put_clocks: - dss_put_clocks(); + dss_put_clocks(dss); + +err_free_dss: + kfree(dss); return r; } static int dss_remove(struct platform_device *pdev) { + struct dss_device *dss = platform_get_drvdata(pdev); + component_master_del(&pdev->dev, &dss_component_ops); dss_uninitialize_debugfs(); pm_runtime_disable(&pdev->dev); - dss_uninit_ports(pdev); + dss_uninit_ports(dss); + + if (dss->video1_pll) + dss_video_pll_uninit(dss->video1_pll); - if (dss.video1_pll) - dss_video_pll_uninit(dss.video1_pll); + if (dss->video2_pll) + dss_video_pll_uninit(dss->video2_pll); - if (dss.video2_pll) - dss_video_pll_uninit(dss.video2_pll); + dss_put_clocks(dss); - dss_put_clocks(); + kfree(dss); return 0; } @@ -1496,7 +1524,9 @@ static void dss_shutdown(struct platform_device *pdev) static int dss_runtime_suspend(struct device *dev) { - dss_save_context(); + struct dss_device *dss = dev_get_drvdata(dev); + + dss_save_context(dss); dss_set_min_bus_tput(dev, 0); pinctrl_pm_select_sleep_state(dev); @@ -1506,6 +1536,7 @@ static int dss_runtime_suspend(struct device *dev) static int dss_runtime_resume(struct device *dev) { + struct dss_device *dss = dev_get_drvdata(dev); int r; pinctrl_pm_select_default_state(dev); @@ -1521,7 +1552,7 @@ static int dss_runtime_resume(struct device *dev) if (r) return r; - dss_restore_context(); + dss_restore_context(dss); return 0; } -- cgit v1.2.3 From f33656e1fe5aba0ac0d35e18d90121dd894611ca Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:29 +0200 Subject: drm: omapdrm: dss: Support passing private data to debugfs show handlers To simplify implementation of debugfs seq_file show handlers, the driver passes the pointer to the show function through the debugfs_create_file data pointer. This prevents using the pointer to pass driver private data to the show handler, and requires all handlers to use global variables to access private data. To prepare for the removal of global private data in the driver, rework the debugfs infrastructure to allow passing a private data pointer to show handlers. The price to pay is explicit removal of debugfs files to free the internally allocated memory. This is desirable anyway as debugfs entries should be removed when a component driver is unbound, otherwise crashes will occur due to access to freed memory when the components will be dynamically allocated instead of stored in global variables. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dispc.c | 13 ++++-- drivers/gpu/drm/omapdrm/dss/dsi.c | 40 ++++++++++++----- drivers/gpu/drm/omapdrm/dss/dss.c | 89 ++++++++++++++++++++++++------------- drivers/gpu/drm/omapdrm/dss/dss.h | 31 ++++++++----- drivers/gpu/drm/omapdrm/dss/hdmi.h | 2 + drivers/gpu/drm/omapdrm/dss/hdmi4.c | 9 ++-- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 9 ++-- drivers/gpu/drm/omapdrm/dss/venc.c | 11 +++-- 8 files changed, 141 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 867887151565..3428ffea70ee 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -167,6 +167,8 @@ static struct { void __iomem *base; struct dss_device *dss; + struct dss_debugfs_entry *debugfs; + int irq; irq_handler_t user_handler; void *user_data; @@ -3268,7 +3270,7 @@ void dispc_dump_clocks(struct seq_file *s) dispc_runtime_put(); } -static void dispc_dump_regs(struct seq_file *s) +static int dispc_dump_regs(struct seq_file *s, void *p) { int i, j; const char *mgr_names[] = { @@ -3289,7 +3291,7 @@ static void dispc_dump_regs(struct seq_file *s) #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r)) if (dispc_runtime_get()) - return; + return 0; /* DISPC common registers */ DUMPREG(DISPC_REVISION); @@ -3461,6 +3463,8 @@ static void dispc_dump_regs(struct seq_file *s) #undef DISPC_REG #undef DUMPREG + + return 0; } /* calculate clock rates using dividers in cinfo */ @@ -4620,7 +4624,8 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) dispc_set_ops(&dispc_ops); - dss_debugfs_create_file("dispc", dispc_dump_regs); + dispc.debugfs = dss_debugfs_create_file("dispc", dispc_dump_regs, + &dispc); return 0; @@ -4632,6 +4637,8 @@ err_runtime_get: static void dispc_unbind(struct device *dev, struct device *master, void *data) { + dss_debugfs_remove_file(dispc.debugfs); + dispc_set_ops(NULL); pm_runtime_disable(dev); diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 26f4122f6784..a676d27dd479 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -401,6 +401,10 @@ struct dsi_data { #endif int debug_read; int debug_write; + struct { + struct dss_debugfs_entry *irqs; + struct dss_debugfs_entry *regs; + } debugfs; #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS spinlock_t irq_stats_lock; @@ -1660,18 +1664,20 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, #undef PIS } -static void dsi1_dump_irqs(struct seq_file *s) +static int dsi1_dump_irqs(struct seq_file *s, void *p) { struct platform_device *dsidev = dsi_get_dsidev_from_id(0); dsi_dump_dsidev_irqs(dsidev, s); + return 0; } -static void dsi2_dump_irqs(struct seq_file *s) +static int dsi2_dump_irqs(struct seq_file *s, void *p) { struct platform_device *dsidev = dsi_get_dsidev_from_id(1); dsi_dump_dsidev_irqs(dsidev, s); + return 0; } #endif @@ -1759,18 +1765,20 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, #undef DUMPREG } -static void dsi1_dump_regs(struct seq_file *s) +static int dsi1_dump_regs(struct seq_file *s, void *p) { struct platform_device *dsidev = dsi_get_dsidev_from_id(0); dsi_dump_dsidev_regs(dsidev, s); + return 0; } -static void dsi2_dump_regs(struct seq_file *s) +static int dsi2_dump_regs(struct seq_file *s, void *p) { struct platform_device *dsidev = dsi_get_dsidev_from_id(1); dsi_dump_dsidev_regs(dsidev, s); + return 0; } enum dsi_cio_power_state { @@ -5569,15 +5577,22 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) dsi_runtime_put(dsidev); if (dsi->module_id == 0) - dss_debugfs_create_file("dsi1_regs", dsi1_dump_regs); - else if (dsi->module_id == 1) - dss_debugfs_create_file("dsi2_regs", dsi2_dump_regs); - + dsi->debugfs.regs = dss_debugfs_create_file("dsi1_regs", + dsi1_dump_regs, + &dsi); + else + dsi->debugfs.regs = dss_debugfs_create_file("dsi2_regs", + dsi2_dump_regs, + &dsi); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS if (dsi->module_id == 0) - dss_debugfs_create_file("dsi1_irqs", dsi1_dump_irqs); - else if (dsi->module_id == 1) - dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs); + dsi->debugfs.irqs = dss_debugfs_create_file("dsi1_irqs", + dsi1_dump_irqs, + &dsi); + else + dsi->debugfs.irqs = dss_debugfs_create_file("dsi2_irqs", + dsi2_dump_irqs, + &dsi); #endif return 0; @@ -5596,6 +5611,9 @@ static void dsi_unbind(struct device *dev, struct device *master, void *data) struct platform_device *dsidev = to_platform_device(dev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + dss_debugfs_remove_file(dsi->debugfs.irqs); + dss_debugfs_remove_file(dsi->debugfs.regs); + of_platform_depopulate(&dsidev->dev); WARN_ON(dsi->scp_clk_refcount > 0); diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 4b00faa1a8cc..14a86e2c6d83 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -365,14 +365,14 @@ static void dss_dump_clocks(struct dss_device *dss, struct seq_file *s) } #endif -static void dss_dump_regs(struct seq_file *s) +static int dss_dump_regs(struct seq_file *s, void *p) { struct dss_device *dss = s->private; #define DUMPREG(dss, r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(dss, r)) if (dss_runtime_get(dss)) - return; + return 0; DUMPREG(dss, DSS_REVISION); DUMPREG(dss, DSS_SYSCONFIG); @@ -387,6 +387,7 @@ static void dss_dump_regs(struct seq_file *s) dss_runtime_put(dss); #undef DUMPREG + return 0; } static int dss_get_channel_index(enum omap_channel channel) @@ -888,7 +889,7 @@ struct dss_device *dss_get_device(struct device *dev) /* DEBUGFS */ #if defined(CONFIG_OMAP2_DSS_DEBUGFS) -static void dss_debug_dump_clocks(struct seq_file *s) +static int dss_debug_dump_clocks(struct seq_file *s, void *p) { struct dss_device *dss = s->private; @@ -897,28 +898,9 @@ static void dss_debug_dump_clocks(struct seq_file *s) #ifdef CONFIG_OMAP2_DSS_DSI dsi_dump_clocks(s); #endif -} - -static int dss_debug_show(struct seq_file *s, void *unused) -{ - void (*func)(struct seq_file *) = s->private; - - func(s); return 0; } -static int dss_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, dss_debug_show, inode->i_private); -} - -static const struct file_operations dss_debug_fops = { - .open = dss_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static struct dentry *dss_debugfs_dir; static int dss_initialize_debugfs(struct dss_device *dss) @@ -931,9 +913,6 @@ static int dss_initialize_debugfs(struct dss_device *dss) return err; } - debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, - &dss_debug_dump_clocks, &dss_debug_fops); - return 0; } @@ -943,15 +922,59 @@ static void dss_uninitialize_debugfs(void) debugfs_remove_recursive(dss_debugfs_dir); } -int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) +struct dss_debugfs_entry { + struct dentry *dentry; + int (*show_fn)(struct seq_file *s, void *data); + void *data; +}; + +static int dss_debug_open(struct inode *inode, struct file *file) +{ + struct dss_debugfs_entry *entry = inode->i_private; + + return single_open(file, entry->show_fn, entry->data); +} + +static const struct file_operations dss_debug_fops = { + .open = dss_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +struct dss_debugfs_entry *dss_debugfs_create_file(const char *name, + int (*show_fn)(struct seq_file *s, void *data), void *data) { + struct dss_debugfs_entry *entry; struct dentry *d; - d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir, - write, &dss_debug_fops); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return ERR_PTR(-ENOMEM); + + entry->show_fn = show_fn; + entry->data = data; - return PTR_ERR_OR_ZERO(d); + d = debugfs_create_file(name, 0444, dss_debugfs_dir, entry, + &dss_debug_fops); + if (IS_ERR(d)) { + kfree(entry); + return ERR_PTR(PTR_ERR(d)); + } + + entry->dentry = d; + return entry; +} + +void dss_debugfs_remove_file(struct dss_debugfs_entry *entry) +{ + if (IS_ERR_OR_NULL(entry)) + return; + + debugfs_remove(entry->dentry); + kfree(entry); } + #else /* CONFIG_OMAP2_DSS_DEBUGFS */ static inline int dss_initialize_debugfs(struct dss_device *dss) { @@ -1449,7 +1472,9 @@ static int dss_probe(struct platform_device *pdev) if (r) goto err_pm_runtime_disable; - dss_debugfs_create_file("dss", dss_dump_regs); + dss->debugfs.clk = dss_debugfs_create_file("clk", dss_debug_dump_clocks, + dss); + dss->debugfs.dss = dss_debugfs_create_file("dss", dss_dump_regs, dss); /* Add all the child devices as components. */ device_for_each_child(&pdev->dev, &match, dss_add_child_component); @@ -1461,6 +1486,8 @@ static int dss_probe(struct platform_device *pdev) return 0; err_uninit_debugfs: + dss_debugfs_remove_file(dss->debugfs.clk); + dss_debugfs_remove_file(dss->debugfs.dss); dss_uninitialize_debugfs(); err_pm_runtime_disable: @@ -1488,6 +1515,8 @@ static int dss_remove(struct platform_device *pdev) component_master_del(&pdev->dev, &dss_component_ops); + dss_debugfs_remove_file(dss->debugfs.clk); + dss_debugfs_remove_file(dss->debugfs.dss); dss_uninitialize_debugfs(); pm_runtime_disable(&pdev->dev); diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 89d708e8e970..ec8e40e09141 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -25,6 +25,10 @@ #include "omapdss.h" +struct dss_debugfs_entry; +struct platform_device; +struct seq_file; + #define MAX_DSS_LCD_MANAGERS 3 #define MAX_NUM_DSI 2 @@ -233,9 +237,6 @@ struct dss_lcd_mgr_config { int lcden_sig_polarity; }; -struct seq_file; -struct platform_device; - #define DSS_SZ_REGS SZ_512 struct dss_device { @@ -261,6 +262,11 @@ struct dss_device { const struct dss_features *feat; + struct { + struct dss_debugfs_entry *clk; + struct dss_debugfs_entry *dss; + } debugfs; + struct dss_pll *video1_pll; struct dss_pll *video2_pll; }; @@ -283,12 +289,20 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id) /* DSS */ #if defined(CONFIG_OMAP2_DSS_DEBUGFS) -int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)); +struct dss_debugfs_entry *dss_debugfs_create_file(const char *name, + int (*show_fn)(struct seq_file *s, void *data), void *data); +void dss_debugfs_remove_file(struct dss_debugfs_entry *entry); #else -static inline int dss_debugfs_create_file(const char *name, - void (*write)(struct seq_file *)) +static inline struct dss_debugfs_entry * +dss_debugfs_create_file(const char *name, + int (*show_fn)(struct seq_file *s, void *data), + void *data) +{ + return NULL; +} + +static inline void dss_debugfs_remove_file(struct dss_debugfs_entry *entry) { - return 0; } #endif /* CONFIG_OMAP2_DSS_DEBUGFS */ @@ -360,9 +374,6 @@ static inline void sdi_uninit_port(struct device_node *port) #ifdef CONFIG_OMAP2_DSS_DSI -struct dentry; -struct file_operations; - void dsi_dump_clocks(struct seq_file *s); void dsi_irq_handler(void); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h index 0563e1955048..fa2fbdaa427c 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h @@ -361,6 +361,8 @@ struct omap_hdmi { struct platform_device *pdev; struct dss_device *dss; + struct dss_debugfs_entry *debugfs; + struct hdmi_wp_data wp; struct hdmi_pll_data pll; struct hdmi_phy_data phy; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 3e4a5cf2d06f..e528b7a223e1 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -303,13 +303,13 @@ static void hdmi_display_get_timings(struct omap_dss_device *dssdev, *vm = hdmi.cfg.vm; } -static void hdmi_dump_regs(struct seq_file *s) +static int hdmi_dump_regs(struct seq_file *s, void *p) { mutex_lock(&hdmi.lock); if (hdmi_runtime_get()) { mutex_unlock(&hdmi.lock); - return; + return 0; } hdmi_wp_dump(&hdmi.wp, s); @@ -319,6 +319,7 @@ static void hdmi_dump_regs(struct seq_file *s) hdmi_runtime_put(); mutex_unlock(&hdmi.lock); + return 0; } static int read_edid(u8 *buf, int len) @@ -779,7 +780,7 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data) return r; } - dss_debugfs_create_file("hdmi", hdmi_dump_regs); + hdmi.debugfs = dss_debugfs_create_file("hdmi", hdmi_dump_regs, &hdmi); return 0; err: @@ -791,6 +792,8 @@ static void hdmi4_unbind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); + dss_debugfs_remove_file(hdmi.debugfs); + if (hdmi.audio_pdev) platform_device_unregister(hdmi.audio_pdev); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index e7a71012b1cd..b3b9d17eb0e2 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -299,13 +299,13 @@ static void hdmi_display_get_timings(struct omap_dss_device *dssdev, *vm = hdmi.cfg.vm; } -static void hdmi_dump_regs(struct seq_file *s) +static int hdmi_dump_regs(struct seq_file *s, void *p) { mutex_lock(&hdmi.lock); if (hdmi_runtime_get()) { mutex_unlock(&hdmi.lock); - return; + return 0; } hdmi_wp_dump(&hdmi.wp, s); @@ -315,6 +315,7 @@ static void hdmi_dump_regs(struct seq_file *s) hdmi_runtime_put(); mutex_unlock(&hdmi.lock); + return 0; } static int read_edid(u8 *buf, int len) @@ -776,7 +777,7 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data) return r; } - dss_debugfs_create_file("hdmi", hdmi_dump_regs); + hdmi.debugfs = dss_debugfs_create_file("hdmi", hdmi_dump_regs, &hdmi); return 0; err: @@ -788,6 +789,8 @@ static void hdmi5_unbind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); + dss_debugfs_remove_file(hdmi.debugfs); + if (hdmi.audio_pdev) platform_device_unregister(hdmi.audio_pdev); diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 08bae18be188..967a192e1789 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -327,6 +327,8 @@ static struct { struct regulator *vdda_dac_reg; struct dss_device *dss; + struct dss_debugfs_entry *debugfs; + struct clk *tv_dac_clk; struct videomode vm; @@ -670,12 +672,12 @@ static int venc_init_regulator(void) return 0; } -static void venc_dump_regs(struct seq_file *s) +static int venc_dump_regs(struct seq_file *s, void *p) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) if (venc_runtime_get()) - return; + return 0; DUMPREG(VENC_F_CONTROL); DUMPREG(VENC_VIDOUT_CTRL); @@ -722,6 +724,7 @@ static void venc_dump_regs(struct seq_file *s) venc_runtime_put(); #undef DUMPREG + return 0; } static int venc_get_clocks(struct platform_device *pdev) @@ -914,7 +917,7 @@ static int venc_bind(struct device *dev, struct device *master, void *data) goto err_probe_of; } - dss_debugfs_create_file("venc", venc_dump_regs); + venc.debugfs = dss_debugfs_create_file("venc", venc_dump_regs, &venc); venc_init_output(pdev); @@ -930,6 +933,8 @@ static void venc_unbind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); + dss_debugfs_remove_file(venc.debugfs); + venc_uninit_output(pdev); pm_runtime_disable(&pdev->dev); -- cgit v1.2.3 From 798957aedbde21c6418c419708b765b102b341c7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:30 +0200 Subject: drm: omapdrm: dss: Store the registered plls array in struct dss_device As part of an effort to remove the usage of global variables in the driver, store the registered plls array in the dss_device structure instead of a global variable. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dispc.c | 4 ++-- drivers/gpu/drm/omapdrm/dss/dpi.c | 17 +++++++------- drivers/gpu/drm/omapdrm/dss/dsi.c | 3 +-- drivers/gpu/drm/omapdrm/dss/dss.h | 8 ++++--- drivers/gpu/drm/omapdrm/dss/hdmi_pll.c | 3 +-- drivers/gpu/drm/omapdrm/dss/pll.c | 40 +++++++++++++++++---------------- drivers/gpu/drm/omapdrm/dss/video-pll.c | 3 +-- 7 files changed, 40 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 3428ffea70ee..285d297db229 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -3123,7 +3123,7 @@ static unsigned long dispc_fclk_rate(void) struct dss_pll *pll; unsigned int clkout_idx; - pll = dss_pll_find_by_src(src); + pll = dss_pll_find_by_src(dispc.dss, src); clkout_idx = dss_pll_get_clkout_idx_for_src(src); r = pll->cinfo.clkout[clkout_idx]; @@ -3150,7 +3150,7 @@ static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) struct dss_pll *pll; unsigned int clkout_idx; - pll = dss_pll_find_by_src(src); + pll = dss_pll_find_by_src(dispc.dss, src); clkout_idx = dss_pll_get_clkout_idx_for_src(src); r = pll->cinfo.clkout[clkout_idx]; diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index ba5adfb7ee70..338ceb1ba61b 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -58,7 +58,8 @@ static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev) return container_of(dssdev, struct dpi_data, output); } -static enum dss_clk_source dpi_get_clk_src_dra7xx(enum omap_channel channel) +static enum dss_clk_source dpi_get_clk_src_dra7xx(struct dpi_data *dpi, + enum omap_channel channel) { /* * Possible clock sources: @@ -70,23 +71,23 @@ static enum dss_clk_source dpi_get_clk_src_dra7xx(enum omap_channel channel) switch (channel) { case OMAP_DSS_CHANNEL_LCD: { - if (dss_pll_find_by_src(DSS_CLK_SRC_PLL1_1)) + if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_1)) return DSS_CLK_SRC_PLL1_1; break; } case OMAP_DSS_CHANNEL_LCD2: { - if (dss_pll_find_by_src(DSS_CLK_SRC_PLL1_3)) + if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3)) return DSS_CLK_SRC_PLL1_3; - if (dss_pll_find_by_src(DSS_CLK_SRC_PLL2_3)) + if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_3)) return DSS_CLK_SRC_PLL2_3; break; } case OMAP_DSS_CHANNEL_LCD3: { - if (dss_pll_find_by_src(DSS_CLK_SRC_PLL2_1)) + if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_1)) return DSS_CLK_SRC_PLL2_1; - if (dss_pll_find_by_src(DSS_CLK_SRC_PLL1_3)) + if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3)) return DSS_CLK_SRC_PLL1_3; break; } @@ -133,7 +134,7 @@ static enum dss_clk_source dpi_get_clk_src(struct dpi_data *dpi) } case DSS_MODEL_DRA7: - return dpi_get_clk_src_dra7xx(channel); + return dpi_get_clk_src_dra7xx(dpi, channel); default: return DSS_CLK_SRC_FCK; @@ -605,7 +606,7 @@ static void dpi_init_pll(struct dpi_data *dpi) dpi->clk_src = dpi_get_clk_src(dpi); - pll = dss_pll_find_by_src(dpi->clk_src); + pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src); if (!pll) return; diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index a676d27dd479..448986031a6a 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -5353,9 +5353,8 @@ static int dsi_init_pll_data(struct dss_device *dss, pll->base = dsi->pll_base; pll->hw = dsi->data->pll_hw; pll->ops = &dsi_pll_ops; - pll->dss = dss; - r = dss_pll_register(pll); + r = dss_pll_register(dss, pll); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index ec8e40e09141..8cc4b6ca203e 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -267,6 +267,7 @@ struct dss_device { struct dss_debugfs_entry *dss; } debugfs; + struct dss_pll *plls[4]; struct dss_pll *video1_pll; struct dss_pll *video2_pll; }; @@ -458,10 +459,11 @@ typedef bool (*dss_pll_calc_func)(int n, int m, unsigned long fint, typedef bool (*dss_hsdiv_calc_func)(int m_dispc, unsigned long dispc, void *data); -int dss_pll_register(struct dss_pll *pll); +int dss_pll_register(struct dss_device *dss, struct dss_pll *pll); void dss_pll_unregister(struct dss_pll *pll); -struct dss_pll *dss_pll_find(const char *name); -struct dss_pll *dss_pll_find_by_src(enum dss_clk_source src); +struct dss_pll *dss_pll_find(struct dss_device *dss, const char *name); +struct dss_pll *dss_pll_find_by_src(struct dss_device *dss, + enum dss_clk_source src); unsigned int dss_pll_get_clkout_idx_for_src(enum dss_clk_source src); int dss_pll_enable(struct dss_pll *pll); void dss_pll_disable(struct dss_pll *pll); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c index 4fb97cd0cc8d..e7be3707d147 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c @@ -146,7 +146,6 @@ static int hdmi_init_pll_data(struct dss_device *dss, pll->id = DSS_PLL_HDMI; pll->base = hpll->base; pll->clkin = clk; - pll->dss = dss; if (hpll->wp->version == 4) pll->hw = &dss_omap4_hdmi_pll_hw; @@ -155,7 +154,7 @@ static int hdmi_init_pll_data(struct dss_device *dss, pll->ops = &hdmi_pll_ops; - r = dss_pll_register(pll); + r = dss_pll_register(dss, pll); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/pll.c b/drivers/gpu/drm/omapdrm/dss/pll.c index ecb03277d831..078b0e8216c3 100644 --- a/drivers/gpu/drm/omapdrm/dss/pll.c +++ b/drivers/gpu/drm/omapdrm/dss/pll.c @@ -35,15 +35,14 @@ #define PLL_SSC_CONFIGURATION2 0x001C #define PLL_CONFIGURATION4 0x0020 -static struct dss_pll *dss_plls[4]; - -int dss_pll_register(struct dss_pll *pll) +int dss_pll_register(struct dss_device *dss, struct dss_pll *pll) { int i; - for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) { - if (!dss_plls[i]) { - dss_plls[i] = pll; + for (i = 0; i < ARRAY_SIZE(dss->plls); ++i) { + if (!dss->plls[i]) { + dss->plls[i] = pll; + pll->dss = dss; return 0; } } @@ -53,29 +52,32 @@ int dss_pll_register(struct dss_pll *pll) void dss_pll_unregister(struct dss_pll *pll) { + struct dss_device *dss = pll->dss; int i; - for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) { - if (dss_plls[i] == pll) { - dss_plls[i] = NULL; + for (i = 0; i < ARRAY_SIZE(dss->plls); ++i) { + if (dss->plls[i] == pll) { + dss->plls[i] = NULL; + pll->dss = NULL; return; } } } -struct dss_pll *dss_pll_find(const char *name) +struct dss_pll *dss_pll_find(struct dss_device *dss, const char *name) { int i; - for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) { - if (dss_plls[i] && strcmp(dss_plls[i]->name, name) == 0) - return dss_plls[i]; + for (i = 0; i < ARRAY_SIZE(dss->plls); ++i) { + if (dss->plls[i] && strcmp(dss->plls[i]->name, name) == 0) + return dss->plls[i]; } return NULL; } -struct dss_pll *dss_pll_find_by_src(enum dss_clk_source src) +struct dss_pll *dss_pll_find_by_src(struct dss_device *dss, + enum dss_clk_source src) { struct dss_pll *pll; @@ -85,22 +87,22 @@ struct dss_pll *dss_pll_find_by_src(enum dss_clk_source src) return NULL; case DSS_CLK_SRC_HDMI_PLL: - return dss_pll_find("hdmi"); + return dss_pll_find(dss, "hdmi"); case DSS_CLK_SRC_PLL1_1: case DSS_CLK_SRC_PLL1_2: case DSS_CLK_SRC_PLL1_3: - pll = dss_pll_find("dsi0"); + pll = dss_pll_find(dss, "dsi0"); if (!pll) - pll = dss_pll_find("video0"); + pll = dss_pll_find(dss, "video0"); return pll; case DSS_CLK_SRC_PLL2_1: case DSS_CLK_SRC_PLL2_2: case DSS_CLK_SRC_PLL2_3: - pll = dss_pll_find("dsi1"); + pll = dss_pll_find(dss, "dsi1"); if (!pll) - pll = dss_pll_find("video1"); + pll = dss_pll_find(dss, "video1"); return pll; } } diff --git a/drivers/gpu/drm/omapdrm/dss/video-pll.c b/drivers/gpu/drm/omapdrm/dss/video-pll.c index 344e7e0bbc4e..585ed94ccf17 100644 --- a/drivers/gpu/drm/omapdrm/dss/video-pll.c +++ b/drivers/gpu/drm/omapdrm/dss/video-pll.c @@ -190,9 +190,8 @@ struct dss_pll *dss_video_pll_init(struct dss_device *dss, pll->base = pll_base; pll->hw = &dss_dra7_video_pll_hw; pll->ops = &dss_pll_ops; - pll->dss = dss; - r = dss_pll_register(pll); + r = dss_pll_register(dss, pll); if (r) return ERR_PTR(r); -- cgit v1.2.3 From 1c4b92ee00734766967f5aa425767923c747f9c6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:31 +0200 Subject: drm: omapdrm: dss: Store the debugfs root directory in struct dss_device As part of an effort to remove the usage of global variables in the driver, store the debugfs root directory in the dss_device structure instead of a global variable. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dispc.c | 2 +- drivers/gpu/drm/omapdrm/dss/dsi.c | 8 ++++---- drivers/gpu/drm/omapdrm/dss/dss.c | 38 ++++++++++++++++++------------------- drivers/gpu/drm/omapdrm/dss/dss.h | 9 ++++++--- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 3 ++- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 3 ++- drivers/gpu/drm/omapdrm/dss/venc.c | 3 ++- 7 files changed, 36 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 285d297db229..8019cc9f4f97 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -4624,7 +4624,7 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) dispc_set_ops(&dispc_ops); - dispc.debugfs = dss_debugfs_create_file("dispc", dispc_dump_regs, + dispc.debugfs = dss_debugfs_create_file(dss, "dispc", dispc_dump_regs, &dispc); return 0; diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 448986031a6a..05030dc25c72 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -5576,20 +5576,20 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) dsi_runtime_put(dsidev); if (dsi->module_id == 0) - dsi->debugfs.regs = dss_debugfs_create_file("dsi1_regs", + dsi->debugfs.regs = dss_debugfs_create_file(dss, "dsi1_regs", dsi1_dump_regs, &dsi); else - dsi->debugfs.regs = dss_debugfs_create_file("dsi2_regs", + dsi->debugfs.regs = dss_debugfs_create_file(dss, "dsi2_regs", dsi2_dump_regs, &dsi); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS if (dsi->module_id == 0) - dsi->debugfs.irqs = dss_debugfs_create_file("dsi1_irqs", + dsi->debugfs.irqs = dss_debugfs_create_file(dss, "dsi1_irqs", dsi1_dump_irqs, &dsi); else - dsi->debugfs.irqs = dss_debugfs_create_file("dsi2_irqs", + dsi->debugfs.irqs = dss_debugfs_create_file(dss, "dsi2_irqs", dsi2_dump_irqs, &dsi); #endif diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 14a86e2c6d83..7a5f5f233ad0 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -901,25 +901,22 @@ static int dss_debug_dump_clocks(struct seq_file *s, void *p) return 0; } -static struct dentry *dss_debugfs_dir; - static int dss_initialize_debugfs(struct dss_device *dss) { - dss_debugfs_dir = debugfs_create_dir("omapdss", NULL); - if (IS_ERR(dss_debugfs_dir)) { - int err = PTR_ERR(dss_debugfs_dir); + struct dentry *dir; - dss_debugfs_dir = NULL; - return err; - } + dir = debugfs_create_dir("omapdss", NULL); + if (IS_ERR(dir)) + return PTR_ERR(dir); + + dss->debugfs.root = dir; return 0; } -static void dss_uninitialize_debugfs(void) +static void dss_uninitialize_debugfs(struct dss_device *dss) { - if (dss_debugfs_dir) - debugfs_remove_recursive(dss_debugfs_dir); + debugfs_remove_recursive(dss->debugfs.root); } struct dss_debugfs_entry { @@ -942,8 +939,10 @@ static const struct file_operations dss_debug_fops = { .release = single_release, }; -struct dss_debugfs_entry *dss_debugfs_create_file(const char *name, - int (*show_fn)(struct seq_file *s, void *data), void *data) +struct dss_debugfs_entry * +dss_debugfs_create_file(struct dss_device *dss, const char *name, + int (*show_fn)(struct seq_file *s, void *data), + void *data) { struct dss_debugfs_entry *entry; struct dentry *d; @@ -955,7 +954,7 @@ struct dss_debugfs_entry *dss_debugfs_create_file(const char *name, entry->show_fn = show_fn; entry->data = data; - d = debugfs_create_file(name, 0444, dss_debugfs_dir, entry, + d = debugfs_create_file(name, 0444, dss->debugfs.root, entry, &dss_debug_fops); if (IS_ERR(d)) { kfree(entry); @@ -980,7 +979,7 @@ static inline int dss_initialize_debugfs(struct dss_device *dss) { return 0; } -static inline void dss_uninitialize_debugfs(void) +static inline void dss_uninitialize_debugfs(struct dss_device *dss) { } #endif /* CONFIG_OMAP2_DSS_DEBUGFS */ @@ -1472,9 +1471,10 @@ static int dss_probe(struct platform_device *pdev) if (r) goto err_pm_runtime_disable; - dss->debugfs.clk = dss_debugfs_create_file("clk", dss_debug_dump_clocks, + dss->debugfs.clk = dss_debugfs_create_file(dss, "clk", + dss_debug_dump_clocks, dss); + dss->debugfs.dss = dss_debugfs_create_file(dss, "dss", dss_dump_regs, dss); - dss->debugfs.dss = dss_debugfs_create_file("dss", dss_dump_regs, dss); /* Add all the child devices as components. */ device_for_each_child(&pdev->dev, &match, dss_add_child_component); @@ -1488,7 +1488,7 @@ static int dss_probe(struct platform_device *pdev) err_uninit_debugfs: dss_debugfs_remove_file(dss->debugfs.clk); dss_debugfs_remove_file(dss->debugfs.dss); - dss_uninitialize_debugfs(); + dss_uninitialize_debugfs(dss); err_pm_runtime_disable: pm_runtime_disable(&pdev->dev); @@ -1517,7 +1517,7 @@ static int dss_remove(struct platform_device *pdev) dss_debugfs_remove_file(dss->debugfs.clk); dss_debugfs_remove_file(dss->debugfs.dss); - dss_uninitialize_debugfs(); + dss_uninitialize_debugfs(dss); pm_runtime_disable(&pdev->dev); diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 8cc4b6ca203e..764c52025a27 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -263,6 +263,7 @@ struct dss_device { const struct dss_features *feat; struct { + struct dentry *root; struct dss_debugfs_entry *clk; struct dss_debugfs_entry *dss; } debugfs; @@ -290,12 +291,14 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id) /* DSS */ #if defined(CONFIG_OMAP2_DSS_DEBUGFS) -struct dss_debugfs_entry *dss_debugfs_create_file(const char *name, - int (*show_fn)(struct seq_file *s, void *data), void *data); +struct dss_debugfs_entry * +dss_debugfs_create_file(struct dss_device *dss, const char *name, + int (*show_fn)(struct seq_file *s, void *data), + void *data); void dss_debugfs_remove_file(struct dss_debugfs_entry *entry); #else static inline struct dss_debugfs_entry * -dss_debugfs_create_file(const char *name, +dss_debugfs_create_file(struct dss_device *dss, const char *name, int (*show_fn)(struct seq_file *s, void *data), void *data) { diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index e528b7a223e1..48608ebfeb0c 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -780,7 +780,8 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data) return r; } - hdmi.debugfs = dss_debugfs_create_file("hdmi", hdmi_dump_regs, &hdmi); + hdmi.debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs, + &hdmi); return 0; err: diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index b3b9d17eb0e2..8ede19c3d8e7 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -777,7 +777,8 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data) return r; } - hdmi.debugfs = dss_debugfs_create_file("hdmi", hdmi_dump_regs, &hdmi); + hdmi.debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs, + &hdmi); return 0; err: diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 967a192e1789..ed756d4c7210 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -917,7 +917,8 @@ static int venc_bind(struct device *dev, struct device *master, void *data) goto err_probe_of; } - venc.debugfs = dss_debugfs_create_file("venc", venc_dump_regs, &venc); + venc.debugfs = dss_debugfs_create_file(dss, "venc", venc_dump_regs, + &venc); venc_init_output(pdev); -- cgit v1.2.3 From b40d0ed647a2d96da38760d0429450936030fd85 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:32 +0200 Subject: drm: omapdrm: dss: Don't unnecessarily cast to dev to pdev and back The dss_unbind() function casts the struct device pointer to a struct platform_device, only to later use the struct device pointer from platform_device. Don't cast at all. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dss.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 7a5f5f233ad0..14d2f024eb70 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1332,11 +1332,9 @@ static int dss_bind(struct device *dev) static void dss_unbind(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - omapdss_set_is_initialized(false); - component_unbind_all(&pdev->dev, NULL); + component_unbind_all(dev, NULL); } static const struct component_master_ops dss_component_ops = { -- cgit v1.2.3 From 7093d6cd1fb39efbc014f209eab0bc7a21e08811 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:33 +0200 Subject: drm: omapdrm: dsi: Pass the dsi_data pointer to internal functions Internal dsi functions take a pointer to the DSI platform_device and then cast it to a dsi_data pointer. That's pointless as the caller already has the dsi_data pointer. Pass it directly instead of the platform_device pointer. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dsi.c | 1228 +++++++++++++++++-------------------- 1 file changed, 564 insertions(+), 664 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 05030dc25c72..7b5656e6abbb 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -119,11 +119,11 @@ struct dsi_reg { u16 module; u16 idx; }; #define DSI_PLL_CONFIGURATION1 DSI_REG(DSI_PLL, 0x000C) #define DSI_PLL_CONFIGURATION2 DSI_REG(DSI_PLL, 0x0010) -#define REG_GET(dsidev, idx, start, end) \ - FLD_GET(dsi_read_reg(dsidev, idx), start, end) +#define REG_GET(dsi, idx, start, end) \ + FLD_GET(dsi_read_reg(dsi, idx), start, end) -#define REG_FLD_MOD(dsidev, idx, val, start, end) \ - dsi_write_reg(dsidev, idx, FLD_MOD(dsi_read_reg(dsidev, idx), val, start, end)) +#define REG_FLD_MOD(dsi, idx, val, start, end) \ + dsi_write_reg(dsi, idx, FLD_MOD(dsi_read_reg(dsi, idx), val, start, end)) /* Global interrupts */ #define DSI_IRQ_VC0 (1 << 0) @@ -213,13 +213,14 @@ struct dsi_reg { u16 module; u16 idx; }; DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5) typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); +struct dsi_data; -static int dsi_display_init_dispc(struct platform_device *dsidev, +static int dsi_display_init_dispc(struct dsi_data *dsi, enum omap_channel channel); -static void dsi_display_uninit_dispc(struct platform_device *dsidev, +static void dsi_display_uninit_dispc(struct dsi_data *dsi, enum omap_channel channel); -static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel); +static int dsi_vc_send_null(struct dsi_data *dsi, int channel); /* DSI PLL HSDIV indices */ #define HSDIV_DISPC 0 @@ -282,7 +283,7 @@ struct dsi_isr_tables { }; struct dsi_clk_calc_ctx { - struct platform_device *dsidev; + struct dsi_data *dsi; struct dss_pll *pll; /* inputs */ @@ -429,7 +430,7 @@ struct dsi_data { }; struct dsi_packet_sent_handler_data { - struct platform_device *dsidev; + struct dsi_data *dsi; struct completion *completion; }; @@ -448,7 +449,7 @@ static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss return to_platform_device(dssdev->dev); } -static struct platform_device *dsi_get_dsidev_from_id(int module) +static struct dsi_data *dsi_get_dsi_from_id(int module) { struct omap_dss_device *out; enum omap_dss_output_id id; @@ -466,13 +467,12 @@ static struct platform_device *dsi_get_dsidev_from_id(int module) out = omap_dss_get_output(id); - return out ? to_platform_device(out->dev) : NULL; + return out ? dsi_get_dsidrv_data(to_platform_device(out->dev)) : NULL; } -static inline void dsi_write_reg(struct platform_device *dsidev, - const struct dsi_reg idx, u32 val) +static inline void dsi_write_reg(struct dsi_data *dsi, + const struct dsi_reg idx, u32 val) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); void __iomem *base; switch(idx.module) { @@ -485,10 +485,8 @@ static inline void dsi_write_reg(struct platform_device *dsidev, __raw_writel(val, base + idx.idx); } -static inline u32 dsi_read_reg(struct platform_device *dsidev, - const struct dsi_reg idx) +static inline u32 dsi_read_reg(struct dsi_data *dsi, const struct dsi_reg idx) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); void __iomem *base; switch(idx.module) { @@ -517,10 +515,8 @@ static void dsi_bus_unlock(struct omap_dss_device *dssdev) up(&dsi->bus_lock); } -static bool dsi_bus_is_locked(struct platform_device *dsidev) +static bool dsi_bus_is_locked(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - return dsi->bus_lock.count == 0; } @@ -529,8 +525,9 @@ static void dsi_completion_handler(void *data, u32 mask) complete((struct completion *)data); } -static inline bool wait_for_bit_change(struct platform_device *dsidev, - const struct dsi_reg idx, int bitnum, int value) +static inline bool wait_for_bit_change(struct dsi_data *dsi, + const struct dsi_reg idx, + int bitnum, int value) { unsigned long timeout; ktime_t wait; @@ -539,14 +536,14 @@ static inline bool wait_for_bit_change(struct platform_device *dsidev, /* first busyloop to see if the bit changes right away */ t = 100; while (t-- > 0) { - if (REG_GET(dsidev, idx, bitnum, bitnum) == value) + if (REG_GET(dsi, idx, bitnum, bitnum) == value) return true; } /* then loop for 500ms, sleeping for 1ms in between */ timeout = jiffies + msecs_to_jiffies(500); while (time_before(jiffies, timeout)) { - if (REG_GET(dsidev, idx, bitnum, bitnum) == value) + if (REG_GET(dsi, idx, bitnum, bitnum) == value) return true; wait = ns_to_ktime(1000 * 1000); @@ -574,21 +571,18 @@ static u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) } #ifdef DSI_PERF_MEASURE -static void dsi_perf_mark_setup(struct platform_device *dsidev) +static void dsi_perf_mark_setup(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); dsi->perf_setup_time = ktime_get(); } -static void dsi_perf_mark_start(struct platform_device *dsidev) +static void dsi_perf_mark_start(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); dsi->perf_start_time = ktime_get(); } -static void dsi_perf_show(struct platform_device *dsidev, const char *name) +static void dsi_perf_show(struct dsi_data *dsi, const char *name) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); ktime_t t, setup_time, trans_time; u32 total_bytes; u32 setup_us, trans_us, total_us; @@ -622,16 +616,15 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name) total_bytes * 1000 / total_us); } #else -static inline void dsi_perf_mark_setup(struct platform_device *dsidev) +static inline void dsi_perf_mark_setup(struct dsi_data *dsi) { } -static inline void dsi_perf_mark_start(struct platform_device *dsidev) +static inline void dsi_perf_mark_start(struct dsi_data *dsi) { } -static inline void dsi_perf_show(struct platform_device *dsidev, - const char *name) +static inline void dsi_perf_show(struct dsi_data *dsi, const char *name) { } #endif @@ -728,10 +721,9 @@ static void print_irq_status_cio(u32 status) } #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus, - u32 *vcstatus, u32 ciostatus) +static void dsi_collect_irq_stats(struct dsi_data *dsi, u32 irqstatus, + u32 *vcstatus, u32 ciostatus) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int i; spin_lock(&dsi->irq_stats_lock); @@ -747,15 +739,14 @@ static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus, spin_unlock(&dsi->irq_stats_lock); } #else -#define dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus) +#define dsi_collect_irq_stats(dsi, irqstatus, vcstatus, ciostatus) #endif static int debug_irq; -static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus, - u32 *vcstatus, u32 ciostatus) +static void dsi_handle_irq_errors(struct dsi_data *dsi, u32 irqstatus, + u32 *vcstatus, u32 ciostatus) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int i; if (irqstatus & DSI_IRQ_ERROR_MASK) { @@ -824,20 +815,16 @@ static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables, static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) { - struct platform_device *dsidev; - struct dsi_data *dsi; + struct dsi_data *dsi = arg; u32 irqstatus, vcstatus[4], ciostatus; int i; - dsidev = (struct platform_device *) arg; - dsi = dsi_get_dsidrv_data(dsidev); - if (!dsi->is_enabled) return IRQ_NONE; spin_lock(&dsi->irq_lock); - irqstatus = dsi_read_reg(dsidev, DSI_IRQSTATUS); + irqstatus = dsi_read_reg(dsi, DSI_IRQSTATUS); /* IRQ is not for us */ if (!irqstatus) { @@ -845,9 +832,9 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) return IRQ_NONE; } - dsi_write_reg(dsidev, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); + dsi_write_reg(dsi, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); /* flush posted write */ - dsi_read_reg(dsidev, DSI_IRQSTATUS); + dsi_read_reg(dsi, DSI_IRQSTATUS); for (i = 0; i < 4; ++i) { if ((irqstatus & (1 << i)) == 0) { @@ -855,19 +842,19 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) continue; } - vcstatus[i] = dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i)); + vcstatus[i] = dsi_read_reg(dsi, DSI_VC_IRQSTATUS(i)); - dsi_write_reg(dsidev, DSI_VC_IRQSTATUS(i), vcstatus[i]); + dsi_write_reg(dsi, DSI_VC_IRQSTATUS(i), vcstatus[i]); /* flush posted write */ - dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i)); + dsi_read_reg(dsi, DSI_VC_IRQSTATUS(i)); } if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) { - ciostatus = dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS); + ciostatus = dsi_read_reg(dsi, DSI_COMPLEXIO_IRQ_STATUS); - dsi_write_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS, ciostatus); + dsi_write_reg(dsi, DSI_COMPLEXIO_IRQ_STATUS, ciostatus); /* flush posted write */ - dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS); + dsi_read_reg(dsi, DSI_COMPLEXIO_IRQ_STATUS); } else { ciostatus = 0; } @@ -886,19 +873,20 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus); - dsi_handle_irq_errors(dsidev, irqstatus, vcstatus, ciostatus); + dsi_handle_irq_errors(dsi, irqstatus, vcstatus, ciostatus); - dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus); + dsi_collect_irq_stats(dsi, irqstatus, vcstatus, ciostatus); return IRQ_HANDLED; } /* dsi->irq_lock has to be locked by the caller */ -static void _omap_dsi_configure_irqs(struct platform_device *dsidev, - struct dsi_isr_data *isr_array, - unsigned int isr_array_size, u32 default_mask, - const struct dsi_reg enable_reg, - const struct dsi_reg status_reg) +static void _omap_dsi_configure_irqs(struct dsi_data *dsi, + struct dsi_isr_data *isr_array, + unsigned int isr_array_size, + u32 default_mask, + const struct dsi_reg enable_reg, + const struct dsi_reg status_reg) { struct dsi_isr_data *isr_data; u32 mask; @@ -916,54 +904,48 @@ static void _omap_dsi_configure_irqs(struct platform_device *dsidev, mask |= isr_data->mask; } - old_mask = dsi_read_reg(dsidev, enable_reg); + old_mask = dsi_read_reg(dsi, enable_reg); /* clear the irqstatus for newly enabled irqs */ - dsi_write_reg(dsidev, status_reg, (mask ^ old_mask) & mask); - dsi_write_reg(dsidev, enable_reg, mask); + dsi_write_reg(dsi, status_reg, (mask ^ old_mask) & mask); + dsi_write_reg(dsi, enable_reg, mask); /* flush posted writes */ - dsi_read_reg(dsidev, enable_reg); - dsi_read_reg(dsidev, status_reg); + dsi_read_reg(dsi, enable_reg); + dsi_read_reg(dsi, status_reg); } /* dsi->irq_lock has to be locked by the caller */ -static void _omap_dsi_set_irqs(struct platform_device *dsidev) +static void _omap_dsi_set_irqs(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 mask = DSI_IRQ_ERROR_MASK; #ifdef DSI_CATCH_MISSING_TE mask |= DSI_IRQ_TE_TRIGGER; #endif - _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table, + _omap_dsi_configure_irqs(dsi, dsi->isr_tables.isr_table, ARRAY_SIZE(dsi->isr_tables.isr_table), mask, DSI_IRQENABLE, DSI_IRQSTATUS); } /* dsi->irq_lock has to be locked by the caller */ -static void _omap_dsi_set_irqs_vc(struct platform_device *dsidev, int vc) +static void _omap_dsi_set_irqs_vc(struct dsi_data *dsi, int vc) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_vc[vc], + _omap_dsi_configure_irqs(dsi, dsi->isr_tables.isr_table_vc[vc], ARRAY_SIZE(dsi->isr_tables.isr_table_vc[vc]), DSI_VC_IRQ_ERROR_MASK, DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc)); } /* dsi->irq_lock has to be locked by the caller */ -static void _omap_dsi_set_irqs_cio(struct platform_device *dsidev) +static void _omap_dsi_set_irqs_cio(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_cio, + _omap_dsi_configure_irqs(dsi, dsi->isr_tables.isr_table_cio, ARRAY_SIZE(dsi->isr_tables.isr_table_cio), DSI_CIO_IRQ_ERROR_MASK, DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS); } -static void _dsi_initialize_irq(struct platform_device *dsidev) +static void _dsi_initialize_irq(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int vc; @@ -971,10 +953,10 @@ static void _dsi_initialize_irq(struct platform_device *dsidev) memset(&dsi->isr_tables, 0, sizeof(dsi->isr_tables)); - _omap_dsi_set_irqs(dsidev); + _omap_dsi_set_irqs(dsi); for (vc = 0; vc < 4; ++vc) - _omap_dsi_set_irqs_vc(dsidev, vc); - _omap_dsi_set_irqs_cio(dsidev); + _omap_dsi_set_irqs_vc(dsi, vc); + _omap_dsi_set_irqs_cio(dsi); spin_unlock_irqrestore(&dsi->irq_lock, flags); } @@ -1035,10 +1017,9 @@ static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask, return -EINVAL; } -static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr, - void *arg, u32 mask) +static int dsi_register_isr(struct dsi_data *dsi, omap_dsi_isr_t isr, + void *arg, u32 mask) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int r; @@ -1048,17 +1029,16 @@ static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr, ARRAY_SIZE(dsi->isr_tables.isr_table)); if (r == 0) - _omap_dsi_set_irqs(dsidev); + _omap_dsi_set_irqs(dsi); spin_unlock_irqrestore(&dsi->irq_lock, flags); return r; } -static int dsi_unregister_isr(struct platform_device *dsidev, - omap_dsi_isr_t isr, void *arg, u32 mask) +static int dsi_unregister_isr(struct dsi_data *dsi, omap_dsi_isr_t isr, + void *arg, u32 mask) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int r; @@ -1068,17 +1048,16 @@ static int dsi_unregister_isr(struct platform_device *dsidev, ARRAY_SIZE(dsi->isr_tables.isr_table)); if (r == 0) - _omap_dsi_set_irqs(dsidev); + _omap_dsi_set_irqs(dsi); spin_unlock_irqrestore(&dsi->irq_lock, flags); return r; } -static int dsi_register_isr_vc(struct platform_device *dsidev, int channel, - omap_dsi_isr_t isr, void *arg, u32 mask) +static int dsi_register_isr_vc(struct dsi_data *dsi, int channel, + omap_dsi_isr_t isr, void *arg, u32 mask) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int r; @@ -1089,17 +1068,16 @@ static int dsi_register_isr_vc(struct platform_device *dsidev, int channel, ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel])); if (r == 0) - _omap_dsi_set_irqs_vc(dsidev, channel); + _omap_dsi_set_irqs_vc(dsi, channel); spin_unlock_irqrestore(&dsi->irq_lock, flags); return r; } -static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel, - omap_dsi_isr_t isr, void *arg, u32 mask) +static int dsi_unregister_isr_vc(struct dsi_data *dsi, int channel, + omap_dsi_isr_t isr, void *arg, u32 mask) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int r; @@ -1110,17 +1088,16 @@ static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel, ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel])); if (r == 0) - _omap_dsi_set_irqs_vc(dsidev, channel); + _omap_dsi_set_irqs_vc(dsi, channel); spin_unlock_irqrestore(&dsi->irq_lock, flags); return r; } -static int dsi_register_isr_cio(struct platform_device *dsidev, - omap_dsi_isr_t isr, void *arg, u32 mask) +static int dsi_register_isr_cio(struct dsi_data *dsi, omap_dsi_isr_t isr, + void *arg, u32 mask) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int r; @@ -1130,17 +1107,16 @@ static int dsi_register_isr_cio(struct platform_device *dsidev, ARRAY_SIZE(dsi->isr_tables.isr_table_cio)); if (r == 0) - _omap_dsi_set_irqs_cio(dsidev); + _omap_dsi_set_irqs_cio(dsi); spin_unlock_irqrestore(&dsi->irq_lock, flags); return r; } -static int dsi_unregister_isr_cio(struct platform_device *dsidev, - omap_dsi_isr_t isr, void *arg, u32 mask) +static int dsi_unregister_isr_cio(struct dsi_data *dsi, omap_dsi_isr_t isr, + void *arg, u32 mask) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; int r; @@ -1150,18 +1126,18 @@ static int dsi_unregister_isr_cio(struct platform_device *dsidev, ARRAY_SIZE(dsi->isr_tables.isr_table_cio)); if (r == 0) - _omap_dsi_set_irqs_cio(dsidev); + _omap_dsi_set_irqs_cio(dsi); spin_unlock_irqrestore(&dsi->irq_lock, flags); return r; } -static u32 dsi_get_errors(struct platform_device *dsidev) +static u32 dsi_get_errors(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; u32 e; + spin_lock_irqsave(&dsi->errors_lock, flags); e = dsi->errors; dsi->errors = 0; @@ -1169,10 +1145,9 @@ static u32 dsi_get_errors(struct platform_device *dsidev) return e; } -static int dsi_runtime_get(struct platform_device *dsidev) +static int dsi_runtime_get(struct dsi_data *dsi) { int r; - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DSSDBG("dsi_runtime_get\n"); @@ -1181,9 +1156,8 @@ static int dsi_runtime_get(struct platform_device *dsidev) return r < 0 ? r : 0; } -static void dsi_runtime_put(struct platform_device *dsidev) +static void dsi_runtime_put(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; DSSDBG("dsi_runtime_put\n"); @@ -1192,9 +1166,8 @@ static void dsi_runtime_put(struct platform_device *dsidev) WARN_ON(r < 0 && r != -ENOSYS); } -static int dsi_regulator_init(struct platform_device *dsidev) +static int dsi_regulator_init(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct regulator *vdds_dsi; if (dsi->vdds_dsi_reg != NULL) @@ -1213,16 +1186,15 @@ static int dsi_regulator_init(struct platform_device *dsidev) return 0; } -static void _dsi_print_reset_status(struct platform_device *dsidev) +static void _dsi_print_reset_status(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 l; int b0, b1, b2; /* A dummy read using the SCP interface to any DSIPHY register is * required after DSIPHY reset to complete the reset of the DSI complex * I/O. */ - l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); + l = dsi_read_reg(dsi, DSI_DSIPHY_CFG5); if (dsi->data->quirks & DSI_QUIRK_REVERSE_TXCLKESC) { b0 = 28; @@ -1235,7 +1207,7 @@ static void _dsi_print_reset_status(struct platform_device *dsidev) } #define DSI_FLD_GET(fld, start, end)\ - FLD_GET(dsi_read_reg(dsidev, DSI_##fld), start, end) + FLD_GET(dsi_read_reg(dsi, DSI_##fld), start, end) pr_debug("DSI resets: PLL (%d) CIO (%d) PHY (%x%x%x, %d, %d, %d)\n", DSI_FLD_GET(PLL_STATUS, 0, 0), @@ -1250,14 +1222,14 @@ static void _dsi_print_reset_status(struct platform_device *dsidev) #undef DSI_FLD_GET } -static inline int dsi_if_enable(struct platform_device *dsidev, bool enable) +static inline int dsi_if_enable(struct dsi_data *dsi, bool enable) { DSSDBG("dsi_if_enable(%d)\n", enable); enable = enable ? 1 : 0; - REG_FLD_MOD(dsidev, DSI_CTRL, enable, 0, 0); /* IF_EN */ + REG_FLD_MOD(dsi, DSI_CTRL, enable, 0, 0); /* IF_EN */ - if (!wait_for_bit_change(dsidev, DSI_CTRL, 0, enable)) { + if (!wait_for_bit_change(dsi, DSI_CTRL, 0, enable)) { DSSERR("Failed to set dsi_if_enable to %d\n", enable); return -EIO; } @@ -1265,31 +1237,24 @@ static inline int dsi_if_enable(struct platform_device *dsidev, bool enable) return 0; } -static unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev) +static unsigned long dsi_get_pll_hsdiv_dispc_rate(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - return dsi->pll.cinfo.clkout[HSDIV_DISPC]; } -static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev) +static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - return dsi->pll.cinfo.clkout[HSDIV_DSI]; } -static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev) +static unsigned long dsi_get_txbyteclkhs(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - return dsi->pll.cinfo.clkdco / 16; } -static unsigned long dsi_fclk_rate(struct platform_device *dsidev) +static unsigned long dsi_fclk_rate(struct dsi_data *dsi) { unsigned long r; - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); enum dss_clk_source source; source = dss_get_dsi_clk_source(dsi->dss, dsi->module_id); @@ -1298,7 +1263,7 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev) r = clk_get_rate(dsi->dss_clk); } else { /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */ - r = dsi_get_pll_hsdiv_dsi_rate(dsidev); + r = dsi_get_pll_hsdiv_dsi_rate(dsi); } return r; @@ -1323,9 +1288,8 @@ static int dsi_lp_clock_calc(unsigned long dsi_fclk, return 0; } -static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) +static int dsi_set_lp_clk_divisor(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long dsi_fclk; unsigned int lp_clk_div; unsigned long lp_clk; @@ -1337,7 +1301,7 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) if (lp_clk_div == 0 || lp_clk_div > lpdiv_max) return -EINVAL; - dsi_fclk = dsi_fclk_rate(dsidev); + dsi_fclk = dsi_fclk_rate(dsi); lp_clk = dsi_fclk / 2 / lp_clk_div; @@ -1346,29 +1310,25 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) dsi->current_lp_cinfo.lp_clk_div = lp_clk_div; /* LP_CLK_DIVISOR */ - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0); + REG_FLD_MOD(dsi, DSI_CLK_CTRL, lp_clk_div, 12, 0); /* LP_RX_SYNCHRO_ENABLE */ - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21); + REG_FLD_MOD(dsi, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21); return 0; } -static void dsi_enable_scp_clk(struct platform_device *dsidev) +static void dsi_enable_scp_clk(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (dsi->scp_clk_refcount++ == 0) - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */ + REG_FLD_MOD(dsi, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */ } -static void dsi_disable_scp_clk(struct platform_device *dsidev) +static void dsi_disable_scp_clk(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - WARN_ON(dsi->scp_clk_refcount == 0); if (--dsi->scp_clk_refcount == 0) - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */ + REG_FLD_MOD(dsi, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */ } enum dsi_pll_power_state { @@ -1378,10 +1338,8 @@ enum dsi_pll_power_state { DSI_PLL_POWER_ON_DIV = 0x3, }; -static int dsi_pll_power(struct platform_device *dsidev, - enum dsi_pll_power_state state) +static int dsi_pll_power(struct dsi_data *dsi, enum dsi_pll_power_state state) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int t = 0; /* DSI-PLL power command 0x3 is not working */ @@ -1390,10 +1348,10 @@ static int dsi_pll_power(struct platform_device *dsidev, state = DSI_PLL_POWER_ON_ALL; /* PLL_PWR_CMD */ - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, state, 31, 30); + REG_FLD_MOD(dsi, DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_STATUS */ - while (FLD_GET(dsi_read_reg(dsidev, DSI_CLK_CTRL), 29, 28) != state) { + while (FLD_GET(dsi_read_reg(dsi, DSI_CLK_CTRL), 29, 28) != state) { if (++t > 1000) { DSSERR("Failed to set DSI PLL power mode to %d\n", state); @@ -1420,23 +1378,22 @@ static void dsi_pll_calc_dsi_fck(struct dsi_data *dsi, static int dsi_pll_enable(struct dss_pll *pll) { struct dsi_data *dsi = container_of(pll, struct dsi_data, pll); - struct platform_device *dsidev = dsi->pdev; int r = 0; DSSDBG("PLL init\n"); - r = dsi_regulator_init(dsidev); + r = dsi_regulator_init(dsi); if (r) return r; - r = dsi_runtime_get(dsidev); + r = dsi_runtime_get(dsi); if (r) return r; /* * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4. */ - dsi_enable_scp_clk(dsidev); + dsi_enable_scp_clk(dsi); if (!dsi->vdds_dsi_enabled) { r = regulator_enable(dsi->vdds_dsi_reg); @@ -1448,7 +1405,7 @@ static int dsi_pll_enable(struct dss_pll *pll) /* XXX PLL does not come out of reset without this... */ dispc_pck_free_enable(1); - if (!wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1)) { + if (!wait_for_bit_change(dsi, DSI_PLL_STATUS, 0, 1)) { DSSERR("PLL not coming out of reset.\n"); r = -ENODEV; dispc_pck_free_enable(0); @@ -1459,7 +1416,7 @@ static int dsi_pll_enable(struct dss_pll *pll) * fill the whole display. No idea about this */ dispc_pck_free_enable(0); - r = dsi_pll_power(dsidev, DSI_PLL_POWER_ON_ALL); + r = dsi_pll_power(dsi, DSI_PLL_POWER_ON_ALL); if (r) goto err1; @@ -1473,24 +1430,22 @@ err1: dsi->vdds_dsi_enabled = false; } err0: - dsi_disable_scp_clk(dsidev); - dsi_runtime_put(dsidev); + dsi_disable_scp_clk(dsi); + dsi_runtime_put(dsi); return r; } -static void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes) +static void dsi_pll_uninit(struct dsi_data *dsi, bool disconnect_lanes) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - dsi_pll_power(dsidev, DSI_PLL_POWER_OFF); + dsi_pll_power(dsi, DSI_PLL_POWER_OFF); if (disconnect_lanes) { WARN_ON(!dsi->vdds_dsi_enabled); regulator_disable(dsi->vdds_dsi_reg); dsi->vdds_dsi_enabled = false; } - dsi_disable_scp_clk(dsidev); - dsi_runtime_put(dsidev); + dsi_disable_scp_clk(dsi); + dsi_runtime_put(dsi); DSSDBG("PLL uninit done\n"); } @@ -1498,15 +1453,12 @@ static void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes static void dsi_pll_disable(struct dss_pll *pll) { struct dsi_data *dsi = container_of(pll, struct dsi_data, pll); - struct platform_device *dsidev = dsi->pdev; - dsi_pll_uninit(dsidev, true); + dsi_pll_uninit(dsi, true); } -static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, - struct seq_file *s) +static void dsi_dump_dsi_clocks(struct dsi_data *dsi, struct seq_file *s) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dss_pll_clock_info *cinfo = &dsi->pll.cinfo; enum dss_clk_source dispc_clk_src, dsi_clk_src; int dsi_module = dsi->module_id; @@ -1515,7 +1467,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, dispc_clk_src = dss_get_dispc_clk_source(dsi->dss); dsi_clk_src = dss_get_dsi_clk_source(dsi->dss, dsi_module); - if (dsi_runtime_get(dsidev)) + if (dsi_runtime_get(dsi)) return; seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); @@ -1550,35 +1502,33 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, seq_printf(s, "dsi fclk source = %s\n", dss_get_clk_source_name(dsi_clk_src)); - seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev)); + seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsi)); seq_printf(s, "DDR_CLK\t\t%lu\n", cinfo->clkdco / 4); - seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev)); + seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsi)); seq_printf(s, "LP_CLK\t\t%lu\n", dsi->current_lp_cinfo.lp_clk); - dsi_runtime_put(dsidev); + dsi_runtime_put(dsi); } void dsi_dump_clocks(struct seq_file *s) { - struct platform_device *dsidev; + struct dsi_data *dsi; int i; for (i = 0; i < MAX_NUM_DSI; i++) { - dsidev = dsi_get_dsidev_from_id(i); - if (dsidev) - dsi_dump_dsidev_clocks(dsidev, s); + dsi = dsi_get_dsi_from_id(i); + if (dsi) + dsi_dump_dsi_clocks(dsi, s); } } #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, - struct seq_file *s) +static void dsi_dump_dsi_irqs(struct dsi_data *dsi, struct seq_file *s) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; struct dsi_irq_stats stats; @@ -1666,29 +1616,28 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, static int dsi1_dump_irqs(struct seq_file *s, void *p) { - struct platform_device *dsidev = dsi_get_dsidev_from_id(0); + struct dsi_data *dsi = dsi_get_dsi_from_id(0); - dsi_dump_dsidev_irqs(dsidev, s); + dsi_dump_dsi_irqs(dsi, s); return 0; } static int dsi2_dump_irqs(struct seq_file *s, void *p) { - struct platform_device *dsidev = dsi_get_dsidev_from_id(1); + struct dsi_data *dsi = dsi_get_dsi_from_id(1); - dsi_dump_dsidev_irqs(dsidev, s); + dsi_dump_dsi_irqs(dsi, s); return 0; } #endif -static void dsi_dump_dsidev_regs(struct platform_device *dsidev, - struct seq_file *s) +static void dsi_dump_dsi_regs(struct dsi_data *dsi, struct seq_file *s) { -#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r)) +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsi, r)) - if (dsi_runtime_get(dsidev)) + if (dsi_runtime_get(dsi)) return; - dsi_enable_scp_clk(dsidev); + dsi_enable_scp_clk(dsi); DUMPREG(DSI_REVISION); DUMPREG(DSI_SYSCONFIG); @@ -1760,24 +1709,24 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, DUMPREG(DSI_PLL_CONFIGURATION1); DUMPREG(DSI_PLL_CONFIGURATION2); - dsi_disable_scp_clk(dsidev); - dsi_runtime_put(dsidev); + dsi_disable_scp_clk(dsi); + dsi_runtime_put(dsi); #undef DUMPREG } static int dsi1_dump_regs(struct seq_file *s, void *p) { - struct platform_device *dsidev = dsi_get_dsidev_from_id(0); + struct dsi_data *dsi = dsi_get_dsi_from_id(0); - dsi_dump_dsidev_regs(dsidev, s); + dsi_dump_dsi_regs(dsi, s); return 0; } static int dsi2_dump_regs(struct seq_file *s, void *p) { - struct platform_device *dsidev = dsi_get_dsidev_from_id(1); + struct dsi_data *dsi = dsi_get_dsi_from_id(1); - dsi_dump_dsidev_regs(dsidev, s); + dsi_dump_dsi_regs(dsi, s); return 0; } @@ -1787,16 +1736,15 @@ enum dsi_cio_power_state { DSI_COMPLEXIO_POWER_ULPS = 0x2, }; -static int dsi_cio_power(struct platform_device *dsidev, - enum dsi_cio_power_state state) +static int dsi_cio_power(struct dsi_data *dsi, enum dsi_cio_power_state state) { int t = 0; /* PWR_CMD */ - REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27); + REG_FLD_MOD(dsi, DSI_COMPLEXIO_CFG1, state, 28, 27); /* PWR_STATUS */ - while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1), + while (FLD_GET(dsi_read_reg(dsi, DSI_COMPLEXIO_CFG1), 26, 25) != state) { if (++t > 1000) { DSSERR("failed to set complexio power state to " @@ -1809,9 +1757,8 @@ static int dsi_cio_power(struct platform_device *dsidev, return 0; } -static unsigned int dsi_get_line_buf_size(struct platform_device *dsidev) +static unsigned int dsi_get_line_buf_size(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int val; /* line buffer on OMAP3 is 1024 x 24bits */ @@ -1821,7 +1768,7 @@ static unsigned int dsi_get_line_buf_size(struct platform_device *dsidev) if (!(dsi->data->quirks & DSI_QUIRK_GNQ)) return 1023 * 3; - val = REG_GET(dsidev, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */ + val = REG_GET(dsi, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */ switch (val) { case 1: @@ -1844,9 +1791,8 @@ static unsigned int dsi_get_line_buf_size(struct platform_device *dsidev) } } -static int dsi_set_lane_config(struct platform_device *dsidev) +static int dsi_set_lane_config(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); static const u8 offsets[] = { 0, 4, 8, 12, 16 }; static const enum dsi_lane_function functions[] = { DSI_LANE_CLK, @@ -1858,7 +1804,7 @@ static int dsi_set_lane_config(struct platform_device *dsidev) u32 r; int i; - r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); + r = dsi_read_reg(dsi, DSI_COMPLEXIO_CFG1); for (i = 0; i < dsi->num_lanes_used; ++i) { unsigned int offset = offsets[i]; @@ -1887,33 +1833,28 @@ static int dsi_set_lane_config(struct platform_device *dsidev) r = FLD_MOD(r, 0, offset + 3, offset + 3); } - dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); + dsi_write_reg(dsi, DSI_COMPLEXIO_CFG1, r); return 0; } -static inline unsigned int ns2ddr(struct platform_device *dsidev, - unsigned int ns) +static inline unsigned int ns2ddr(struct dsi_data *dsi, unsigned int ns) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - /* convert time in ns to ddr ticks, rounding up */ unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4; + return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000; } -static inline unsigned int ddr2ns(struct platform_device *dsidev, - unsigned int ddr) +static inline unsigned int ddr2ns(struct dsi_data *dsi, unsigned int ddr) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4; + return ddr * 1000 * 1000 / (ddr_clk / 1000); } -static void dsi_cio_timings(struct platform_device *dsidev) +static void dsi_cio_timings(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit; u32 tlpx_half, tclk_trail, tclk_zero; @@ -1924,54 +1865,54 @@ static void dsi_cio_timings(struct platform_device *dsidev) /* 1 * DDR_CLK = 2 * UI */ /* min 40ns + 4*UI max 85ns + 6*UI */ - ths_prepare = ns2ddr(dsidev, 70) + 2; + ths_prepare = ns2ddr(dsi, 70) + 2; /* min 145ns + 10*UI */ - ths_prepare_ths_zero = ns2ddr(dsidev, 175) + 2; + ths_prepare_ths_zero = ns2ddr(dsi, 175) + 2; /* min max(8*UI, 60ns+4*UI) */ - ths_trail = ns2ddr(dsidev, 60) + 5; + ths_trail = ns2ddr(dsi, 60) + 5; /* min 100ns */ - ths_exit = ns2ddr(dsidev, 145); + ths_exit = ns2ddr(dsi, 145); /* tlpx min 50n */ - tlpx_half = ns2ddr(dsidev, 25); + tlpx_half = ns2ddr(dsi, 25); /* min 60ns */ - tclk_trail = ns2ddr(dsidev, 60) + 2; + tclk_trail = ns2ddr(dsi, 60) + 2; /* min 38ns, max 95ns */ - tclk_prepare = ns2ddr(dsidev, 65); + tclk_prepare = ns2ddr(dsi, 65); /* min tclk-prepare + tclk-zero = 300ns */ - tclk_zero = ns2ddr(dsidev, 260); + tclk_zero = ns2ddr(dsi, 260); DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n", - ths_prepare, ddr2ns(dsidev, ths_prepare), - ths_prepare_ths_zero, ddr2ns(dsidev, ths_prepare_ths_zero)); + ths_prepare, ddr2ns(dsi, ths_prepare), + ths_prepare_ths_zero, ddr2ns(dsi, ths_prepare_ths_zero)); DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n", - ths_trail, ddr2ns(dsidev, ths_trail), - ths_exit, ddr2ns(dsidev, ths_exit)); + ths_trail, ddr2ns(dsi, ths_trail), + ths_exit, ddr2ns(dsi, ths_exit)); DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), " "tclk_zero %u (%uns)\n", - tlpx_half, ddr2ns(dsidev, tlpx_half), - tclk_trail, ddr2ns(dsidev, tclk_trail), - tclk_zero, ddr2ns(dsidev, tclk_zero)); + tlpx_half, ddr2ns(dsi, tlpx_half), + tclk_trail, ddr2ns(dsi, tclk_trail), + tclk_zero, ddr2ns(dsi, tclk_zero)); DSSDBG("tclk_prepare %u (%uns)\n", - tclk_prepare, ddr2ns(dsidev, tclk_prepare)); + tclk_prepare, ddr2ns(dsi, tclk_prepare)); /* program timings */ - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG0); r = FLD_MOD(r, ths_prepare, 31, 24); r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16); r = FLD_MOD(r, ths_trail, 15, 8); r = FLD_MOD(r, ths_exit, 7, 0); - dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r); + dsi_write_reg(dsi, DSI_DSIPHY_CFG0, r); - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG1); r = FLD_MOD(r, tlpx_half, 20, 16); r = FLD_MOD(r, tclk_trail, 15, 8); r = FLD_MOD(r, tclk_zero, 7, 0); @@ -1982,18 +1923,18 @@ static void dsi_cio_timings(struct platform_device *dsidev) r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */ } - dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r); + dsi_write_reg(dsi, DSI_DSIPHY_CFG1, r); - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG2); r = FLD_MOD(r, tclk_prepare, 7, 0); - dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r); + dsi_write_reg(dsi, DSI_DSIPHY_CFG2, r); } /* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */ -static void dsi_cio_enable_lane_override(struct platform_device *dsidev, - unsigned int mask_p, unsigned int mask_n) +static void dsi_cio_enable_lane_override(struct dsi_data *dsi, + unsigned int mask_p, + unsigned int mask_n) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int i; u32 l; u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26; @@ -2022,26 +1963,25 @@ static void dsi_cio_enable_lane_override(struct platform_device *dsidev, /* Set the lane override configuration */ /* REGLPTXSCPDAT4TO0DXDY */ - REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, lptxscp_start, 17); + REG_FLD_MOD(dsi, DSI_DSIPHY_CFG10, l, lptxscp_start, 17); /* Enable lane override */ /* ENLPTXSCPDAT */ - REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 1, 27, 27); + REG_FLD_MOD(dsi, DSI_DSIPHY_CFG10, 1, 27, 27); } -static void dsi_cio_disable_lane_override(struct platform_device *dsidev) +static void dsi_cio_disable_lane_override(struct dsi_data *dsi) { /* Disable lane override */ - REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */ + REG_FLD_MOD(dsi, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */ /* Reset the lane override configuration */ /* REGLPTXSCPDAT4TO0DXDY */ - REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17); + REG_FLD_MOD(dsi, DSI_DSIPHY_CFG10, 0, 22, 17); } -static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) +static int dsi_cio_wait_tx_clk_esc_reset(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int t, i; bool in_use[DSI_MAX_NR_LANES]; static const u8 offsets_old[] = { 28, 27, 26 }; @@ -2061,7 +2001,7 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) u32 l; int ok; - l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); + l = dsi_read_reg(dsi, DSI_DSIPHY_CFG5); ok = 0; for (i = 0; i < dsi->num_lanes_supported; ++i) { @@ -2088,9 +2028,8 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) } /* return bitmask of enabled lanes, lane0 being the lsb */ -static unsigned int dsi_get_lane_mask(struct platform_device *dsidev) +static unsigned int dsi_get_lane_mask(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned int mask = 0; int i; @@ -2179,42 +2118,41 @@ static void dsi_disable_pads(struct dsi_data *dsi) dsi_omap5_mux_pads(dsi, 0); } -static int dsi_cio_init(struct platform_device *dsidev) +static int dsi_cio_init(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; u32 l; DSSDBG("DSI CIO init starts"); - r = dsi_enable_pads(dsi, dsi_get_lane_mask(dsidev)); + r = dsi_enable_pads(dsi, dsi_get_lane_mask(dsi)); if (r) return r; - dsi_enable_scp_clk(dsidev); + dsi_enable_scp_clk(dsi); /* A dummy read using the SCP interface to any DSIPHY register is * required after DSIPHY reset to complete the reset of the DSI complex * I/O. */ - dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); + dsi_read_reg(dsi, DSI_DSIPHY_CFG5); - if (!wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1)) { + if (!wait_for_bit_change(dsi, DSI_DSIPHY_CFG5, 30, 1)) { DSSERR("CIO SCP Clock domain not coming out of reset.\n"); r = -EIO; goto err_scp_clk_dom; } - r = dsi_set_lane_config(dsidev); + r = dsi_set_lane_config(dsi); if (r) goto err_scp_clk_dom; /* set TX STOP MODE timer to maximum for this operation */ - l = dsi_read_reg(dsidev, DSI_TIMING1); + l = dsi_read_reg(dsi, DSI_TIMING1); l = FLD_MOD(l, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ l = FLD_MOD(l, 1, 14, 14); /* STOP_STATE_X16_IO */ l = FLD_MOD(l, 1, 13, 13); /* STOP_STATE_X4_IO */ l = FLD_MOD(l, 0x1fff, 12, 0); /* STOP_STATE_COUNTER_IO */ - dsi_write_reg(dsidev, DSI_TIMING1, l); + dsi_write_reg(dsi, DSI_TIMING1, l); if (dsi->ulps_enabled) { unsigned int mask_p; @@ -2239,24 +2177,24 @@ static int dsi_cio_init(struct platform_device *dsidev) mask_p |= 1 << i; } - dsi_cio_enable_lane_override(dsidev, mask_p, 0); + dsi_cio_enable_lane_override(dsi, mask_p, 0); } - r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); + r = dsi_cio_power(dsi, DSI_COMPLEXIO_POWER_ON); if (r) goto err_cio_pwr; - if (!wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1)) { + if (!wait_for_bit_change(dsi, DSI_COMPLEXIO_CFG1, 29, 1)) { DSSERR("CIO PWR clock domain not coming out of reset.\n"); r = -ENODEV; goto err_cio_pwr_dom; } - dsi_if_enable(dsidev, true); - dsi_if_enable(dsidev, false); - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */ + dsi_if_enable(dsi, true); + dsi_if_enable(dsi, false); + REG_FLD_MOD(dsi, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */ - r = dsi_cio_wait_tx_clk_esc_reset(dsidev); + r = dsi_cio_wait_tx_clk_esc_reset(dsi); if (r) goto err_tx_clk_esc_rst; @@ -2268,17 +2206,17 @@ static int dsi_cio_init(struct platform_device *dsidev) /* Disable the override. The lanes should be set to Mark-11 * state by the HW */ - dsi_cio_disable_lane_override(dsidev); + dsi_cio_disable_lane_override(dsi); } /* FORCE_TX_STOP_MODE_IO */ - REG_FLD_MOD(dsidev, DSI_TIMING1, 0, 15, 15); + REG_FLD_MOD(dsi, DSI_TIMING1, 0, 15, 15); - dsi_cio_timings(dsidev); + dsi_cio_timings(dsi); if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { /* DDR_CLK_ALWAYS_ON */ - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, + REG_FLD_MOD(dsi, DSI_CLK_CTRL, dsi->vm_timings.ddr_clk_always_on, 13, 13); } @@ -2289,35 +2227,32 @@ static int dsi_cio_init(struct platform_device *dsidev) return 0; err_tx_clk_esc_rst: - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */ + REG_FLD_MOD(dsi, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */ err_cio_pwr_dom: - dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); + dsi_cio_power(dsi, DSI_COMPLEXIO_POWER_OFF); err_cio_pwr: if (dsi->ulps_enabled) - dsi_cio_disable_lane_override(dsidev); + dsi_cio_disable_lane_override(dsi); err_scp_clk_dom: - dsi_disable_scp_clk(dsidev); + dsi_disable_scp_clk(dsi); dsi_disable_pads(dsi); return r; } -static void dsi_cio_uninit(struct platform_device *dsidev) +static void dsi_cio_uninit(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - /* DDR_CLK_ALWAYS_ON */ - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13); + REG_FLD_MOD(dsi, DSI_CLK_CTRL, 0, 13, 13); - dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); - dsi_disable_scp_clk(dsidev); + dsi_cio_power(dsi, DSI_COMPLEXIO_POWER_OFF); + dsi_disable_scp_clk(dsi); dsi_disable_pads(dsi); } -static void dsi_config_tx_fifo(struct platform_device *dsidev, - enum fifo_size size1, enum fifo_size size2, - enum fifo_size size3, enum fifo_size size4) +static void dsi_config_tx_fifo(struct dsi_data *dsi, + enum fifo_size size1, enum fifo_size size2, + enum fifo_size size3, enum fifo_size size4) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r = 0; int add = 0; int i; @@ -2343,14 +2278,13 @@ static void dsi_config_tx_fifo(struct platform_device *dsidev, add += size; } - dsi_write_reg(dsidev, DSI_TX_FIFO_VC_SIZE, r); + dsi_write_reg(dsi, DSI_TX_FIFO_VC_SIZE, r); } -static void dsi_config_rx_fifo(struct platform_device *dsidev, +static void dsi_config_rx_fifo(struct dsi_data *dsi, enum fifo_size size1, enum fifo_size size2, enum fifo_size size3, enum fifo_size size4) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r = 0; int add = 0; int i; @@ -2376,18 +2310,18 @@ static void dsi_config_rx_fifo(struct platform_device *dsidev, add += size; } - dsi_write_reg(dsidev, DSI_RX_FIFO_VC_SIZE, r); + dsi_write_reg(dsi, DSI_RX_FIFO_VC_SIZE, r); } -static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev) +static int dsi_force_tx_stop_mode_io(struct dsi_data *dsi) { u32 r; - r = dsi_read_reg(dsidev, DSI_TIMING1); + r = dsi_read_reg(dsi, DSI_TIMING1); r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ - dsi_write_reg(dsidev, DSI_TIMING1, r); + dsi_write_reg(dsi, DSI_TIMING1, r); - if (!wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0)) { + if (!wait_for_bit_change(dsi, DSI_TIMING1, 15, 0)) { DSSERR("TX_STOP bit not going down\n"); return -EIO; } @@ -2395,29 +2329,28 @@ static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev) return 0; } -static bool dsi_vc_is_enabled(struct platform_device *dsidev, int channel) +static bool dsi_vc_is_enabled(struct dsi_data *dsi, int channel) { - return REG_GET(dsidev, DSI_VC_CTRL(channel), 0, 0); + return REG_GET(dsi, DSI_VC_CTRL(channel), 0, 0); } static void dsi_packet_sent_handler_vp(void *data, u32 mask) { struct dsi_packet_sent_handler_data *vp_data = (struct dsi_packet_sent_handler_data *) data; - struct dsi_data *dsi = dsi_get_dsidrv_data(vp_data->dsidev); + struct dsi_data *dsi = vp_data->dsi; const int channel = dsi->update_channel; u8 bit = dsi->te_enabled ? 30 : 31; - if (REG_GET(vp_data->dsidev, DSI_VC_TE(channel), bit, bit) == 0) + if (REG_GET(dsi, DSI_VC_TE(channel), bit, bit) == 0) complete(vp_data->completion); } -static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel) +static int dsi_sync_vc_vp(struct dsi_data *dsi, int channel) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DECLARE_COMPLETION_ONSTACK(completion); struct dsi_packet_sent_handler_data vp_data = { - .dsidev = dsidev, + .dsi = dsi, .completion = &completion }; int r = 0; @@ -2425,13 +2358,13 @@ static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel) bit = dsi->te_enabled ? 30 : 31; - r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp, + r = dsi_register_isr_vc(dsi, channel, dsi_packet_sent_handler_vp, &vp_data, DSI_VC_IRQ_PACKET_SENT); if (r) goto err0; /* Wait for completion only if TE_EN/TE_START is still set */ - if (REG_GET(dsidev, DSI_VC_TE(channel), bit, bit)) { + if (REG_GET(dsi, DSI_VC_TE(channel), bit, bit)) { if (wait_for_completion_timeout(&completion, msecs_to_jiffies(10)) == 0) { DSSERR("Failed to complete previous frame transfer\n"); @@ -2440,12 +2373,12 @@ static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel) } } - dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp, + dsi_unregister_isr_vc(dsi, channel, dsi_packet_sent_handler_vp, &vp_data, DSI_VC_IRQ_PACKET_SENT); return 0; err1: - dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp, + dsi_unregister_isr_vc(dsi, channel, dsi_packet_sent_handler_vp, &vp_data, DSI_VC_IRQ_PACKET_SENT); err0: return r; @@ -2455,29 +2388,29 @@ static void dsi_packet_sent_handler_l4(void *data, u32 mask) { struct dsi_packet_sent_handler_data *l4_data = (struct dsi_packet_sent_handler_data *) data; - struct dsi_data *dsi = dsi_get_dsidrv_data(l4_data->dsidev); + struct dsi_data *dsi = l4_data->dsi; const int channel = dsi->update_channel; - if (REG_GET(l4_data->dsidev, DSI_VC_CTRL(channel), 5, 5) == 0) + if (REG_GET(dsi, DSI_VC_CTRL(channel), 5, 5) == 0) complete(l4_data->completion); } -static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel) +static int dsi_sync_vc_l4(struct dsi_data *dsi, int channel) { DECLARE_COMPLETION_ONSTACK(completion); struct dsi_packet_sent_handler_data l4_data = { - .dsidev = dsidev, + .dsi = dsi, .completion = &completion }; int r = 0; - r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4, + r = dsi_register_isr_vc(dsi, channel, dsi_packet_sent_handler_l4, &l4_data, DSI_VC_IRQ_PACKET_SENT); if (r) goto err0; /* Wait for completion only if TX_FIFO_NOT_EMPTY is still set */ - if (REG_GET(dsidev, DSI_VC_CTRL(channel), 5, 5)) { + if (REG_GET(dsi, DSI_VC_CTRL(channel), 5, 5)) { if (wait_for_completion_timeout(&completion, msecs_to_jiffies(10)) == 0) { DSSERR("Failed to complete previous l4 transfer\n"); @@ -2486,50 +2419,47 @@ static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel) } } - dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4, + dsi_unregister_isr_vc(dsi, channel, dsi_packet_sent_handler_l4, &l4_data, DSI_VC_IRQ_PACKET_SENT); return 0; err1: - dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4, + dsi_unregister_isr_vc(dsi, channel, dsi_packet_sent_handler_l4, &l4_data, DSI_VC_IRQ_PACKET_SENT); err0: return r; } -static int dsi_sync_vc(struct platform_device *dsidev, int channel) +static int dsi_sync_vc(struct dsi_data *dsi, int channel) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); WARN_ON(in_interrupt()); - if (!dsi_vc_is_enabled(dsidev, channel)) + if (!dsi_vc_is_enabled(dsi, channel)) return 0; switch (dsi->vc[channel].source) { case DSI_VC_SOURCE_VP: - return dsi_sync_vc_vp(dsidev, channel); + return dsi_sync_vc_vp(dsi, channel); case DSI_VC_SOURCE_L4: - return dsi_sync_vc_l4(dsidev, channel); + return dsi_sync_vc_l4(dsi, channel); default: BUG(); return -EINVAL; } } -static int dsi_vc_enable(struct platform_device *dsidev, int channel, - bool enable) +static int dsi_vc_enable(struct dsi_data *dsi, int channel, bool enable) { DSSDBG("dsi_vc_enable channel %d, enable %d\n", channel, enable); enable = enable ? 1 : 0; - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 0, 0); + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), enable, 0, 0); - if (!wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 0, enable)) { + if (!wait_for_bit_change(dsi, DSI_VC_CTRL(channel), 0, enable)) { DSSERR("Failed to set dsi_vc_enable to %d\n", enable); return -EIO; } @@ -2537,14 +2467,13 @@ static int dsi_vc_enable(struct platform_device *dsidev, int channel, return 0; } -static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) +static void dsi_vc_initial_config(struct dsi_data *dsi, int channel) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; DSSDBG("Initial config of virtual channel %d", channel); - r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); + r = dsi_read_reg(dsi, DSI_VC_CTRL(channel)); if (FLD_GET(r, 15, 15)) /* VC_BUSY */ DSSERR("VC(%d) busy when trying to configure it!\n", @@ -2563,41 +2492,39 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */ r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */ - dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r); + dsi_write_reg(dsi, DSI_VC_CTRL(channel), r); dsi->vc[channel].source = DSI_VC_SOURCE_L4; } -static int dsi_vc_config_source(struct platform_device *dsidev, int channel, - enum dsi_vc_source source) +static int dsi_vc_config_source(struct dsi_data *dsi, int channel, + enum dsi_vc_source source) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (dsi->vc[channel].source == source) return 0; DSSDBG("Source config of virtual channel %d", channel); - dsi_sync_vc(dsidev, channel); + dsi_sync_vc(dsi, channel); - dsi_vc_enable(dsidev, channel, 0); + dsi_vc_enable(dsi, channel, 0); /* VC_BUSY */ - if (!wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0)) { + if (!wait_for_bit_change(dsi, DSI_VC_CTRL(channel), 15, 0)) { DSSERR("vc(%d) busy when trying to config for VP\n", channel); return -EIO; } /* SOURCE, 0 = L4, 1 = video port */ - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), source, 1, 1); + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), source, 1, 1); /* DCS_CMD_ENABLE */ if (dsi->data->quirks & DSI_QUIRK_DCS_CMD_CONFIG_VC) { bool enable = source == DSI_VC_SOURCE_VP; - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 30, 30); + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), enable, 30, 30); } - dsi_vc_enable(dsidev, channel, 1); + dsi_vc_enable(dsi, channel, 1); dsi->vc[channel].source = source; @@ -2612,28 +2539,28 @@ static void dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); - dsi_vc_enable(dsidev, channel, 0); - dsi_if_enable(dsidev, 0); + dsi_vc_enable(dsi, channel, 0); + dsi_if_enable(dsi, 0); - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 9, 9); + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), enable, 9, 9); - dsi_vc_enable(dsidev, channel, 1); - dsi_if_enable(dsidev, 1); + dsi_vc_enable(dsi, channel, 1); + dsi_if_enable(dsi, 1); - dsi_force_tx_stop_mode_io(dsidev); + dsi_force_tx_stop_mode_io(dsi); /* start the DDR clock by sending a NULL packet */ if (dsi->vm_timings.ddr_clk_always_on && enable) - dsi_vc_send_null(dssdev, channel); + dsi_vc_send_null(dsi, channel); } -static void dsi_vc_flush_long_data(struct platform_device *dsidev, int channel) +static void dsi_vc_flush_long_data(struct dsi_data *dsi, int channel) { - while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) { + while (REG_GET(dsi, DSI_VC_CTRL(channel), 20, 20)) { u32 val; - val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel)); + val = dsi_read_reg(dsi, DSI_VC_SHORT_PACKET_HEADER(channel)); DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n", (val >> 0) & 0xff, (val >> 8) & 0xff, @@ -2679,14 +2606,13 @@ static void dsi_show_rx_ack_with_err(u16 err) DSSERR("\t\tDSI Protocol Violation\n"); } -static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev, - int channel) +static u16 dsi_vc_flush_receive_data(struct dsi_data *dsi, int channel) { /* RX_FIFO_NOT_EMPTY */ - while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) { + while (REG_GET(dsi, DSI_VC_CTRL(channel), 20, 20)) { u32 val; u8 dt; - val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel)); + val = dsi_read_reg(dsi, DSI_VC_SHORT_PACKET_HEADER(channel)); DSSERR("\trawval %#08x\n", val); dt = FLD_GET(val, 5, 0); if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) { @@ -2701,7 +2627,7 @@ static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev, } else if (dt == MIPI_DSI_RX_DCS_LONG_READ_RESPONSE) { DSSERR("\tDCS long response, len %d\n", FLD_GET(val, 23, 8)); - dsi_vc_flush_long_data(dsidev, channel); + dsi_vc_flush_long_data(dsi, channel); } else { DSSERR("\tunknown datatype 0x%02x\n", dt); } @@ -2709,25 +2635,23 @@ static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev, return 0; } -static int dsi_vc_send_bta(struct platform_device *dsidev, int channel) +static int dsi_vc_send_bta(struct dsi_data *dsi, int channel) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (dsi->debug_write || dsi->debug_read) DSSDBG("dsi_vc_send_bta %d\n", channel); - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); /* RX_FIFO_NOT_EMPTY */ - if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) { + if (REG_GET(dsi, DSI_VC_CTRL(channel), 20, 20)) { DSSERR("rx fifo not empty when sending BTA, dumping data:\n"); - dsi_vc_flush_receive_data(dsidev, channel); + dsi_vc_flush_receive_data(dsi, channel); } - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ /* flush posted write */ - dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); + dsi_read_reg(dsi, DSI_VC_CTRL(channel)); return 0; } @@ -2735,21 +2659,22 @@ static int dsi_vc_send_bta(struct platform_device *dsidev, int channel) static int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DECLARE_COMPLETION_ONSTACK(completion); int r = 0; u32 err; - r = dsi_register_isr_vc(dsidev, channel, dsi_completion_handler, + r = dsi_register_isr_vc(dsi, channel, dsi_completion_handler, &completion, DSI_VC_IRQ_BTA); if (r) goto err0; - r = dsi_register_isr(dsidev, dsi_completion_handler, &completion, + r = dsi_register_isr(dsi, dsi_completion_handler, &completion, DSI_IRQ_ERROR_MASK); if (r) goto err1; - r = dsi_vc_send_bta(dsidev, channel); + r = dsi_vc_send_bta(dsi, channel); if (r) goto err2; @@ -2760,41 +2685,40 @@ static int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel) goto err2; } - err = dsi_get_errors(dsidev); + err = dsi_get_errors(dsi); if (err) { DSSERR("Error while sending BTA: %x\n", err); r = -EIO; goto err2; } err2: - dsi_unregister_isr(dsidev, dsi_completion_handler, &completion, + dsi_unregister_isr(dsi, dsi_completion_handler, &completion, DSI_IRQ_ERROR_MASK); err1: - dsi_unregister_isr_vc(dsidev, channel, dsi_completion_handler, + dsi_unregister_isr_vc(dsi, channel, dsi_completion_handler, &completion, DSI_VC_IRQ_BTA); err0: return r; } -static inline void dsi_vc_write_long_header(struct platform_device *dsidev, - int channel, u8 data_type, u16 len, u8 ecc) +static inline void dsi_vc_write_long_header(struct dsi_data *dsi, int channel, + u8 data_type, u16 len, u8 ecc) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 val; u8 data_id; - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); data_id = data_type | dsi->vc[channel].vc_id << 6; val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) | FLD_VAL(ecc, 31, 24); - dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(channel), val); + dsi_write_reg(dsi, DSI_VC_LONG_PACKET_HEADER(channel), val); } -static inline void dsi_vc_write_long_payload(struct platform_device *dsidev, - int channel, u8 b1, u8 b2, u8 b3, u8 b4) +static inline void dsi_vc_write_long_payload(struct dsi_data *dsi, int channel, + u8 b1, u8 b2, u8 b3, u8 b4) { u32 val; @@ -2803,14 +2727,13 @@ static inline void dsi_vc_write_long_payload(struct platform_device *dsidev, /* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n", b1, b2, b3, b4, val); */ - dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(channel), val); + dsi_write_reg(dsi, DSI_VC_LONG_PACKET_PAYLOAD(channel), val); } -static int dsi_vc_send_long(struct platform_device *dsidev, int channel, - u8 data_type, u8 *data, u16 len, u8 ecc) +static int dsi_vc_send_long(struct dsi_data *dsi, int channel, u8 data_type, + u8 *data, u16 len, u8 ecc) { /*u32 val; */ - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int i; u8 *p; int r = 0; @@ -2825,9 +2748,9 @@ static int dsi_vc_send_long(struct platform_device *dsidev, int channel, return -EINVAL; } - dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4); + dsi_vc_config_source(dsi, channel, DSI_VC_SOURCE_L4); - dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc); + dsi_vc_write_long_header(dsi, channel, data_type, len, ecc); p = data; for (i = 0; i < len >> 2; i++) { @@ -2839,7 +2762,7 @@ static int dsi_vc_send_long(struct platform_device *dsidev, int channel, b3 = *p++; b4 = *p++; - dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, b4); + dsi_vc_write_long_payload(dsi, channel, b1, b2, b3, b4); } i = len % 4; @@ -2864,29 +2787,28 @@ static int dsi_vc_send_long(struct platform_device *dsidev, int channel, break; } - dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, 0); + dsi_vc_write_long_payload(dsi, channel, b1, b2, b3, 0); } return r; } -static int dsi_vc_send_short(struct platform_device *dsidev, int channel, - u8 data_type, u16 data, u8 ecc) +static int dsi_vc_send_short(struct dsi_data *dsi, int channel, u8 data_type, + u16 data, u8 ecc) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; u8 data_id; - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); if (dsi->debug_write) DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n", channel, data_type, data & 0xff, (data >> 8) & 0xff); - dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4); + dsi_vc_config_source(dsi, channel, DSI_VC_SOURCE_L4); - if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) { + if (FLD_GET(dsi_read_reg(dsi, DSI_VC_CTRL(channel)), 16, 16)) { DSSERR("ERROR FIFO FULL, aborting transfer\n"); return -EINVAL; } @@ -2895,41 +2817,39 @@ static int dsi_vc_send_short(struct platform_device *dsidev, int channel, r = (data_id << 0) | (data << 8) | (ecc << 24); - dsi_write_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel), r); + dsi_write_reg(dsi, DSI_VC_SHORT_PACKET_HEADER(channel), r); return 0; } -static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel) +static int dsi_vc_send_null(struct dsi_data *dsi, int channel) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - - return dsi_vc_send_long(dsidev, channel, MIPI_DSI_NULL_PACKET, NULL, - 0, 0); + return dsi_vc_send_long(dsi, channel, MIPI_DSI_NULL_PACKET, NULL, 0, 0); } -static int dsi_vc_write_nosync_common(struct platform_device *dsidev, - int channel, u8 *data, int len, enum dss_dsi_content_type type) +static int dsi_vc_write_nosync_common(struct dsi_data *dsi, int channel, + u8 *data, int len, + enum dss_dsi_content_type type) { int r; if (len == 0) { BUG_ON(type == DSS_DSI_CONTENT_DCS); - r = dsi_vc_send_short(dsidev, channel, + r = dsi_vc_send_short(dsi, channel, MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM, 0, 0); } else if (len == 1) { - r = dsi_vc_send_short(dsidev, channel, + r = dsi_vc_send_short(dsi, channel, type == DSS_DSI_CONTENT_GENERIC ? MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM : MIPI_DSI_DCS_SHORT_WRITE, data[0], 0); } else if (len == 2) { - r = dsi_vc_send_short(dsidev, channel, + r = dsi_vc_send_short(dsi, channel, type == DSS_DSI_CONTENT_GENERIC ? MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM : MIPI_DSI_DCS_SHORT_WRITE_PARAM, data[0] | (data[1] << 8), 0); } else { - r = dsi_vc_send_long(dsidev, channel, + r = dsi_vc_send_long(dsi, channel, type == DSS_DSI_CONTENT_GENERIC ? MIPI_DSI_GENERIC_LONG_WRITE : MIPI_DSI_DCS_LONG_WRITE, data, len, 0); @@ -2942,8 +2862,9 @@ static int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, u8 *data, int len) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - return dsi_vc_write_nosync_common(dsidev, channel, data, len, + return dsi_vc_write_nosync_common(dsi, channel, data, len, DSS_DSI_CONTENT_DCS); } @@ -2951,18 +2872,21 @@ static int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int chann u8 *data, int len) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - return dsi_vc_write_nosync_common(dsidev, channel, data, len, + return dsi_vc_write_nosync_common(dsi, channel, data, len, DSS_DSI_CONTENT_GENERIC); } -static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel, - u8 *data, int len, enum dss_dsi_content_type type) +static int dsi_vc_write_common(struct omap_dss_device *dssdev, + int channel, u8 *data, int len, + enum dss_dsi_content_type type) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; - r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type); + r = dsi_vc_write_nosync_common(dsi, channel, data, len, type); if (r) goto err; @@ -2971,9 +2895,9 @@ static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel, goto err; /* RX_FIFO_NOT_EMPTY */ - if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) { + if (REG_GET(dsi, DSI_VC_CTRL(channel), 20, 20)) { DSSERR("rx fifo not empty after write, dumping data:\n"); - dsi_vc_flush_receive_data(dsidev, channel); + dsi_vc_flush_receive_data(dsi, channel); r = -EIO; goto err; } @@ -2999,17 +2923,16 @@ static int dsi_vc_generic_write(struct omap_dss_device *dssdev, int channel, u8 DSS_DSI_CONTENT_GENERIC); } -static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev, - int channel, u8 dcs_cmd) +static int dsi_vc_dcs_send_read_request(struct dsi_data *dsi, int channel, + u8 dcs_cmd) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; if (dsi->debug_read) DSSDBG("dsi_vc_dcs_send_read_request(ch%d, dcs_cmd %x)\n", channel, dcs_cmd); - r = dsi_vc_send_short(dsidev, channel, MIPI_DSI_DCS_READ, dcs_cmd, 0); + r = dsi_vc_send_short(dsi, channel, MIPI_DSI_DCS_READ, dcs_cmd, 0); if (r) { DSSERR("dsi_vc_dcs_send_read_request(ch %d, cmd 0x%02x)" " failed\n", channel, dcs_cmd); @@ -3019,10 +2942,9 @@ static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev, return 0; } -static int dsi_vc_generic_send_read_request(struct platform_device *dsidev, - int channel, u8 *reqdata, int reqlen) +static int dsi_vc_generic_send_read_request(struct dsi_data *dsi, int channel, + u8 *reqdata, int reqlen) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u16 data; u8 data_type; int r; @@ -3045,7 +2967,7 @@ static int dsi_vc_generic_send_read_request(struct platform_device *dsidev, return -EINVAL; } - r = dsi_vc_send_short(dsidev, channel, data_type, data, 0); + r = dsi_vc_send_short(dsi, channel, data_type, data, 0); if (r) { DSSERR("dsi_vc_generic_send_read_request(ch %d, reqlen %d)" " failed\n", channel, reqlen); @@ -3055,22 +2977,21 @@ static int dsi_vc_generic_send_read_request(struct platform_device *dsidev, return 0; } -static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel, - u8 *buf, int buflen, enum dss_dsi_content_type type) +static int dsi_vc_read_rx_fifo(struct dsi_data *dsi, int channel, u8 *buf, + int buflen, enum dss_dsi_content_type type) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 val; u8 dt; int r; /* RX_FIFO_NOT_EMPTY */ - if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) { + if (REG_GET(dsi, DSI_VC_CTRL(channel), 20, 20) == 0) { DSSERR("RX fifo empty when trying to read.\n"); r = -EIO; goto err; } - val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel)); + val = dsi_read_reg(dsi, DSI_VC_SHORT_PACKET_HEADER(channel)); if (dsi->debug_read) DSSDBG("\theader: %08x\n", val); dt = FLD_GET(val, 5, 0); @@ -3133,7 +3054,7 @@ static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel, /* two byte checksum ends the packet, not included in len */ for (w = 0; w < len + 2;) { int b; - val = dsi_read_reg(dsidev, + val = dsi_read_reg(dsi, DSI_VC_SHORT_PACKET_HEADER(channel)); if (dsi->debug_read) DSSDBG("\t\t%02x %02x %02x %02x\n", @@ -3168,9 +3089,10 @@ static int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_c u8 *buf, int buflen) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; - r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd); + r = dsi_vc_dcs_send_read_request(dsi, channel, dcs_cmd); if (r) goto err; @@ -3178,7 +3100,7 @@ static int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_c if (r) goto err; - r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen, + r = dsi_vc_read_rx_fifo(dsi, channel, buf, buflen, DSS_DSI_CONTENT_DCS); if (r < 0) goto err; @@ -3198,9 +3120,10 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, u8 *reqdata, int reqlen, u8 *buf, int buflen) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; - r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen); + r = dsi_vc_generic_send_read_request(dsi, channel, reqdata, reqlen); if (r) return r; @@ -3208,7 +3131,7 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, if (r) return r; - r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen, + r = dsi_vc_read_rx_fifo(dsi, channel, buf, buflen, DSS_DSI_CONTENT_GENERIC); if (r < 0) return r; @@ -3225,21 +3148,21 @@ static int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int cha u16 len) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - return dsi_vc_send_short(dsidev, channel, + return dsi_vc_send_short(dsi, channel, MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0); } -static int dsi_enter_ulps(struct platform_device *dsidev) +static int dsi_enter_ulps(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DECLARE_COMPLETION_ONSTACK(completion); int r, i; unsigned int mask; DSSDBG("Entering ULPS"); - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); WARN_ON(dsi->ulps_enabled); @@ -3247,35 +3170,35 @@ static int dsi_enter_ulps(struct platform_device *dsidev) return 0; /* DDR_CLK_ALWAYS_ON */ - if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) { - dsi_if_enable(dsidev, 0); - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13); - dsi_if_enable(dsidev, 1); + if (REG_GET(dsi, DSI_CLK_CTRL, 13, 13)) { + dsi_if_enable(dsi, 0); + REG_FLD_MOD(dsi, DSI_CLK_CTRL, 0, 13, 13); + dsi_if_enable(dsi, 1); } - dsi_sync_vc(dsidev, 0); - dsi_sync_vc(dsidev, 1); - dsi_sync_vc(dsidev, 2); - dsi_sync_vc(dsidev, 3); + dsi_sync_vc(dsi, 0); + dsi_sync_vc(dsi, 1); + dsi_sync_vc(dsi, 2); + dsi_sync_vc(dsi, 3); - dsi_force_tx_stop_mode_io(dsidev); + dsi_force_tx_stop_mode_io(dsi); - dsi_vc_enable(dsidev, 0, false); - dsi_vc_enable(dsidev, 1, false); - dsi_vc_enable(dsidev, 2, false); - dsi_vc_enable(dsidev, 3, false); + dsi_vc_enable(dsi, 0, false); + dsi_vc_enable(dsi, 1, false); + dsi_vc_enable(dsi, 2, false); + dsi_vc_enable(dsi, 3, false); - if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 16, 16)) { /* HS_BUSY */ + if (REG_GET(dsi, DSI_COMPLEXIO_CFG2, 16, 16)) { /* HS_BUSY */ DSSERR("HS busy when enabling ULPS\n"); return -EIO; } - if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 17, 17)) { /* LP_BUSY */ + if (REG_GET(dsi, DSI_COMPLEXIO_CFG2, 17, 17)) { /* LP_BUSY */ DSSERR("LP busy when enabling ULPS\n"); return -EIO; } - r = dsi_register_isr_cio(dsidev, dsi_completion_handler, &completion, + r = dsi_register_isr_cio(dsi, dsi_completion_handler, &completion, DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); if (r) return r; @@ -3289,10 +3212,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev) } /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */ /* LANEx_ULPS_SIG2 */ - REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5); + REG_FLD_MOD(dsi, DSI_COMPLEXIO_CFG2, mask, 9, 5); /* flush posted write and wait for SCP interface to finish the write */ - dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); + dsi_read_reg(dsi, DSI_COMPLEXIO_CFG2); if (wait_for_completion_timeout(&completion, msecs_to_jiffies(1000)) == 0) { @@ -3301,31 +3224,31 @@ static int dsi_enter_ulps(struct platform_device *dsidev) goto err; } - dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion, + dsi_unregister_isr_cio(dsi, dsi_completion_handler, &completion, DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); /* Reset LANEx_ULPS_SIG2 */ - REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5); + REG_FLD_MOD(dsi, DSI_COMPLEXIO_CFG2, 0, 9, 5); /* flush posted write and wait for SCP interface to finish the write */ - dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); + dsi_read_reg(dsi, DSI_COMPLEXIO_CFG2); - dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); + dsi_cio_power(dsi, DSI_COMPLEXIO_POWER_ULPS); - dsi_if_enable(dsidev, false); + dsi_if_enable(dsi, false); dsi->ulps_enabled = true; return 0; err: - dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion, + dsi_unregister_isr_cio(dsi, dsi_completion_handler, &completion, DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); return r; } -static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, - unsigned int ticks, bool x4, bool x16) +static void dsi_set_lp_rx_timeout(struct dsi_data *dsi, unsigned int ticks, + bool x4, bool x16) { unsigned long fck; unsigned long total_ticks; @@ -3334,14 +3257,14 @@ static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, BUG_ON(ticks > 0x1fff); /* ticks in DSI_FCK */ - fck = dsi_fclk_rate(dsidev); + fck = dsi_fclk_rate(dsi); - r = dsi_read_reg(dsidev, DSI_TIMING2); + r = dsi_read_reg(dsi, DSI_TIMING2); r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */ r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */ r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */ r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */ - dsi_write_reg(dsidev, DSI_TIMING2, r); + dsi_write_reg(dsi, DSI_TIMING2, r); total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); @@ -3351,8 +3274,8 @@ static void dsi_set_lp_rx_timeout(struct platform_device *dsidev, (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_ta_timeout(struct platform_device *dsidev, - unsigned int ticks, bool x8, bool x16) +static void dsi_set_ta_timeout(struct dsi_data *dsi, unsigned int ticks, + bool x8, bool x16) { unsigned long fck; unsigned long total_ticks; @@ -3361,14 +3284,14 @@ static void dsi_set_ta_timeout(struct platform_device *dsidev, BUG_ON(ticks > 0x1fff); /* ticks in DSI_FCK */ - fck = dsi_fclk_rate(dsidev); + fck = dsi_fclk_rate(dsi); - r = dsi_read_reg(dsidev, DSI_TIMING1); + r = dsi_read_reg(dsi, DSI_TIMING1); r = FLD_MOD(r, 1, 31, 31); /* TA_TO */ r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */ r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */ r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */ - dsi_write_reg(dsidev, DSI_TIMING1, r); + dsi_write_reg(dsi, DSI_TIMING1, r); total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1); @@ -3378,8 +3301,8 @@ static void dsi_set_ta_timeout(struct platform_device *dsidev, (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_stop_state_counter(struct platform_device *dsidev, - unsigned int ticks, bool x4, bool x16) +static void dsi_set_stop_state_counter(struct dsi_data *dsi, unsigned int ticks, + bool x4, bool x16) { unsigned long fck; unsigned long total_ticks; @@ -3388,14 +3311,14 @@ static void dsi_set_stop_state_counter(struct platform_device *dsidev, BUG_ON(ticks > 0x1fff); /* ticks in DSI_FCK */ - fck = dsi_fclk_rate(dsidev); + fck = dsi_fclk_rate(dsi); - r = dsi_read_reg(dsidev, DSI_TIMING1); + r = dsi_read_reg(dsi, DSI_TIMING1); r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */ r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */ r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */ - dsi_write_reg(dsidev, DSI_TIMING1, r); + dsi_write_reg(dsi, DSI_TIMING1, r); total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); @@ -3405,8 +3328,8 @@ static void dsi_set_stop_state_counter(struct platform_device *dsidev, (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, - unsigned int ticks, bool x4, bool x16) +static void dsi_set_hs_tx_timeout(struct dsi_data *dsi, unsigned int ticks, + bool x4, bool x16) { unsigned long fck; unsigned long total_ticks; @@ -3415,14 +3338,14 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, BUG_ON(ticks > 0x1fff); /* ticks in TxByteClkHS */ - fck = dsi_get_txbyteclkhs(dsidev); + fck = dsi_get_txbyteclkhs(dsi); - r = dsi_read_reg(dsidev, DSI_TIMING2); + r = dsi_read_reg(dsi, DSI_TIMING2); r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */ r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */ r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */ r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */ - dsi_write_reg(dsidev, DSI_TIMING2, r); + dsi_write_reg(dsi, DSI_TIMING2, r); total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); @@ -3432,9 +3355,8 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) +static void dsi_config_vp_num_line_buffers(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int num_line_buffers; if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { @@ -3454,12 +3376,11 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) } /* LINE_BUFFER */ - REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12); + REG_FLD_MOD(dsi, DSI_CTRL, num_line_buffers, 13, 12); } -static void dsi_config_vp_sync_events(struct platform_device *dsidev) +static void dsi_config_vp_sync_events(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); bool sync_end; u32 r; @@ -3468,7 +3389,7 @@ static void dsi_config_vp_sync_events(struct platform_device *dsidev) else sync_end = false; - r = dsi_read_reg(dsidev, DSI_CTRL); + r = dsi_read_reg(dsi, DSI_CTRL); r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */ r = FLD_MOD(r, 1, 10, 10); /* VP_HSYNC_POL */ r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */ @@ -3476,12 +3397,11 @@ static void dsi_config_vp_sync_events(struct platform_device *dsidev) r = FLD_MOD(r, sync_end, 16, 16); /* VP_VSYNC_END */ r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */ r = FLD_MOD(r, sync_end, 18, 18); /* VP_HSYNC_END */ - dsi_write_reg(dsidev, DSI_CTRL, r); + dsi_write_reg(dsi, DSI_CTRL, r); } -static void dsi_config_blanking_modes(struct platform_device *dsidev) +static void dsi_config_blanking_modes(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int blanking_mode = dsi->vm_timings.blanking_mode; int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode; int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode; @@ -3492,12 +3412,12 @@ static void dsi_config_blanking_modes(struct platform_device *dsidev) * 0 = TX FIFO packets sent or LPS in corresponding blanking periods * 1 = Long blanking packets are sent in corresponding blanking periods */ - r = dsi_read_reg(dsidev, DSI_CTRL); + r = dsi_read_reg(dsi, DSI_CTRL); r = FLD_MOD(r, blanking_mode, 20, 20); /* BLANKING_MODE */ r = FLD_MOD(r, hfp_blanking_mode, 21, 21); /* HFP_BLANKING */ r = FLD_MOD(r, hbp_blanking_mode, 22, 22); /* HBP_BLANKING */ r = FLD_MOD(r, hsa_blanking_mode, 23, 23); /* HSA_BLANKING */ - dsi_write_reg(dsidev, DSI_CTRL, r); + dsi_write_reg(dsi, DSI_CTRL, r); } /* @@ -3562,9 +3482,8 @@ static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs, return max(lp_inter, 0); } -static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev) +static void dsi_config_cmd_mode_interleaving(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int blanking_mode; int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode; int hsa, hfp, hbp, width_bytes, bllp, lp_clk_div; @@ -3581,33 +3500,33 @@ static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev) int bl_interleave_hs = 0, bl_interleave_lp = 0; u32 r; - r = dsi_read_reg(dsidev, DSI_CTRL); + r = dsi_read_reg(dsi, DSI_CTRL); blanking_mode = FLD_GET(r, 20, 20); hfp_blanking_mode = FLD_GET(r, 21, 21); hbp_blanking_mode = FLD_GET(r, 22, 22); hsa_blanking_mode = FLD_GET(r, 23, 23); - r = dsi_read_reg(dsidev, DSI_VM_TIMING1); + r = dsi_read_reg(dsi, DSI_VM_TIMING1); hbp = FLD_GET(r, 11, 0); hfp = FLD_GET(r, 23, 12); hsa = FLD_GET(r, 31, 24); - r = dsi_read_reg(dsidev, DSI_CLK_TIMING); + r = dsi_read_reg(dsi, DSI_CLK_TIMING); ddr_clk_post = FLD_GET(r, 7, 0); ddr_clk_pre = FLD_GET(r, 15, 8); - r = dsi_read_reg(dsidev, DSI_VM_TIMING7); + r = dsi_read_reg(dsi, DSI_VM_TIMING7); exit_hs_mode_lat = FLD_GET(r, 15, 0); enter_hs_mode_lat = FLD_GET(r, 31, 16); - r = dsi_read_reg(dsidev, DSI_CLK_CTRL); + r = dsi_read_reg(dsi, DSI_CLK_CTRL); lp_clk_div = FLD_GET(r, 12, 0); ddr_alwon = FLD_GET(r, 13, 13); - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG0); ths_exit = FLD_GET(r, 7, 0); - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG1); tclk_trail = FLD_GET(r, 15, 8); exiths_clk = ths_exit + tclk_trail; @@ -3661,45 +3580,44 @@ static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev) hsa_interleave_lp, hfp_interleave_lp, hbp_interleave_lp, bl_interleave_lp); - r = dsi_read_reg(dsidev, DSI_VM_TIMING4); + r = dsi_read_reg(dsi, DSI_VM_TIMING4); r = FLD_MOD(r, hsa_interleave_hs, 23, 16); r = FLD_MOD(r, hfp_interleave_hs, 15, 8); r = FLD_MOD(r, hbp_interleave_hs, 7, 0); - dsi_write_reg(dsidev, DSI_VM_TIMING4, r); + dsi_write_reg(dsi, DSI_VM_TIMING4, r); - r = dsi_read_reg(dsidev, DSI_VM_TIMING5); + r = dsi_read_reg(dsi, DSI_VM_TIMING5); r = FLD_MOD(r, hsa_interleave_lp, 23, 16); r = FLD_MOD(r, hfp_interleave_lp, 15, 8); r = FLD_MOD(r, hbp_interleave_lp, 7, 0); - dsi_write_reg(dsidev, DSI_VM_TIMING5, r); + dsi_write_reg(dsi, DSI_VM_TIMING5, r); - r = dsi_read_reg(dsidev, DSI_VM_TIMING6); + r = dsi_read_reg(dsi, DSI_VM_TIMING6); r = FLD_MOD(r, bl_interleave_hs, 31, 15); r = FLD_MOD(r, bl_interleave_lp, 16, 0); - dsi_write_reg(dsidev, DSI_VM_TIMING6, r); + dsi_write_reg(dsi, DSI_VM_TIMING6, r); } -static int dsi_proto_config(struct platform_device *dsidev) +static int dsi_proto_config(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; int buswidth = 0; - dsi_config_tx_fifo(dsidev, DSI_FIFO_SIZE_32, + dsi_config_tx_fifo(dsi, DSI_FIFO_SIZE_32, DSI_FIFO_SIZE_32, DSI_FIFO_SIZE_32, DSI_FIFO_SIZE_32); - dsi_config_rx_fifo(dsidev, DSI_FIFO_SIZE_32, + dsi_config_rx_fifo(dsi, DSI_FIFO_SIZE_32, DSI_FIFO_SIZE_32, DSI_FIFO_SIZE_32, DSI_FIFO_SIZE_32); /* XXX what values for the timeouts? */ - dsi_set_stop_state_counter(dsidev, 0x1000, false, false); - dsi_set_ta_timeout(dsidev, 0x1fff, true, true); - dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true); - dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true); + dsi_set_stop_state_counter(dsi, 0x1000, false, false); + dsi_set_ta_timeout(dsi, 0x1fff, true, true); + dsi_set_lp_rx_timeout(dsi, 0x1fff, true, true); + dsi_set_hs_tx_timeout(dsi, 0x1fff, true, true); switch (dsi_get_pixel_size(dsi->pix_fmt)) { case 16: @@ -3716,7 +3634,7 @@ static int dsi_proto_config(struct platform_device *dsidev) return -EINVAL; } - r = dsi_read_reg(dsidev, DSI_CTRL); + r = dsi_read_reg(dsi, DSI_CTRL); r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */ r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */ r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */ @@ -3731,27 +3649,26 @@ static int dsi_proto_config(struct platform_device *dsidev) r = FLD_MOD(r, 0, 25, 25); } - dsi_write_reg(dsidev, DSI_CTRL, r); + dsi_write_reg(dsi, DSI_CTRL, r); - dsi_config_vp_num_line_buffers(dsidev); + dsi_config_vp_num_line_buffers(dsi); if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { - dsi_config_vp_sync_events(dsidev); - dsi_config_blanking_modes(dsidev); - dsi_config_cmd_mode_interleaving(dsidev); + dsi_config_vp_sync_events(dsi); + dsi_config_blanking_modes(dsi); + dsi_config_cmd_mode_interleaving(dsi); } - dsi_vc_initial_config(dsidev, 0); - dsi_vc_initial_config(dsidev, 1); - dsi_vc_initial_config(dsidev, 2); - dsi_vc_initial_config(dsidev, 3); + dsi_vc_initial_config(dsi, 0); + dsi_vc_initial_config(dsi, 1); + dsi_vc_initial_config(dsi, 2); + dsi_vc_initial_config(dsi, 3); return 0; } -static void dsi_proto_timings(struct platform_device *dsidev) +static void dsi_proto_timings(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned int tlpx, tclk_zero, tclk_prepare, tclk_trail; unsigned int tclk_pre, tclk_post; unsigned int ths_prepare, ths_prepare_ths_zero, ths_zero; @@ -3762,25 +3679,25 @@ static void dsi_proto_timings(struct platform_device *dsidev) int ndl = dsi->num_lanes_used - 1; u32 r; - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG0); ths_prepare = FLD_GET(r, 31, 24); ths_prepare_ths_zero = FLD_GET(r, 23, 16); ths_zero = ths_prepare_ths_zero - ths_prepare; ths_trail = FLD_GET(r, 15, 8); ths_exit = FLD_GET(r, 7, 0); - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG1); tlpx = FLD_GET(r, 20, 16) * 2; tclk_trail = FLD_GET(r, 15, 8); tclk_zero = FLD_GET(r, 7, 0); - r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); + r = dsi_read_reg(dsi, DSI_DSIPHY_CFG2); tclk_prepare = FLD_GET(r, 7, 0); /* min 8*UI */ tclk_pre = 20; /* min 60ns + 52*UI */ - tclk_post = ns2ddr(dsidev, 60) + 26; + tclk_post = ns2ddr(dsi, 60) + 26; ths_eot = DIV_ROUND_UP(4, ndl); @@ -3791,10 +3708,10 @@ static void dsi_proto_timings(struct platform_device *dsidev) BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255); BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255); - r = dsi_read_reg(dsidev, DSI_CLK_TIMING); + r = dsi_read_reg(dsi, DSI_CLK_TIMING); r = FLD_MOD(r, ddr_clk_pre, 15, 8); r = FLD_MOD(r, ddr_clk_post, 7, 0); - dsi_write_reg(dsidev, DSI_CLK_TIMING, r); + dsi_write_reg(dsi, DSI_CLK_TIMING, r); DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n", ddr_clk_pre, @@ -3808,7 +3725,7 @@ static void dsi_proto_timings(struct platform_device *dsidev) r = FLD_VAL(enter_hs_mode_lat, 31, 16) | FLD_VAL(exit_hs_mode_lat, 15, 0); - dsi_write_reg(dsidev, DSI_VM_TIMING7, r); + dsi_write_reg(dsi, DSI_VM_TIMING7, r); DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n", enter_hs_mode_lat, exit_hs_mode_lat); @@ -3842,23 +3759,23 @@ static void dsi_proto_timings(struct platform_device *dsidev) DSSDBG("VBP: %d, VFP: %d, VSA: %d, VACT: %d lines\n", vbp, vfp, vsa, vm->vactive); - r = dsi_read_reg(dsidev, DSI_VM_TIMING1); + r = dsi_read_reg(dsi, DSI_VM_TIMING1); r = FLD_MOD(r, hbp, 11, 0); /* HBP */ r = FLD_MOD(r, hfp, 23, 12); /* HFP */ r = FLD_MOD(r, hsync_end ? hsa : 0, 31, 24); /* HSA */ - dsi_write_reg(dsidev, DSI_VM_TIMING1, r); + dsi_write_reg(dsi, DSI_VM_TIMING1, r); - r = dsi_read_reg(dsidev, DSI_VM_TIMING2); + r = dsi_read_reg(dsi, DSI_VM_TIMING2); r = FLD_MOD(r, vbp, 7, 0); /* VBP */ r = FLD_MOD(r, vfp, 15, 8); /* VFP */ r = FLD_MOD(r, vsa, 23, 16); /* VSA */ r = FLD_MOD(r, window_sync, 27, 24); /* WINDOW_SYNC */ - dsi_write_reg(dsidev, DSI_VM_TIMING2, r); + dsi_write_reg(dsi, DSI_VM_TIMING2, r); - r = dsi_read_reg(dsidev, DSI_VM_TIMING3); + r = dsi_read_reg(dsi, DSI_VM_TIMING3); r = FLD_MOD(r, vm->vactive, 14, 0); /* VACT */ r = FLD_MOD(r, tl, 31, 16); /* TL */ - dsi_write_reg(dsidev, DSI_VM_TIMING3, r); + dsi_write_reg(dsi, DSI_VM_TIMING3, r); } } @@ -3945,7 +3862,7 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) return -ENODEV; } - r = dsi_display_init_dispc(dsidev, dispc_channel); + r = dsi_display_init_dispc(dsi, dispc_channel); if (r) goto err_init_dispc; @@ -3968,19 +3885,19 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) goto err_pix_fmt; } - dsi_if_enable(dsidev, false); - dsi_vc_enable(dsidev, channel, false); + dsi_if_enable(dsi, false); + dsi_vc_enable(dsi, channel, false); /* MODE, 1 = video mode */ - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), 1, 4, 4); word_count = DIV_ROUND_UP(dsi->vm.hactive * bpp, 8); - dsi_vc_write_long_header(dsidev, channel, data_type, + dsi_vc_write_long_header(dsi, channel, data_type, word_count, 0); - dsi_vc_enable(dsidev, channel, true); - dsi_if_enable(dsidev, true); + dsi_vc_enable(dsi, channel, true); + dsi_if_enable(dsi, true); } r = dss_mgr_enable(dispc_channel); @@ -3991,11 +3908,11 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) err_mgr_enable: if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { - dsi_if_enable(dsidev, false); - dsi_vc_enable(dsidev, channel, false); + dsi_if_enable(dsi, false); + dsi_vc_enable(dsi, channel, false); } err_pix_fmt: - dsi_display_uninit_dispc(dsidev, dispc_channel); + dsi_display_uninit_dispc(dsi, dispc_channel); err_init_dispc: return r; } @@ -4007,24 +3924,23 @@ static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel enum omap_channel dispc_channel = dssdev->dispc_channel; if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { - dsi_if_enable(dsidev, false); - dsi_vc_enable(dsidev, channel, false); + dsi_if_enable(dsi, false); + dsi_vc_enable(dsi, channel, false); /* MODE, 0 = command mode */ - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); + REG_FLD_MOD(dsi, DSI_VC_CTRL(channel), 0, 4, 4); - dsi_vc_enable(dsidev, channel, true); - dsi_if_enable(dsidev, true); + dsi_vc_enable(dsi, channel, true); + dsi_if_enable(dsi, true); } dss_mgr_disable(dispc_channel); - dsi_display_uninit_dispc(dsidev, dispc_channel); + dsi_display_uninit_dispc(dsi, dispc_channel); } -static void dsi_update_screen_dispc(struct platform_device *dsidev) +static void dsi_update_screen_dispc(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); enum omap_channel dispc_channel = dsi->output.dispc_channel; unsigned int bytespp; unsigned int bytespl; @@ -4041,7 +3957,7 @@ static void dsi_update_screen_dispc(struct platform_device *dsidev) DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h); - dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); + dsi_vc_config_source(dsi, channel, DSI_VC_SOURCE_VP); bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8; bytespl = w * bytespp; @@ -4062,16 +3978,16 @@ static void dsi_update_screen_dispc(struct platform_device *dsidev) total_len += (bytespf % packet_payload) + 1; l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */ - dsi_write_reg(dsidev, DSI_VC_TE(channel), l); + dsi_write_reg(dsi, DSI_VC_TE(channel), l); - dsi_vc_write_long_header(dsidev, channel, MIPI_DSI_DCS_LONG_WRITE, + dsi_vc_write_long_header(dsi, channel, MIPI_DSI_DCS_LONG_WRITE, packet_len, 0); if (dsi->te_enabled) l = FLD_MOD(l, 1, 30, 30); /* TE_EN */ else l = FLD_MOD(l, 1, 31, 31); /* TE_START */ - dsi_write_reg(dsidev, DSI_VC_TE(channel), l); + dsi_write_reg(dsi, DSI_VC_TE(channel), l); /* We put SIDLEMODE to no-idle for the duration of the transfer, * because DSS interrupts are not capable of waking up the CPU and the @@ -4081,7 +3997,7 @@ static void dsi_update_screen_dispc(struct platform_device *dsidev) */ dispc_disable_sidle(); - dsi_perf_mark_start(dsidev); + dsi_perf_mark_start(dsi); r = schedule_delayed_work(&dsi->framedone_timeout_work, msecs_to_jiffies(250)); @@ -4094,9 +4010,9 @@ static void dsi_update_screen_dispc(struct platform_device *dsidev) if (dsi->te_enabled) { /* disable LP_RX_TO, so that we can receive TE. Time to wait * for TE is longer than the timer allows */ - REG_FLD_MOD(dsidev, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */ + REG_FLD_MOD(dsi, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */ - dsi_vc_send_bta(dsidev, channel); + dsi_vc_send_bta(dsi, channel); #ifdef DSI_CATCH_MISSING_TE mod_timer(&dsi->te_timer, jiffies + msecs_to_jiffies(250)); @@ -4111,22 +4027,20 @@ static void dsi_te_timeout(struct timer_list *unused) } #endif -static void dsi_handle_framedone(struct platform_device *dsidev, int error) +static void dsi_handle_framedone(struct dsi_data *dsi, int error) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - /* SIDLEMODE back to smart-idle */ dispc_enable_sidle(); if (dsi->te_enabled) { /* enable LP_RX_TO again after the TE */ - REG_FLD_MOD(dsidev, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ + REG_FLD_MOD(dsi, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ } dsi->framedone_callback(error, dsi->framedone_data); if (!error) - dsi_perf_show(dsidev, "DISPC"); + dsi_perf_show(dsi, "DISPC"); } static void dsi_framedone_timeout_work_callback(struct work_struct *work) @@ -4142,13 +4056,12 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) DSSERR("Framedone not received for 250ms!\n"); - dsi_handle_framedone(dsi->pdev, -ETIMEDOUT); + dsi_handle_framedone(dsi, -ETIMEDOUT); } static void dsi_framedone_irq_callback(void *data) { - struct platform_device *dsidev = (struct platform_device *) data; - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = data; /* Note: We get FRAMEDONE when DISPC has finished sending pixels and * turns itself off. However, DSI still has the pixels in its buffers, @@ -4157,7 +4070,7 @@ static void dsi_framedone_irq_callback(void *data) cancel_delayed_work(&dsi->framedone_timeout_work); - dsi_handle_framedone(dsidev, 0); + dsi_handle_framedone(dsi, 0); } static int dsi_update(struct omap_dss_device *dssdev, int channel, @@ -4167,7 +4080,7 @@ static int dsi_update(struct omap_dss_device *dssdev, int channel, struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u16 dw, dh; - dsi_perf_mark_setup(dsidev); + dsi_perf_mark_setup(dsi); dsi->update_channel = channel; @@ -4181,21 +4094,20 @@ static int dsi_update(struct omap_dss_device *dssdev, int channel, dsi->update_bytes = dw * dh * dsi_get_pixel_size(dsi->pix_fmt) / 8; #endif - dsi_update_screen_dispc(dsidev); + dsi_update_screen_dispc(dsi); return 0; } /* Display funcs */ -static int dsi_configure_dispc_clocks(struct platform_device *dsidev) +static int dsi_configure_dispc_clocks(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dispc_clock_info dispc_cinfo; int r; unsigned long fck; - fck = dsi_get_pll_hsdiv_dispc_rate(dsidev); + fck = dsi_get_pll_hsdiv_dispc_rate(dsi); dispc_cinfo.lck_div = dsi->user_dispc_cinfo.lck_div; dispc_cinfo.pck_div = dsi->user_dispc_cinfo.pck_div; @@ -4211,10 +4123,9 @@ static int dsi_configure_dispc_clocks(struct platform_device *dsidev) return 0; } -static int dsi_display_init_dispc(struct platform_device *dsidev, - enum omap_channel channel) +static int dsi_display_init_dispc(struct dsi_data *dsi, + enum omap_channel channel) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; dss_select_lcd_clk_source(dsi->dss, channel, dsi->module_id == 0 ? @@ -4223,7 +4134,7 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { r = dss_mgr_register_framedone_handler(channel, - dsi_framedone_irq_callback, dsidev); + dsi_framedone_irq_callback, dsi); if (r) { DSSERR("can't register FRAMEDONE handler\n"); goto err; @@ -4254,7 +4165,7 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, dss_mgr_set_timings(channel, &dsi->vm); - r = dsi_configure_dispc_clocks(dsidev); + r = dsi_configure_dispc_clocks(dsi); if (r) goto err1; @@ -4269,27 +4180,24 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, err1: if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) dss_mgr_unregister_framedone_handler(channel, - dsi_framedone_irq_callback, dsidev); + dsi_framedone_irq_callback, dsi); err: dss_select_lcd_clk_source(dsi->dss, channel, DSS_CLK_SRC_FCK); return r; } -static void dsi_display_uninit_dispc(struct platform_device *dsidev, - enum omap_channel channel) +static void dsi_display_uninit_dispc(struct dsi_data *dsi, + enum omap_channel channel) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) dss_mgr_unregister_framedone_handler(channel, - dsi_framedone_irq_callback, dsidev); + dsi_framedone_irq_callback, dsi); dss_select_lcd_clk_source(dsi->dss, channel, DSS_CLK_SRC_FCK); } -static int dsi_configure_dsi_clocks(struct platform_device *dsidev) +static int dsi_configure_dsi_clocks(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dss_pll_clock_info cinfo; int r; @@ -4304,16 +4212,15 @@ static int dsi_configure_dsi_clocks(struct platform_device *dsidev) return 0; } -static int dsi_display_init_dsi(struct platform_device *dsidev) +static int dsi_display_init_dsi(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; r = dss_pll_enable(&dsi->pll); if (r) goto err0; - r = dsi_configure_dsi_clocks(dsidev); + r = dsi_configure_dsi_clocks(dsi); if (r) goto err1; @@ -4323,33 +4230,33 @@ static int dsi_display_init_dsi(struct platform_device *dsidev) DSSDBG("PLL OK\n"); - r = dsi_cio_init(dsidev); + r = dsi_cio_init(dsi); if (r) goto err2; - _dsi_print_reset_status(dsidev); + _dsi_print_reset_status(dsi); - dsi_proto_timings(dsidev); - dsi_set_lp_clk_divisor(dsidev); + dsi_proto_timings(dsi); + dsi_set_lp_clk_divisor(dsi); if (1) - _dsi_print_reset_status(dsidev); + _dsi_print_reset_status(dsi); - r = dsi_proto_config(dsidev); + r = dsi_proto_config(dsi); if (r) goto err3; /* enable interface */ - dsi_vc_enable(dsidev, 0, 1); - dsi_vc_enable(dsidev, 1, 1); - dsi_vc_enable(dsidev, 2, 1); - dsi_vc_enable(dsidev, 3, 1); - dsi_if_enable(dsidev, 1); - dsi_force_tx_stop_mode_io(dsidev); + dsi_vc_enable(dsi, 0, 1); + dsi_vc_enable(dsi, 1, 1); + dsi_vc_enable(dsi, 2, 1); + dsi_vc_enable(dsi, 3, 1); + dsi_if_enable(dsi, 1); + dsi_force_tx_stop_mode_io(dsi); return 0; err3: - dsi_cio_uninit(dsidev); + dsi_cio_uninit(dsi); err2: dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); err1: @@ -4358,24 +4265,22 @@ err0: return r; } -static void dsi_display_uninit_dsi(struct platform_device *dsidev, - bool disconnect_lanes, bool enter_ulps) +static void dsi_display_uninit_dsi(struct dsi_data *dsi, bool disconnect_lanes, + bool enter_ulps) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (enter_ulps && !dsi->ulps_enabled) - dsi_enter_ulps(dsidev); + dsi_enter_ulps(dsi); /* disable interface */ - dsi_if_enable(dsidev, 0); - dsi_vc_enable(dsidev, 0, 0); - dsi_vc_enable(dsidev, 1, 0); - dsi_vc_enable(dsidev, 2, 0); - dsi_vc_enable(dsidev, 3, 0); + dsi_if_enable(dsi, 0); + dsi_vc_enable(dsi, 0, 0); + dsi_vc_enable(dsi, 1, 0); + dsi_vc_enable(dsi, 2, 0); + dsi_vc_enable(dsi, 3, 0); dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); - dsi_cio_uninit(dsidev); - dsi_pll_uninit(dsidev, disconnect_lanes); + dsi_cio_uninit(dsi); + dsi_pll_uninit(dsi, disconnect_lanes); } static int dsi_display_enable(struct omap_dss_device *dssdev) @@ -4386,17 +4291,17 @@ static int dsi_display_enable(struct omap_dss_device *dssdev) DSSDBG("dsi_display_enable\n"); - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); mutex_lock(&dsi->lock); - r = dsi_runtime_get(dsidev); + r = dsi_runtime_get(dsi); if (r) goto err_get_dsi; - _dsi_initialize_irq(dsidev); + _dsi_initialize_irq(dsi); - r = dsi_display_init_dsi(dsidev); + r = dsi_display_init_dsi(dsi); if (r) goto err_init_dsi; @@ -4405,7 +4310,7 @@ static int dsi_display_enable(struct omap_dss_device *dssdev) return 0; err_init_dsi: - dsi_runtime_put(dsidev); + dsi_runtime_put(dsi); err_get_dsi: mutex_unlock(&dsi->lock); DSSDBG("dsi_display_enable FAILED\n"); @@ -4420,18 +4325,18 @@ static void dsi_display_disable(struct omap_dss_device *dssdev, DSSDBG("dsi_display_disable\n"); - WARN_ON(!dsi_bus_is_locked(dsidev)); + WARN_ON(!dsi_bus_is_locked(dsi)); mutex_lock(&dsi->lock); - dsi_sync_vc(dsidev, 0); - dsi_sync_vc(dsidev, 1); - dsi_sync_vc(dsidev, 2); - dsi_sync_vc(dsidev, 3); + dsi_sync_vc(dsi, 0); + dsi_sync_vc(dsi, 1); + dsi_sync_vc(dsi, 2); + dsi_sync_vc(dsi, 3); - dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps); + dsi_display_uninit_dsi(dsi, disconnect_lanes, enter_ulps); - dsi_runtime_put(dsidev); + dsi_runtime_put(dsi); mutex_unlock(&dsi->lock); } @@ -4568,7 +4473,7 @@ static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint, unsigned long clkdco, void *data) { struct dsi_clk_calc_ctx *ctx = data; - struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev); + struct dsi_data *dsi = ctx->dsi; ctx->dsi_cinfo.n = n; ctx->dsi_cinfo.m = m; @@ -4604,7 +4509,7 @@ static bool dsi_cm_calc(struct dsi_data *dsi, txbyteclk = pck * bitspp / 8 / ndl; memset(ctx, 0, sizeof(*ctx)); - ctx->dsidev = dsi->pdev; + ctx->dsi = dsi; ctx->pll = &dsi->pll; ctx->config = cfg; ctx->req_pck_min = pck; @@ -4621,7 +4526,7 @@ static bool dsi_cm_calc(struct dsi_data *dsi, static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx) { - struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev); + struct dsi_data *dsi = ctx->dsi; const struct omap_dss_dsi_config *cfg = ctx->config; int bitspp = dsi_get_pixel_size(cfg->pixel_format); int ndl = dsi->num_lanes_used - 1; @@ -4868,7 +4773,7 @@ static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint, unsigned long clkdco, void *data) { struct dsi_clk_calc_ctx *ctx = data; - struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev); + struct dsi_data *dsi = ctx->dsi; ctx->dsi_cinfo.n = n; ctx->dsi_cinfo.m = m; @@ -4895,7 +4800,7 @@ static bool dsi_vm_calc(struct dsi_data *dsi, clkin = clk_get_rate(dsi->pll.clkin); memset(ctx, 0, sizeof(*ctx)); - ctx->dsidev = dsi->pdev; + ctx->dsi = dsi; ctx->pll = &dsi->pll; ctx->config = cfg; @@ -5068,12 +4973,11 @@ static void dsi_release_vc(struct omap_dss_device *dssdev, int channel) } -static int dsi_get_clocks(struct platform_device *dsidev) +static int dsi_get_clocks(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct clk *clk; - clk = devm_clk_get(&dsidev->dev, "fck"); + clk = devm_clk_get(&dsi->pdev->dev, "fck"); if (IS_ERR(clk)) { DSSERR("can't get fck\n"); return PTR_ERR(clk); @@ -5088,10 +4992,11 @@ static int dsi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); enum omap_channel dispc_channel = dssdev->dispc_channel; int r; - r = dsi_regulator_init(dsidev); + r = dsi_regulator_init(dsi); if (r) return r; @@ -5164,12 +5069,11 @@ static const struct omapdss_dsi_ops dsi_ops = { .set_max_rx_packet_size = dsi_vc_set_max_rx_packet_size, }; -static void dsi_init_output(struct platform_device *dsidev) +static void dsi_init_output(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct omap_dss_device *out = &dsi->output; - out->dev = &dsidev->dev; + out->dev = &dsi->pdev->dev; out->id = dsi->module_id == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; @@ -5182,18 +5086,16 @@ static void dsi_init_output(struct platform_device *dsidev) omapdss_register_output(out); } -static void dsi_uninit_output(struct platform_device *dsidev) +static void dsi_uninit_output(struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct omap_dss_device *out = &dsi->output; omapdss_unregister_output(out); } -static int dsi_probe_of(struct platform_device *pdev) +static int dsi_probe_of(struct dsi_data *dsi) { - struct device_node *node = pdev->dev.of_node; - struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + struct device_node *node = dsi->pdev->dev.of_node; struct property *prop; u32 lane_arr[10]; int len, num_pins; @@ -5207,7 +5109,7 @@ static int dsi_probe_of(struct platform_device *pdev) prop = of_find_property(ep, "lanes", &len); if (prop == NULL) { - dev_err(&pdev->dev, "failed to find lane data\n"); + dev_err(&dsi->pdev->dev, "failed to find lane data\n"); r = -EINVAL; goto err; } @@ -5216,14 +5118,14 @@ static int dsi_probe_of(struct platform_device *pdev) if (num_pins < 4 || num_pins % 2 != 0 || num_pins > dsi->num_lanes_supported * 2) { - dev_err(&pdev->dev, "bad number of lanes\n"); + dev_err(&dsi->pdev->dev, "bad number of lanes\n"); r = -EINVAL; goto err; } r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins); if (r) { - dev_err(&pdev->dev, "failed to read lane data\n"); + dev_err(&dsi->pdev->dev, "failed to read lane data\n"); goto err; } @@ -5233,7 +5135,7 @@ static int dsi_probe_of(struct platform_device *pdev) r = dsi_configure_pins(&dsi->output, &pin_cfg); if (r) { - dev_err(&pdev->dev, "failed to configure pins"); + dev_err(&dsi->pdev->dev, "failed to configure pins"); goto err; } @@ -5333,15 +5235,13 @@ static const struct dss_pll_hw dss_omap5_dsi_pll_hw = { .has_refsel = true, }; -static int dsi_init_pll_data(struct dss_device *dss, - struct platform_device *dsidev) +static int dsi_init_pll_data(struct dss_device *dss, struct dsi_data *dsi) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dss_pll *pll = &dsi->pll; struct clk *clk; int r; - clk = devm_clk_get(&dsidev->dev, "sys_clk"); + clk = devm_clk_get(&dsi->pdev->dev, "sys_clk"); if (IS_ERR(clk)) { DSSERR("can't get sys_clk\n"); return PTR_ERR(clk); @@ -5487,7 +5387,7 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) } r = devm_request_irq(&dsidev->dev, dsi->irq, omap_dsi_irq_handler, - IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev); + IRQF_SHARED, dev_name(&dsidev->dev), dsi); if (r < 0) { DSSERR("request_irq failed\n"); return r; @@ -5535,19 +5435,19 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) dsi->vc[i].vc_id = 0; } - r = dsi_get_clocks(dsidev); + r = dsi_get_clocks(dsi); if (r) return r; - dsi_init_pll_data(dss, dsidev); + dsi_init_pll_data(dss, dsi); pm_runtime_enable(&dsidev->dev); - r = dsi_runtime_get(dsidev); + r = dsi_runtime_get(dsi); if (r) goto err_runtime_get; - rev = dsi_read_reg(dsidev, DSI_REVISION); + rev = dsi_read_reg(dsi, DSI_REVISION); dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); @@ -5555,15 +5455,15 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) * of data to 3 by default */ if (dsi->data->quirks & DSI_QUIRK_GNQ) /* NB_DATA_LANES */ - dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9); + dsi->num_lanes_supported = 1 + REG_GET(dsi, DSI_GNQ, 11, 9); else dsi->num_lanes_supported = 3; - dsi->line_buffer_size = dsi_get_line_buf_size(dsidev); + dsi->line_buffer_size = dsi_get_line_buf_size(dsi); - dsi_init_output(dsidev); + dsi_init_output(dsi); - r = dsi_probe_of(dsidev); + r = dsi_probe_of(dsi); if (r) { DSSERR("Invalid DSI DT data\n"); goto err_probe_of; @@ -5573,7 +5473,7 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) if (r) DSSERR("Failed to populate DSI child devices: %d\n", r); - dsi_runtime_put(dsidev); + dsi_runtime_put(dsi); if (dsi->module_id == 0) dsi->debugfs.regs = dss_debugfs_create_file(dss, "dsi1_regs", @@ -5597,8 +5497,8 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) return 0; err_probe_of: - dsi_uninit_output(dsidev); - dsi_runtime_put(dsidev); + dsi_uninit_output(dsi); + dsi_runtime_put(dsi); err_runtime_get: pm_runtime_disable(&dsidev->dev); @@ -5619,7 +5519,7 @@ static void dsi_unbind(struct device *dev, struct device *master, void *data) dss_pll_unregister(&dsi->pll); - dsi_uninit_output(dsidev); + dsi_uninit_output(dsi); pm_runtime_disable(&dsidev->dev); -- cgit v1.2.3 From c068408ef386e151e566ab96dd9e3103b264189b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:34 +0200 Subject: drm: omapdrm: dsi: Combine two commonly used inline functions The dsi_get_dsidrv_data() and dsi_get_dsidev_from_dssdev() inline functions convert a struct omap_dss_device pointer to the corresponding struct platform_device, and a struct platform_device pointer to the corresponding struct dsi_data. They are nearly always called together without any use of the intermediate platform_device, so combine them into a single function. In the three locations where only dsi_get_dsidrv_data() is used, call dev_get_drvdata() directly. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dsi.c | 90 +++++++++++++-------------------------- 1 file changed, 30 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 7b5656e6abbb..cb250dbf0f9b 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -439,14 +439,9 @@ static bool dsi_perf; module_param(dsi_perf, bool, 0644); #endif -static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev) +static inline struct dsi_data *to_dsi_data(struct omap_dss_device *dssdev) { - return dev_get_drvdata(&dsidev->dev); -} - -static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev) -{ - return to_platform_device(dssdev->dev); + return dev_get_drvdata(dssdev->dev); } static struct dsi_data *dsi_get_dsi_from_id(int module) @@ -467,7 +462,7 @@ static struct dsi_data *dsi_get_dsi_from_id(int module) out = omap_dss_get_output(id); - return out ? dsi_get_dsidrv_data(to_platform_device(out->dev)) : NULL; + return out ? to_dsi_data(out) : NULL; } static inline void dsi_write_reg(struct dsi_data *dsi, @@ -501,16 +496,14 @@ static inline u32 dsi_read_reg(struct dsi_data *dsi, const struct dsi_reg idx) static void dsi_bus_lock(struct omap_dss_device *dssdev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); down(&dsi->bus_lock); } static void dsi_bus_unlock(struct omap_dss_device *dssdev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); up(&dsi->bus_lock); } @@ -2534,8 +2527,7 @@ static int dsi_vc_config_source(struct dsi_data *dsi, int channel, static void dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, bool enable) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); @@ -2658,8 +2650,7 @@ static int dsi_vc_send_bta(struct dsi_data *dsi, int channel) static int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); DECLARE_COMPLETION_ONSTACK(completion); int r = 0; u32 err; @@ -2861,8 +2852,7 @@ static int dsi_vc_write_nosync_common(struct dsi_data *dsi, int channel, static int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, u8 *data, int len) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); return dsi_vc_write_nosync_common(dsi, channel, data, len, DSS_DSI_CONTENT_DCS); @@ -2871,8 +2861,7 @@ static int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, static int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel, u8 *data, int len) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); return dsi_vc_write_nosync_common(dsi, channel, data, len, DSS_DSI_CONTENT_GENERIC); @@ -2882,8 +2871,7 @@ static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel, u8 *data, int len, enum dss_dsi_content_type type) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); int r; r = dsi_vc_write_nosync_common(dsi, channel, data, len, type); @@ -3088,8 +3076,7 @@ err: static int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, u8 *buf, int buflen) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); int r; r = dsi_vc_dcs_send_read_request(dsi, channel, dcs_cmd); @@ -3119,8 +3106,7 @@ err: static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, u8 *reqdata, int reqlen, u8 *buf, int buflen) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); int r; r = dsi_vc_generic_send_read_request(dsi, channel, reqdata, reqlen); @@ -3147,8 +3133,7 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, static int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel, u16 len) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); return dsi_vc_send_short(dsi, channel, MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0); @@ -3782,8 +3767,7 @@ static void dsi_proto_timings(struct dsi_data *dsi) static int dsi_configure_pins(struct omap_dss_device *dssdev, const struct omap_dsi_pin_config *pin_cfg) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); int num_pins; const int *pins; struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; @@ -3848,8 +3832,7 @@ static int dsi_configure_pins(struct omap_dss_device *dssdev, static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); enum omap_channel dispc_channel = dssdev->dispc_channel; int bpp = dsi_get_pixel_size(dsi->pix_fmt); struct omap_dss_device *out = &dsi->output; @@ -3919,8 +3902,7 @@ err_init_dispc: static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); enum omap_channel dispc_channel = dssdev->dispc_channel; if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { @@ -4076,8 +4058,7 @@ static void dsi_framedone_irq_callback(void *data) static int dsi_update(struct omap_dss_device *dssdev, int channel, void (*callback)(int, void *), void *data) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); u16 dw, dh; dsi_perf_mark_setup(dsi); @@ -4285,8 +4266,7 @@ static void dsi_display_uninit_dsi(struct dsi_data *dsi, bool disconnect_lanes, static int dsi_display_enable(struct omap_dss_device *dssdev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); int r = 0; DSSDBG("dsi_display_enable\n"); @@ -4320,8 +4300,7 @@ err_get_dsi: static void dsi_display_disable(struct omap_dss_device *dssdev, bool disconnect_lanes, bool enter_ulps) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); DSSDBG("dsi_display_disable\n"); @@ -4343,8 +4322,7 @@ static void dsi_display_disable(struct omap_dss_device *dssdev, static int dsi_enable_te(struct omap_dss_device *dssdev, bool enable) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); dsi->te_enabled = enable; return 0; @@ -4830,8 +4808,7 @@ static bool dsi_vm_calc(struct dsi_data *dsi, static int dsi_set_config(struct omap_dss_device *dssdev, const struct omap_dss_dsi_config *config) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); struct dsi_clk_calc_ctx ctx; bool ok; int r; @@ -4918,8 +4895,7 @@ static enum omap_channel dsi_get_channel(struct dsi_data *dsi) static int dsi_request_vc(struct omap_dss_device *dssdev, int *channel) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); int i; for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) { @@ -4936,8 +4912,7 @@ static int dsi_request_vc(struct omap_dss_device *dssdev, int *channel) static int dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); if (vc_id < 0 || vc_id > 3) { DSSERR("VC ID out of range\n"); @@ -4962,8 +4937,7 @@ static int dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id) static void dsi_release_vc(struct omap_dss_device *dssdev, int channel) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); if ((channel >= 0 && channel <= 3) && dsi->vc[channel].dssdev == dssdev) { @@ -4991,8 +4965,7 @@ static int dsi_get_clocks(struct dsi_data *dsi) static int dsi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = to_dsi_data(dssdev); enum omap_channel dispc_channel = dssdev->dispc_channel; int r; @@ -5507,13 +5480,12 @@ err_runtime_get: static void dsi_unbind(struct device *dev, struct device *master, void *data) { - struct platform_device *dsidev = to_platform_device(dev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_data *dsi = dev_get_drvdata(dev); dss_debugfs_remove_file(dsi->debugfs.irqs); dss_debugfs_remove_file(dsi->debugfs.regs); - of_platform_depopulate(&dsidev->dev); + of_platform_depopulate(dev); WARN_ON(dsi->scp_clk_refcount > 0); @@ -5521,7 +5493,7 @@ static void dsi_unbind(struct device *dev, struct device *master, void *data) dsi_uninit_output(dsi); - pm_runtime_disable(&dsidev->dev); + pm_runtime_disable(dev); if (dsi->vdds_dsi_reg != NULL && dsi->vdds_dsi_enabled) { regulator_disable(dsi->vdds_dsi_reg); @@ -5547,8 +5519,7 @@ static int dsi_remove(struct platform_device *pdev) static int dsi_runtime_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + struct dsi_data *dsi = dev_get_drvdata(dev); dsi->is_enabled = false; /* ensure the irq handler sees the is_enabled value */ @@ -5563,8 +5534,7 @@ static int dsi_runtime_suspend(struct device *dev) static int dsi_runtime_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + struct dsi_data *dsi = dev_get_drvdata(dev); int r; r = dispc_runtime_get(); -- cgit v1.2.3 From c7963f5f13dfecb3e5d375b4d807927272bf28d0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:35 +0200 Subject: drm: omapdrm: dsi: Use dev pointer directly in dsi_bind() function The dsi_bind() function receives a pointer to a struct device that it casts to a struct platform_device, only to use the platform device's dev field through the code. Use the dev pointer directly. While at it rename the struct platform_device pointer dsidev to pdev to make it more explicit. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dsi.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index cb250dbf0f9b..62131d7593a7 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -5299,9 +5299,10 @@ static const struct soc_device_attribute dsi_soc_devices[] = { { .machine = "AM35*", .data = &dsi_of_data_omap34xx }, { /* sentinel */ } }; + static int dsi_bind(struct device *dev, struct device *master, void *data) { - struct platform_device *dsidev = to_platform_device(dev); + struct platform_device *pdev = to_platform_device(dev); struct dss_device *dss = dss_get_device(master); const struct soc_device_attribute *soc; const struct dsi_module_id_data *d; @@ -5311,13 +5312,13 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) struct resource *dsi_mem; struct resource *res; - dsi = devm_kzalloc(&dsidev->dev, sizeof(*dsi), GFP_KERNEL); + dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); if (!dsi) return -ENOMEM; dsi->dss = dss; - dsi->pdev = dsidev; - dev_set_drvdata(&dsidev->dev, dsi); + dsi->pdev = pdev; + dev_set_drvdata(dev, dsi); spin_lock_init(&dsi->irq_lock); spin_lock_init(&dsi->errors_lock); @@ -5338,29 +5339,29 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) timer_setup(&dsi->te_timer, dsi_te_timeout, 0); #endif - dsi_mem = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "proto"); - dsi->proto_base = devm_ioremap_resource(&dsidev->dev, dsi_mem); + dsi_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "proto"); + dsi->proto_base = devm_ioremap_resource(dev, dsi_mem); if (IS_ERR(dsi->proto_base)) return PTR_ERR(dsi->proto_base); - res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "phy"); - dsi->phy_base = devm_ioremap_resource(&dsidev->dev, res); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); + dsi->phy_base = devm_ioremap_resource(dev, res); if (IS_ERR(dsi->phy_base)) return PTR_ERR(dsi->phy_base); - res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "pll"); - dsi->pll_base = devm_ioremap_resource(&dsidev->dev, res); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); + dsi->pll_base = devm_ioremap_resource(dev, res); if (IS_ERR(dsi->pll_base)) return PTR_ERR(dsi->pll_base); - dsi->irq = platform_get_irq(dsi->pdev, 0); + dsi->irq = platform_get_irq(pdev, 0); if (dsi->irq < 0) { DSSERR("platform_get_irq failed\n"); return -ENODEV; } - r = devm_request_irq(&dsidev->dev, dsi->irq, omap_dsi_irq_handler, - IRQF_SHARED, dev_name(&dsidev->dev), dsi); + r = devm_request_irq(dev, dsi->irq, omap_dsi_irq_handler, + IRQF_SHARED, dev_name(dev), dsi); if (r < 0) { DSSERR("request_irq failed\n"); return r; @@ -5414,14 +5415,14 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) dsi_init_pll_data(dss, dsi); - pm_runtime_enable(&dsidev->dev); + pm_runtime_enable(dev); r = dsi_runtime_get(dsi); if (r) goto err_runtime_get; rev = dsi_read_reg(dsi, DSI_REVISION); - dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", + dev_dbg(dev, "OMAP DSI rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); /* DSI on OMAP3 doesn't have register DSI_GNQ, set number @@ -5442,7 +5443,7 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) goto err_probe_of; } - r = of_platform_populate(dsidev->dev.of_node, NULL, NULL, &dsidev->dev); + r = of_platform_populate(dev->of_node, NULL, NULL, dev); if (r) DSSERR("Failed to populate DSI child devices: %d\n", r); @@ -5474,7 +5475,7 @@ err_probe_of: dsi_runtime_put(dsi); err_runtime_get: - pm_runtime_disable(&dsidev->dev); + pm_runtime_disable(dev); return r; } -- cgit v1.2.3 From 4600ea9c49cc494fd7fb65d4f659e9f7b27b56e8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:36 +0200 Subject: drm: omapdrm: dsi: Store the struct device pointer in struct dsi_data The dsi_data structure stores a pointer to a struct platform_device. The driver only uses the dev member of the platform device structure. Store the struct device pointer instead and use it directly. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dsi.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 62131d7593a7..ecfdc6ef2500 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -330,7 +330,7 @@ struct dsi_of_data { }; struct dsi_data { - struct platform_device *pdev; + struct device *dev; void __iomem *proto_base; void __iomem *phy_base; void __iomem *pll_base; @@ -1144,7 +1144,7 @@ static int dsi_runtime_get(struct dsi_data *dsi) DSSDBG("dsi_runtime_get\n"); - r = pm_runtime_get_sync(&dsi->pdev->dev); + r = pm_runtime_get_sync(dsi->dev); WARN_ON(r < 0); return r < 0 ? r : 0; } @@ -1155,7 +1155,7 @@ static void dsi_runtime_put(struct dsi_data *dsi) DSSDBG("dsi_runtime_put\n"); - r = pm_runtime_put_sync(&dsi->pdev->dev); + r = pm_runtime_put_sync(dsi->dev); WARN_ON(r < 0 && r != -ENOSYS); } @@ -1166,7 +1166,7 @@ static int dsi_regulator_init(struct dsi_data *dsi) if (dsi->vdds_dsi_reg != NULL) return 0; - vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdd"); + vdds_dsi = devm_regulator_get(dsi->dev, "vdd"); if (IS_ERR(vdds_dsi)) { if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER) @@ -4951,7 +4951,7 @@ static int dsi_get_clocks(struct dsi_data *dsi) { struct clk *clk; - clk = devm_clk_get(&dsi->pdev->dev, "fck"); + clk = devm_clk_get(dsi->dev, "fck"); if (IS_ERR(clk)) { DSSERR("can't get fck\n"); return PTR_ERR(clk); @@ -5046,7 +5046,7 @@ static void dsi_init_output(struct dsi_data *dsi) { struct omap_dss_device *out = &dsi->output; - out->dev = &dsi->pdev->dev; + out->dev = dsi->dev; out->id = dsi->module_id == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; @@ -5068,7 +5068,7 @@ static void dsi_uninit_output(struct dsi_data *dsi) static int dsi_probe_of(struct dsi_data *dsi) { - struct device_node *node = dsi->pdev->dev.of_node; + struct device_node *node = dsi->dev->of_node; struct property *prop; u32 lane_arr[10]; int len, num_pins; @@ -5082,7 +5082,7 @@ static int dsi_probe_of(struct dsi_data *dsi) prop = of_find_property(ep, "lanes", &len); if (prop == NULL) { - dev_err(&dsi->pdev->dev, "failed to find lane data\n"); + dev_err(dsi->dev, "failed to find lane data\n"); r = -EINVAL; goto err; } @@ -5091,14 +5091,14 @@ static int dsi_probe_of(struct dsi_data *dsi) if (num_pins < 4 || num_pins % 2 != 0 || num_pins > dsi->num_lanes_supported * 2) { - dev_err(&dsi->pdev->dev, "bad number of lanes\n"); + dev_err(dsi->dev, "bad number of lanes\n"); r = -EINVAL; goto err; } r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins); if (r) { - dev_err(&dsi->pdev->dev, "failed to read lane data\n"); + dev_err(dsi->dev, "failed to read lane data\n"); goto err; } @@ -5108,7 +5108,7 @@ static int dsi_probe_of(struct dsi_data *dsi) r = dsi_configure_pins(&dsi->output, &pin_cfg); if (r) { - dev_err(&dsi->pdev->dev, "failed to configure pins"); + dev_err(dsi->dev, "failed to configure pins"); goto err; } @@ -5214,7 +5214,7 @@ static int dsi_init_pll_data(struct dss_device *dss, struct dsi_data *dsi) struct clk *clk; int r; - clk = devm_clk_get(&dsi->pdev->dev, "sys_clk"); + clk = devm_clk_get(dsi->dev, "sys_clk"); if (IS_ERR(clk)) { DSSERR("can't get sys_clk\n"); return PTR_ERR(clk); @@ -5317,7 +5317,7 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) return -ENOMEM; dsi->dss = dss; - dsi->pdev = pdev; + dsi->dev = dev; dev_set_drvdata(dev, dsi); spin_lock_init(&dsi->irq_lock); -- cgit v1.2.3 From f81b0fd4701c6c25481a81f8ec279ddb9fa2c27a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:37 +0200 Subject: drm: omapdrm: dsi: Don't pass channel to dispc init/uninit functions The dsi_display_init_dispc() and dsi_display_uninit_dispc() functions take a channel argument that is reduntant as it is always identical to the dsi->output.dispc_channel. Remove the argument and use the field directly in the functions to avoid misuse. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dsi.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index ecfdc6ef2500..0c4668e722b9 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -215,10 +215,8 @@ struct dsi_reg { u16 module; u16 idx; }; typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); struct dsi_data; -static int dsi_display_init_dispc(struct dsi_data *dsi, - enum omap_channel channel); -static void dsi_display_uninit_dispc(struct dsi_data *dsi, - enum omap_channel channel); +static int dsi_display_init_dispc(struct dsi_data *dsi); +static void dsi_display_uninit_dispc(struct dsi_data *dsi); static int dsi_vc_send_null(struct dsi_data *dsi, int channel); @@ -3845,7 +3843,7 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) return -ENODEV; } - r = dsi_display_init_dispc(dsi, dispc_channel); + r = dsi_display_init_dispc(dsi); if (r) goto err_init_dispc; @@ -3895,7 +3893,7 @@ err_mgr_enable: dsi_vc_enable(dsi, channel, false); } err_pix_fmt: - dsi_display_uninit_dispc(dsi, dispc_channel); + dsi_display_uninit_dispc(dsi); err_init_dispc: return r; } @@ -3918,7 +3916,7 @@ static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel dss_mgr_disable(dispc_channel); - dsi_display_uninit_dispc(dsi, dispc_channel); + dsi_display_uninit_dispc(dsi); } static void dsi_update_screen_dispc(struct dsi_data *dsi) @@ -4104,9 +4102,9 @@ static int dsi_configure_dispc_clocks(struct dsi_data *dsi) return 0; } -static int dsi_display_init_dispc(struct dsi_data *dsi, - enum omap_channel channel) +static int dsi_display_init_dispc(struct dsi_data *dsi) { + enum omap_channel channel = dsi->output.dispc_channel; int r; dss_select_lcd_clk_source(dsi->dss, channel, dsi->module_id == 0 ? @@ -4167,9 +4165,10 @@ err: return r; } -static void dsi_display_uninit_dispc(struct dsi_data *dsi, - enum omap_channel channel) +static void dsi_display_uninit_dispc(struct dsi_data *dsi) { + enum omap_channel channel = dsi->output.dispc_channel; + if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) dss_mgr_unregister_framedone_handler(channel, dsi_framedone_irq_callback, dsi); -- cgit v1.2.3 From 28d79f3e56b2c1d5ff0fd363da3229be0962cc85 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:38 +0200 Subject: drm: omapdrm: dss: Pass omap_dss_device pointer to dss_mgr_*() functions The dss_mgr_*() functions take a channel argument to identify the channel they operate on. This prevents the functions from accessing driver data structures without resorting to global variables. In an effort to remove global variables, pass the omap_dss_device pointer associated with the channel instead. This will be used to look up the omap_drm_private data structure to pass to the dss_mgr_ops. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dpi.c | 32 ++++++++++---------------- drivers/gpu/drm/omapdrm/dss/dsi.c | 30 +++++++++++-------------- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 20 ++++++----------- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 20 ++++++----------- drivers/gpu/drm/omapdrm/dss/omapdss.h | 22 +++++++++--------- drivers/gpu/drm/omapdrm/dss/output.c | 42 ++++++++++++++++++----------------- drivers/gpu/drm/omapdrm/dss/sdi.c | 28 +++++++++-------------- drivers/gpu/drm/omapdrm/dss/venc.c | 18 +++++---------- 8 files changed, 88 insertions(+), 124 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 338ceb1ba61b..e818e7836cbb 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -343,8 +343,6 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, static int dpi_set_mode(struct dpi_data *dpi) { - struct omap_dss_device *out = &dpi->output; - enum omap_channel channel = out->dispc_channel; struct videomode *vm = &dpi->vm; int lck_div = 0, pck_div = 0; unsigned long fck = 0; @@ -352,8 +350,8 @@ static int dpi_set_mode(struct dpi_data *dpi) int r = 0; if (dpi->pll) - r = dpi_set_pll_clk(dpi, channel, vm->pixelclock, &fck, - &lck_div, &pck_div); + r = dpi_set_pll_clk(dpi, dpi->output.dispc_channel, + vm->pixelclock, &fck, &lck_div, &pck_div); else r = dpi_set_dispc_clk(dpi, vm->pixelclock, &fck, &lck_div, &pck_div); @@ -369,16 +367,13 @@ static int dpi_set_mode(struct dpi_data *dpi) vm->pixelclock = pck; } - dss_mgr_set_timings(channel, vm); + dss_mgr_set_timings(&dpi->output, vm); return 0; } static void dpi_config_lcd_manager(struct dpi_data *dpi) { - struct omap_dss_device *out = &dpi->output; - enum omap_channel channel = out->dispc_channel; - dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; dpi->mgr_config.stallmode = false; @@ -388,14 +383,13 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi) dpi->mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(channel, &dpi->mgr_config); + dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config); } static int dpi_display_enable(struct omap_dss_device *dssdev) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); struct omap_dss_device *out = &dpi->output; - enum omap_channel channel = out->dispc_channel; int r; mutex_lock(&dpi->lock); @@ -416,7 +410,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_get_dispc; - r = dss_dpi_select_source(dpi->dss, out->port_num, channel); + r = dss_dpi_select_source(dpi->dss, out->port_num, out->dispc_channel); if (r) goto err_src_sel; @@ -434,7 +428,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) mdelay(2); - r = dss_mgr_enable(channel); + r = dss_mgr_enable(&dpi->output); if (r) goto err_mgr_enable; @@ -461,14 +455,14 @@ err_no_out_mgr: static void dpi_display_disable(struct omap_dss_device *dssdev) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - enum omap_channel channel = dpi->output.dispc_channel; mutex_lock(&dpi->lock); - dss_mgr_disable(channel); + dss_mgr_disable(&dpi->output); if (dpi->pll) { - dss_select_lcd_clk_source(dpi->dss, channel, DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel, + DSS_CLK_SRC_FCK); dss_pll_disable(dpi->pll); } @@ -658,7 +652,6 @@ static int dpi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - enum omap_channel channel = dpi->output.dispc_channel; int r; r = dpi_init_regulator(dpi); @@ -667,7 +660,7 @@ static int dpi_connect(struct omap_dss_device *dssdev, dpi_init_pll(dpi); - r = dss_mgr_connect(channel, dssdev); + r = dss_mgr_connect(&dpi->output, dssdev); if (r) return r; @@ -675,7 +668,7 @@ static int dpi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&dpi->output, dssdev); return r; } @@ -686,7 +679,6 @@ static void dpi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); - enum omap_channel channel = dpi->output.dispc_channel; WARN_ON(dst != dssdev->dst); @@ -695,7 +687,7 @@ static void dpi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&dpi->output, dssdev); } static const struct omapdss_dpi_ops dpi_ops = { diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 0c4668e722b9..66c4d973e7eb 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -3831,7 +3831,6 @@ static int dsi_configure_pins(struct omap_dss_device *dssdev, static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) { struct dsi_data *dsi = to_dsi_data(dssdev); - enum omap_channel dispc_channel = dssdev->dispc_channel; int bpp = dsi_get_pixel_size(dsi->pix_fmt); struct omap_dss_device *out = &dsi->output; u8 data_type; @@ -3881,7 +3880,7 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) dsi_if_enable(dsi, true); } - r = dss_mgr_enable(dispc_channel); + r = dss_mgr_enable(&dsi->output); if (r) goto err_mgr_enable; @@ -3901,7 +3900,6 @@ err_init_dispc: static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) { struct dsi_data *dsi = to_dsi_data(dssdev); - enum omap_channel dispc_channel = dssdev->dispc_channel; if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_if_enable(dsi, false); @@ -3914,14 +3912,13 @@ static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel dsi_if_enable(dsi, true); } - dss_mgr_disable(dispc_channel); + dss_mgr_disable(&dsi->output); dsi_display_uninit_dispc(dsi); } static void dsi_update_screen_dispc(struct dsi_data *dsi) { - enum omap_channel dispc_channel = dsi->output.dispc_channel; unsigned int bytespp; unsigned int bytespl; unsigned int bytespf; @@ -3983,9 +3980,9 @@ static void dsi_update_screen_dispc(struct dsi_data *dsi) msecs_to_jiffies(250)); BUG_ON(r == 0); - dss_mgr_set_timings(dispc_channel, &dsi->vm); + dss_mgr_set_timings(&dsi->output, &dsi->vm); - dss_mgr_start_update(dispc_channel); + dss_mgr_start_update(&dsi->output); if (dsi->te_enabled) { /* disable LP_RX_TO, so that we can receive TE. Time to wait @@ -4112,7 +4109,7 @@ static int dsi_display_init_dispc(struct dsi_data *dsi) DSS_CLK_SRC_PLL2_1); if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { - r = dss_mgr_register_framedone_handler(channel, + r = dss_mgr_register_framedone_handler(&dsi->output, dsi_framedone_irq_callback, dsi); if (r) { DSSERR("can't register FRAMEDONE handler\n"); @@ -4142,7 +4139,7 @@ static int dsi_display_init_dispc(struct dsi_data *dsi) dsi->vm.flags &= ~DISPLAY_FLAGS_SYNC_POSEDGE; dsi->vm.flags |= DISPLAY_FLAGS_SYNC_NEGEDGE; - dss_mgr_set_timings(channel, &dsi->vm); + dss_mgr_set_timings(&dsi->output, &dsi->vm); r = dsi_configure_dispc_clocks(dsi); if (r) @@ -4153,12 +4150,12 @@ static int dsi_display_init_dispc(struct dsi_data *dsi) dsi_get_pixel_size(dsi->pix_fmt); dsi->mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(channel, &dsi->mgr_config); + dss_mgr_set_lcd_config(&dsi->output, &dsi->mgr_config); return 0; err1: if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) - dss_mgr_unregister_framedone_handler(channel, + dss_mgr_unregister_framedone_handler(&dsi->output, dsi_framedone_irq_callback, dsi); err: dss_select_lcd_clk_source(dsi->dss, channel, DSS_CLK_SRC_FCK); @@ -4170,7 +4167,7 @@ static void dsi_display_uninit_dispc(struct dsi_data *dsi) enum omap_channel channel = dsi->output.dispc_channel; if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) - dss_mgr_unregister_framedone_handler(channel, + dss_mgr_unregister_framedone_handler(&dsi->output, dsi_framedone_irq_callback, dsi); dss_select_lcd_clk_source(dsi->dss, channel, DSS_CLK_SRC_FCK); @@ -4965,14 +4962,13 @@ static int dsi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { struct dsi_data *dsi = to_dsi_data(dssdev); - enum omap_channel dispc_channel = dssdev->dispc_channel; int r; r = dsi_regulator_init(dsi); if (r) return r; - r = dss_mgr_connect(dispc_channel, dssdev); + r = dss_mgr_connect(&dsi->output, dssdev); if (r) return r; @@ -4980,7 +4976,7 @@ static int dsi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dssdev->name); - dss_mgr_disconnect(dispc_channel, dssdev); + dss_mgr_disconnect(&dsi->output, dssdev); return r; } @@ -4990,7 +4986,7 @@ static int dsi_connect(struct omap_dss_device *dssdev, static void dsi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel dispc_channel = dssdev->dispc_channel; + struct dsi_data *dsi = to_dsi_data(dssdev); WARN_ON(dst != dssdev->dst); @@ -4999,7 +4995,7 @@ static void dsi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(dispc_channel, dssdev); + dss_mgr_disconnect(&dsi->output, dssdev); } static const struct omapdss_dsi_ops dsi_ops = { diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 48608ebfeb0c..096542fb75d2 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -177,7 +177,6 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) { int r; struct videomode *vm; - enum omap_channel channel = dssdev->dispc_channel; struct hdmi_wp_data *wp = &hdmi.wp; struct dss_pll_clock_info hdmi_cinfo = { 0 }; unsigned int pc; @@ -231,9 +230,9 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); /* tv size */ - dss_mgr_set_timings(channel, vm); + dss_mgr_set_timings(&hdmi.output, vm); - r = dss_mgr_enable(channel); + r = dss_mgr_enable(&hdmi.output); if (r) goto err_mgr_enable; @@ -247,7 +246,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) return 0; err_vid_enable: - dss_mgr_disable(channel); + dss_mgr_disable(&hdmi.output); err_mgr_enable: hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); err_phy_pwr: @@ -261,13 +260,11 @@ err_pll_enable: static void hdmi_power_off_full(struct omap_dss_device *dssdev) { - enum omap_channel channel = dssdev->dispc_channel; - hdmi_wp_clear_irqenable(&hdmi.wp, ~HDMI_IRQ_CORE); hdmi_wp_video_stop(&hdmi.wp); - dss_mgr_disable(channel); + dss_mgr_disable(&hdmi.output); hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); @@ -451,14 +448,13 @@ void hdmi4_core_disable(struct omap_dss_device *dssdev) static int hdmi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; int r; r = hdmi_init_regulator(); if (r) return r; - r = dss_mgr_connect(channel, dssdev); + r = dss_mgr_connect(&hdmi.output, dssdev); if (r) return r; @@ -466,7 +462,7 @@ static int hdmi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&hdmi.output, dssdev); return r; } @@ -476,8 +472,6 @@ static int hdmi_connect(struct omap_dss_device *dssdev, static void hdmi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; - WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -485,7 +479,7 @@ static void hdmi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&hdmi.output, dssdev); } static int hdmi_read_edid(struct omap_dss_device *dssdev, diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 8ede19c3d8e7..597baebd959c 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -173,7 +173,6 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) { int r; struct videomode *vm; - enum omap_channel channel = dssdev->dispc_channel; struct dss_pll_clock_info hdmi_cinfo = { 0 }; unsigned int pc; @@ -227,9 +226,9 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); /* tv size */ - dss_mgr_set_timings(channel, vm); + dss_mgr_set_timings(&hdmi.output, vm); - r = dss_mgr_enable(channel); + r = dss_mgr_enable(&hdmi.output); if (r) goto err_mgr_enable; @@ -243,7 +242,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) return 0; err_vid_enable: - dss_mgr_disable(channel); + dss_mgr_disable(&hdmi.output); err_mgr_enable: hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); err_phy_pwr: @@ -257,13 +256,11 @@ err_pll_enable: static void hdmi_power_off_full(struct omap_dss_device *dssdev) { - enum omap_channel channel = dssdev->dispc_channel; - hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); hdmi_wp_video_stop(&hdmi.wp); - dss_mgr_disable(channel); + dss_mgr_disable(&hdmi.output); hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); @@ -456,14 +453,13 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev) static int hdmi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; int r; r = hdmi_init_regulator(); if (r) return r; - r = dss_mgr_connect(channel, dssdev); + r = dss_mgr_connect(&hdmi.output, dssdev); if (r) return r; @@ -471,7 +467,7 @@ static int hdmi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&hdmi.output, dssdev); return r; } @@ -481,8 +477,6 @@ static int hdmi_connect(struct omap_dss_device *dssdev, static void hdmi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; - WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -490,7 +484,7 @@ static void hdmi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&hdmi.output, dssdev); } static int hdmi_read_edid(struct omap_dss_device *dssdev, diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 4222661d4c88..aeaa337b29c7 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -656,20 +656,20 @@ struct dss_mgr_ops { int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops); void dss_uninstall_mgr_ops(void); -int dss_mgr_connect(enum omap_channel channel, - struct omap_dss_device *dst); -void dss_mgr_disconnect(enum omap_channel channel, - struct omap_dss_device *dst); -void dss_mgr_set_timings(enum omap_channel channel, +int dss_mgr_connect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); +void dss_mgr_disconnect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); +void dss_mgr_set_timings(struct omap_dss_device *dssdev, const struct videomode *vm); -void dss_mgr_set_lcd_config(enum omap_channel channel, +void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev, const struct dss_lcd_mgr_config *config); -int dss_mgr_enable(enum omap_channel channel); -void dss_mgr_disable(enum omap_channel channel); -void dss_mgr_start_update(enum omap_channel channel); -int dss_mgr_register_framedone_handler(enum omap_channel channel, +int dss_mgr_enable(struct omap_dss_device *dssdev); +void dss_mgr_disable(struct omap_dss_device *dssdev); +void dss_mgr_start_update(struct omap_dss_device *dssdev); +int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev, void (*handler)(void *), void *data); -void dss_mgr_unregister_framedone_handler(enum omap_channel channel, +void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev, void (*handler)(void *), void *data); /* dispc ops */ diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index a28e00c94c05..9ff29dea28ce 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -188,61 +188,63 @@ void dss_uninstall_mgr_ops(void) } EXPORT_SYMBOL(dss_uninstall_mgr_ops); -int dss_mgr_connect(enum omap_channel channel, - struct omap_dss_device *dst) +int dss_mgr_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - return dss_mgr_ops->connect(channel, dst); + return dss_mgr_ops->connect(dssdev->dispc_channel, dst); } EXPORT_SYMBOL(dss_mgr_connect); -void dss_mgr_disconnect(enum omap_channel channel, - struct omap_dss_device *dst) +void dss_mgr_disconnect(struct omap_dss_device *dssdev, + struct omap_dss_device *dst) { - dss_mgr_ops->disconnect(channel, dst); + dss_mgr_ops->disconnect(dssdev->dispc_channel, dst); } EXPORT_SYMBOL(dss_mgr_disconnect); -void dss_mgr_set_timings(enum omap_channel channel, const struct videomode *vm) +void dss_mgr_set_timings(struct omap_dss_device *dssdev, + const struct videomode *vm) { - dss_mgr_ops->set_timings(channel, vm); + dss_mgr_ops->set_timings(dssdev->dispc_channel, vm); } EXPORT_SYMBOL(dss_mgr_set_timings); -void dss_mgr_set_lcd_config(enum omap_channel channel, +void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev, const struct dss_lcd_mgr_config *config) { - dss_mgr_ops->set_lcd_config(channel, config); + dss_mgr_ops->set_lcd_config(dssdev->dispc_channel, config); } EXPORT_SYMBOL(dss_mgr_set_lcd_config); -int dss_mgr_enable(enum omap_channel channel) +int dss_mgr_enable(struct omap_dss_device *dssdev) { - return dss_mgr_ops->enable(channel); + return dss_mgr_ops->enable(dssdev->dispc_channel); } EXPORT_SYMBOL(dss_mgr_enable); -void dss_mgr_disable(enum omap_channel channel) +void dss_mgr_disable(struct omap_dss_device *dssdev) { - dss_mgr_ops->disable(channel); + dss_mgr_ops->disable(dssdev->dispc_channel); } EXPORT_SYMBOL(dss_mgr_disable); -void dss_mgr_start_update(enum omap_channel channel) +void dss_mgr_start_update(struct omap_dss_device *dssdev) { - dss_mgr_ops->start_update(channel); + dss_mgr_ops->start_update(dssdev->dispc_channel); } EXPORT_SYMBOL(dss_mgr_start_update); -int dss_mgr_register_framedone_handler(enum omap_channel channel, +int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev, void (*handler)(void *), void *data) { - return dss_mgr_ops->register_framedone_handler(channel, handler, data); + return dss_mgr_ops->register_framedone_handler(dssdev->dispc_channel, + handler, data); } EXPORT_SYMBOL(dss_mgr_register_framedone_handler); -void dss_mgr_unregister_framedone_handler(enum omap_channel channel, +void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev, void (*handler)(void *), void *data) { - dss_mgr_ops->unregister_framedone_handler(channel, handler, data); + dss_mgr_ops->unregister_framedone_handler(dssdev->dispc_channel, + handler, data); } EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index 6f39e0ff3055..bf225ae69b06 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -113,8 +113,6 @@ static int sdi_calc_clock_div(unsigned long pclk, static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) { - enum omap_channel channel = dssdev->dispc_channel; - sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; sdi.mgr_config.stallmode = false; @@ -123,20 +121,18 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) sdi.mgr_config.video_port_width = 24; sdi.mgr_config.lcden_sig_polarity = 1; - dss_mgr_set_lcd_config(channel, &sdi.mgr_config); + dss_mgr_set_lcd_config(&sdi.output, &sdi.mgr_config); } static int sdi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_device *out = &sdi.output; - enum omap_channel channel = dssdev->dispc_channel; struct videomode *vm = &sdi.vm; unsigned long fck; struct dispc_clock_info dispc_cinfo; unsigned long pck; int r; - if (!out->dispc_channel_connected) { + if (!sdi.output.dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); return -ENODEV; } @@ -168,7 +164,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) } - dss_mgr_set_timings(channel, vm); + dss_mgr_set_timings(&sdi.output, vm); r = dss_set_fck_rate(sdi.dss, fck); if (r) @@ -187,7 +183,8 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) * need to care about the shadow register mechanism for pck-free. The * exact reason for this is unknown. */ - dispc_mgr_set_clock_div(channel, &sdi.mgr_config.clock_info); + dispc_mgr_set_clock_div(sdi.output.dispc_channel, + &sdi.mgr_config.clock_info); dss_sdi_init(sdi.dss, sdi.datapairs); r = dss_sdi_enable(sdi.dss); @@ -195,7 +192,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) goto err_sdi_enable; mdelay(2); - r = dss_mgr_enable(channel); + r = dss_mgr_enable(&sdi.output); if (r) goto err_mgr_enable; @@ -215,9 +212,7 @@ err_reg_enable: static void sdi_display_disable(struct omap_dss_device *dssdev) { - enum omap_channel channel = dssdev->dispc_channel; - - dss_mgr_disable(channel); + dss_mgr_disable(&sdi.output); dss_sdi_disable(sdi.dss); @@ -274,14 +269,13 @@ static int sdi_init_regulator(void) static int sdi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; int r; r = sdi_init_regulator(); if (r) return r; - r = dss_mgr_connect(channel, dssdev); + r = dss_mgr_connect(&sdi.output, dssdev); if (r) return r; @@ -289,7 +283,7 @@ static int sdi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&sdi.output, dssdev); return r; } @@ -299,8 +293,6 @@ static int sdi_connect(struct omap_dss_device *dssdev, static void sdi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; - WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -308,7 +300,7 @@ static void sdi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&sdi.output, dssdev); } static const struct omapdss_sdi_ops sdi_ops = { diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index ed756d4c7210..bed3b54b70b2 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -460,7 +460,6 @@ static const struct venc_config *venc_timings_to_config(struct videomode *vm) static int venc_power_on(struct omap_dss_device *dssdev) { - enum omap_channel channel = dssdev->dispc_channel; u32 l; int r; @@ -486,13 +485,13 @@ static int venc_power_on(struct omap_dss_device *dssdev) venc_write_reg(VENC_OUTPUT_CONTROL, l); - dss_mgr_set_timings(channel, &venc.vm); + dss_mgr_set_timings(&venc.output, &venc.vm); r = regulator_enable(venc.vdda_dac_reg); if (r) goto err1; - r = dss_mgr_enable(channel); + r = dss_mgr_enable(&venc.output); if (r) goto err2; @@ -511,12 +510,10 @@ err0: static void venc_power_off(struct omap_dss_device *dssdev) { - enum omap_channel channel = dssdev->dispc_channel; - venc_write_reg(VENC_OUTPUT_CONTROL, 0); dss_set_dac_pwrdn_bgz(venc.dss, 0); - dss_mgr_disable(channel); + dss_mgr_disable(&venc.output); regulator_disable(venc.vdda_dac_reg); @@ -749,14 +746,13 @@ static int venc_get_clocks(struct platform_device *pdev) static int venc_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; int r; r = venc_init_regulator(); if (r) return r; - r = dss_mgr_connect(channel, dssdev); + r = dss_mgr_connect(&venc.output, dssdev); if (r) return r; @@ -764,7 +760,7 @@ static int venc_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&venc.output, dssdev); return r; } @@ -774,8 +770,6 @@ static int venc_connect(struct omap_dss_device *dssdev, static void venc_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - enum omap_channel channel = dssdev->dispc_channel; - WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -783,7 +777,7 @@ static void venc_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(channel, dssdev); + dss_mgr_disconnect(&venc.output, dssdev); } static const struct omapdss_atv_ops venc_ops = { -- cgit v1.2.3 From 64cb81797f8b56e1806d67024de561b60944d1a5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:39 +0200 Subject: drm: omapdrm: dss: Pass omap_drm_private pointer to dss_mgr_ops The dss_mgr_ops operations implemented by the omapdrm side have to look up the omap_crtc objects from global variables as they are only passed a channel number. In order to remove global variables in the omapdrm driver pass the omap_drm_private pointer to the dss_mgr_ops. This requires storing a pointer to the omap_drm_private in a global variable on the DSS side as a temporary measure until the omapdrm and omapdss drivers get merged. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/omapdss.h | 41 ++++++++++++++++++++++------------- drivers/gpu/drm/omapdrm/dss/output.c | 28 +++++++++++++++--------- drivers/gpu/drm/omapdrm/omap_crtc.c | 31 +++++++++++++++----------- drivers/gpu/drm/omapdrm/omap_crtc.h | 2 +- drivers/gpu/drm/omapdrm/omap_drv.c | 2 +- 5 files changed, 64 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index aeaa337b29c7..318641f5bc24 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -59,6 +59,7 @@ #define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 29) #define DISPC_IRQ_FRAMEDONE3 (1 << 30) +struct omap_drm_private; struct omap_dss_device; struct dss_lcd_mgr_config; struct snd_aes_iec958; @@ -635,25 +636,35 @@ struct device_node *dss_of_port_get_parent_device(struct device_node *port); u32 dss_of_port_get_port_number(struct device_node *port); struct dss_mgr_ops { - int (*connect)(enum omap_channel channel, - struct omap_dss_device *dst); - void (*disconnect)(enum omap_channel channel, - struct omap_dss_device *dst); - - void (*start_update)(enum omap_channel channel); - int (*enable)(enum omap_channel channel); - void (*disable)(enum omap_channel channel); - void (*set_timings)(enum omap_channel channel, - const struct videomode *vm); - void (*set_lcd_config)(enum omap_channel channel, - const struct dss_lcd_mgr_config *config); - int (*register_framedone_handler)(enum omap_channel channel, + int (*connect)(struct omap_drm_private *priv, + enum omap_channel channel, + struct omap_dss_device *dst); + void (*disconnect)(struct omap_drm_private *priv, + enum omap_channel channel, + struct omap_dss_device *dst); + + void (*start_update)(struct omap_drm_private *priv, + enum omap_channel channel); + int (*enable)(struct omap_drm_private *priv, + enum omap_channel channel); + void (*disable)(struct omap_drm_private *priv, + enum omap_channel channel); + void (*set_timings)(struct omap_drm_private *priv, + enum omap_channel channel, + const struct videomode *vm); + void (*set_lcd_config)(struct omap_drm_private *priv, + enum omap_channel channel, + const struct dss_lcd_mgr_config *config); + int (*register_framedone_handler)(struct omap_drm_private *priv, + enum omap_channel channel, void (*handler)(void *), void *data); - void (*unregister_framedone_handler)(enum omap_channel channel, + void (*unregister_framedone_handler)(struct omap_drm_private *priv, + enum omap_channel channel, void (*handler)(void *), void *data); }; -int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops); +int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops, + struct omap_drm_private *priv); void dss_uninstall_mgr_ops(void); int dss_mgr_connect(struct omap_dss_device *dssdev, diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index 9ff29dea28ce..96b9d4cd505f 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -170,13 +170,16 @@ struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device EXPORT_SYMBOL(omapdss_find_output_from_display); static const struct dss_mgr_ops *dss_mgr_ops; +static struct omap_drm_private *dss_mgr_ops_priv; -int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops) +int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops, + struct omap_drm_private *priv) { if (dss_mgr_ops) return -EBUSY; dss_mgr_ops = mgr_ops; + dss_mgr_ops_priv = priv; return 0; } @@ -185,58 +188,62 @@ EXPORT_SYMBOL(dss_install_mgr_ops); void dss_uninstall_mgr_ops(void) { dss_mgr_ops = NULL; + dss_mgr_ops_priv = NULL; } EXPORT_SYMBOL(dss_uninstall_mgr_ops); int dss_mgr_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - return dss_mgr_ops->connect(dssdev->dispc_channel, dst); + return dss_mgr_ops->connect(dss_mgr_ops_priv, + dssdev->dispc_channel, dst); } EXPORT_SYMBOL(dss_mgr_connect); void dss_mgr_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { - dss_mgr_ops->disconnect(dssdev->dispc_channel, dst); + dss_mgr_ops->disconnect(dss_mgr_ops_priv, dssdev->dispc_channel, dst); } EXPORT_SYMBOL(dss_mgr_disconnect); void dss_mgr_set_timings(struct omap_dss_device *dssdev, const struct videomode *vm) { - dss_mgr_ops->set_timings(dssdev->dispc_channel, vm); + dss_mgr_ops->set_timings(dss_mgr_ops_priv, dssdev->dispc_channel, vm); } EXPORT_SYMBOL(dss_mgr_set_timings); void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev, const struct dss_lcd_mgr_config *config) { - dss_mgr_ops->set_lcd_config(dssdev->dispc_channel, config); + dss_mgr_ops->set_lcd_config(dss_mgr_ops_priv, + dssdev->dispc_channel, config); } EXPORT_SYMBOL(dss_mgr_set_lcd_config); int dss_mgr_enable(struct omap_dss_device *dssdev) { - return dss_mgr_ops->enable(dssdev->dispc_channel); + return dss_mgr_ops->enable(dss_mgr_ops_priv, dssdev->dispc_channel); } EXPORT_SYMBOL(dss_mgr_enable); void dss_mgr_disable(struct omap_dss_device *dssdev) { - dss_mgr_ops->disable(dssdev->dispc_channel); + dss_mgr_ops->disable(dss_mgr_ops_priv, dssdev->dispc_channel); } EXPORT_SYMBOL(dss_mgr_disable); void dss_mgr_start_update(struct omap_dss_device *dssdev) { - dss_mgr_ops->start_update(dssdev->dispc_channel); + dss_mgr_ops->start_update(dss_mgr_ops_priv, dssdev->dispc_channel); } EXPORT_SYMBOL(dss_mgr_start_update); int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev, void (*handler)(void *), void *data) { - return dss_mgr_ops->register_framedone_handler(dssdev->dispc_channel, + return dss_mgr_ops->register_framedone_handler(dss_mgr_ops_priv, + dssdev->dispc_channel, handler, data); } EXPORT_SYMBOL(dss_mgr_register_framedone_handler); @@ -244,7 +251,8 @@ EXPORT_SYMBOL(dss_mgr_register_framedone_handler); void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev, void (*handler)(void *), void *data) { - dss_mgr_ops->unregister_framedone_handler(dssdev->dispc_channel, + dss_mgr_ops->unregister_framedone_handler(dss_mgr_ops_priv, + dssdev->dispc_channel, handler, data); } EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 95615a86e9f7..61d8d17a4243 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -113,7 +113,8 @@ static struct omap_crtc *omap_crtcs[8]; static struct omap_dss_device *omap_crtc_output[8]; /* we can probably ignore these until we support command-mode panels: */ -static int omap_crtc_dss_connect(enum omap_channel channel, +static int omap_crtc_dss_connect(struct omap_drm_private *priv, + enum omap_channel channel, struct omap_dss_device *dst) { const struct dispc_ops *dispc_ops = dispc_get_ops(); @@ -130,14 +131,16 @@ static int omap_crtc_dss_connect(enum omap_channel channel, return 0; } -static void omap_crtc_dss_disconnect(enum omap_channel channel, +static void omap_crtc_dss_disconnect(struct omap_drm_private *priv, + enum omap_channel channel, struct omap_dss_device *dst) { omap_crtc_output[channel] = NULL; dst->dispc_channel_connected = false; } -static void omap_crtc_dss_start_update(enum omap_channel channel) +static void omap_crtc_dss_start_update(struct omap_drm_private *priv, + enum omap_channel channel) { } @@ -207,10 +210,10 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) } -static int omap_crtc_dss_enable(enum omap_channel channel) +static int omap_crtc_dss_enable(struct omap_drm_private *priv, + enum omap_channel channel) { struct omap_crtc *omap_crtc = omap_crtcs[channel]; - struct omap_drm_private *priv = omap_crtc->base.dev->dev_private; priv->dispc_ops->mgr_set_timings(omap_crtc->channel, &omap_crtc->vm); omap_crtc_set_enabled(&omap_crtc->base, true); @@ -218,14 +221,16 @@ static int omap_crtc_dss_enable(enum omap_channel channel) return 0; } -static void omap_crtc_dss_disable(enum omap_channel channel) +static void omap_crtc_dss_disable(struct omap_drm_private *priv, + enum omap_channel channel) { struct omap_crtc *omap_crtc = omap_crtcs[channel]; omap_crtc_set_enabled(&omap_crtc->base, false); } -static void omap_crtc_dss_set_timings(enum omap_channel channel, +static void omap_crtc_dss_set_timings(struct omap_drm_private *priv, + enum omap_channel channel, const struct videomode *vm) { struct omap_crtc *omap_crtc = omap_crtcs[channel]; @@ -233,25 +238,25 @@ static void omap_crtc_dss_set_timings(enum omap_channel channel, omap_crtc->vm = *vm; } -static void omap_crtc_dss_set_lcd_config(enum omap_channel channel, +static void omap_crtc_dss_set_lcd_config(struct omap_drm_private *priv, + enum omap_channel channel, const struct dss_lcd_mgr_config *config) { struct omap_crtc *omap_crtc = omap_crtcs[channel]; - struct omap_drm_private *priv = omap_crtc->base.dev->dev_private; DBG("%s", omap_crtc->name); priv->dispc_ops->mgr_set_lcd_config(omap_crtc->channel, config); } static int omap_crtc_dss_register_framedone( - enum omap_channel channel, + struct omap_drm_private *priv, enum omap_channel channel, void (*handler)(void *), void *data) { return 0; } static void omap_crtc_dss_unregister_framedone( - enum omap_channel channel, + struct omap_drm_private *priv, enum omap_channel channel, void (*handler)(void *), void *data) { } @@ -669,11 +674,11 @@ static const char *channel_names[] = { [OMAP_DSS_CHANNEL_LCD3] = "lcd3", }; -void omap_crtc_pre_init(void) +void omap_crtc_pre_init(struct omap_drm_private *priv) { memset(omap_crtcs, 0, sizeof(omap_crtcs)); - dss_install_mgr_ops(&mgr_ops); + dss_install_mgr_ops(&mgr_ops, priv); } void omap_crtc_pre_uninit(void) diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.h b/drivers/gpu/drm/omapdrm/omap_crtc.h index 7f01e730a050..eaab2d7f0324 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.h +++ b/drivers/gpu/drm/omapdrm/omap_crtc.h @@ -32,7 +32,7 @@ struct videomode; struct videomode *omap_crtc_timings(struct drm_crtc *crtc); enum omap_channel omap_crtc_channel(struct drm_crtc *crtc); -void omap_crtc_pre_init(void); +void omap_crtc_pre_init(struct omap_drm_private *priv); void omap_crtc_pre_uninit(void); struct drm_crtc *omap_crtc_init(struct drm_device *dev, struct drm_plane *plane, struct omap_dss_device *dssdev); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index b571cc04e08d..39e78f765f7e 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -521,7 +521,7 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) priv->dev = dev; - omap_crtc_pre_init(); + omap_crtc_pre_init(priv); ret = omap_connect_dssdevs(); if (ret) -- cgit v1.2.3 From 72877cf38b4b78fbb3a852f2288d7f2a7af0db22 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:40 +0200 Subject: drm: omapdrm: dss: Store DSS device pointer in the omapdrm private data The dss_device is the top-level component in the omapdss driver. Give the omapdrm driver access to the dss_device pointer in order to obtain pointers to all other components from it. This requires a new global variable in the omapdss driver that will be removed when merging the omapdrm and omapdss drivers, but will already allow removal of several other global variables. As this partly duplicates the omapdss_is_initialized() API, reimplement it as an inline function wrapping omapdss_get_dss(). Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/base.c | 14 +++++++------- drivers/gpu/drm/omapdrm/dss/dss.c | 5 +++-- drivers/gpu/drm/omapdrm/dss/omapdss.h | 10 +++++++--- drivers/gpu/drm/omapdrm/omap_drv.c | 1 + drivers/gpu/drm/omapdrm/omap_drv.h | 1 + 5 files changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index 67cc87a4f1f6..6346bc967a77 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -20,7 +20,7 @@ #include #include "omapdss.h" -static bool dss_initialized; +static struct dss_device *dss_device; static const struct dispc_ops *ops; static struct list_head omapdss_comp_list; @@ -31,17 +31,17 @@ struct omapdss_comp_node { bool dss_core_component; }; -void omapdss_set_is_initialized(bool set) +struct dss_device *omapdss_get_dss(void) { - dss_initialized = set; + return dss_device; } -EXPORT_SYMBOL(omapdss_set_is_initialized); +EXPORT_SYMBOL(omapdss_get_dss); -bool omapdss_is_initialized(void) +void omapdss_set_dss(struct dss_device *dss) { - return dss_initialized; + dss_device = dss; } -EXPORT_SYMBOL(omapdss_is_initialized); +EXPORT_SYMBOL(omapdss_set_dss); void dispc_set_ops(const struct dispc_ops *o) { diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 14d2f024eb70..ca2efb937d42 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1316,6 +1316,7 @@ static const struct soc_device_attribute dss_soc_devices[] = { static int dss_bind(struct device *dev) { + struct dss_device *dss = dev_get_drvdata(dev); int r; r = component_bind_all(dev, NULL); @@ -1325,14 +1326,14 @@ static int dss_bind(struct device *dev) pm_set_vt_switch(0); omapdss_gather_components(dev); - omapdss_set_is_initialized(true); + omapdss_set_dss(dss); return 0; } static void dss_unbind(struct device *dev) { - omapdss_set_is_initialized(false); + omapdss_set_dss(NULL); component_unbind_all(dev, NULL); } diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 318641f5bc24..312485714703 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -59,6 +59,7 @@ #define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 29) #define DISPC_IRQ_FRAMEDONE3 (1 << 30) +struct dss_device; struct omap_drm_private; struct omap_dss_device; struct dss_lcd_mgr_config; @@ -586,7 +587,12 @@ struct omap_dss_driver { const struct hdmi_avi_infoframe *avi); }; -bool omapdss_is_initialized(void); +struct dss_device *omapdss_get_dss(void); +void omapdss_set_dss(struct dss_device *dss); +static inline bool omapdss_is_initialized(void) +{ + return !!omapdss_get_dss(); +} int omapdss_register_display(struct omap_dss_device *dssdev); void omapdss_unregister_display(struct omap_dss_device *dssdev); @@ -630,8 +636,6 @@ static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev) struct omap_dss_device * omapdss_of_find_source_for_first_ep(struct device_node *node); -void omapdss_set_is_initialized(bool set); - struct device_node *dss_of_port_get_parent_device(struct device_node *port); u32 dss_of_port_get_port_number(struct device_node *port); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 39e78f765f7e..003445b70ee7 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -527,6 +527,7 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) if (ret) goto err_crtc_uninit; + priv->dss = omapdss_get_dss(); priv->dispc_ops = dispc_get_ops(); soc = soc_device_match(omapdrm_soc_devices); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 49351bb3731e..a7962c14fc7c 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -50,6 +50,7 @@ struct omap_drm_private { struct device *dev; u32 omaprev; + struct dss_device *dss; const struct dispc_ops *dispc_ops; unsigned int num_crtcs; -- cgit v1.2.3 From d3541ca81dbddeefa0c42df448211a9dbaef0843 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:41 +0200 Subject: drm: omapdrm: dss: Store dispc ops in dss_device structure Remove the global dispc ops variable by storing it in the dss_device structure. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/base.c | 13 ++++--------- drivers/gpu/drm/omapdrm/dss/dispc.c | 6 ++++-- drivers/gpu/drm/omapdrm/dss/dss.h | 2 ++ drivers/gpu/drm/omapdrm/dss/omapdss.h | 3 +-- drivers/gpu/drm/omapdrm/omap_crtc.c | 4 +--- drivers/gpu/drm/omapdrm/omap_drv.c | 5 ++--- 6 files changed, 14 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index 6346bc967a77..c248c3c31904 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -18,10 +18,11 @@ #include #include #include + +#include "dss.h" #include "omapdss.h" static struct dss_device *dss_device; -static const struct dispc_ops *ops; static struct list_head omapdss_comp_list; @@ -43,15 +44,9 @@ void omapdss_set_dss(struct dss_device *dss) } EXPORT_SYMBOL(omapdss_set_dss); -void dispc_set_ops(const struct dispc_ops *o) -{ - ops = o; -} -EXPORT_SYMBOL(dispc_set_ops); - -const struct dispc_ops *dispc_get_ops(void) +const struct dispc_ops *dispc_get_ops(struct dss_device *dss) { - return ops; + return dss->dispc_ops; } EXPORT_SYMBOL(dispc_get_ops); diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 8019cc9f4f97..aae6037f499f 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -4622,7 +4622,7 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) dispc_runtime_put(); - dispc_set_ops(&dispc_ops); + dss->dispc_ops = &dispc_ops; dispc.debugfs = dss_debugfs_create_file(dss, "dispc", dispc_dump_regs, &dispc); @@ -4637,9 +4637,11 @@ err_runtime_get: static void dispc_unbind(struct device *dev, struct device *master, void *data) { + struct dss_device *dss = dispc.dss; + dss_debugfs_remove_file(dispc.debugfs); - dispc_set_ops(NULL); + dss->dispc_ops = NULL; pm_runtime_disable(dev); diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 764c52025a27..348378f1b5a5 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -271,6 +271,8 @@ struct dss_device { struct dss_pll *plls[4]; struct dss_pll *video1_pll; struct dss_pll *video2_pll; + + const struct dispc_ops *dispc_ops; }; /* core */ diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 312485714703..4bf7843b4aec 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -733,8 +733,7 @@ struct dispc_ops { const u32 *(*ovl_get_color_modes)(enum omap_plane_id plane); }; -void dispc_set_ops(const struct dispc_ops *o); -const struct dispc_ops *dispc_get_ops(void); +const struct dispc_ops *dispc_get_ops(struct dss_device *dss); bool omapdss_component_is_display(struct device_node *node); bool omapdss_component_is_output(struct device_node *node); diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 61d8d17a4243..ffe4f698d291 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -117,12 +117,10 @@ static int omap_crtc_dss_connect(struct omap_drm_private *priv, enum omap_channel channel, struct omap_dss_device *dst) { - const struct dispc_ops *dispc_ops = dispc_get_ops(); - if (omap_crtc_output[channel]) return -EINVAL; - if ((dispc_ops->mgr_get_supported_outputs(channel) & dst->id) == 0) + if (!(priv->dispc_ops->mgr_get_supported_outputs(channel) & dst->id)) return -EINVAL; omap_crtc_output[channel] = dst; diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 003445b70ee7..a93916cd0258 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -520,6 +520,8 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) DBG("%s", dev_name(dev)); priv->dev = dev; + priv->dss = omapdss_get_dss(); + priv->dispc_ops = dispc_get_ops(priv->dss); omap_crtc_pre_init(priv); @@ -527,9 +529,6 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) if (ret) goto err_crtc_uninit; - priv->dss = omapdss_get_dss(); - priv->dispc_ops = dispc_get_ops(); - soc = soc_device_match(omapdrm_soc_devices); priv->omaprev = soc ? (unsigned int)soc->data : 0; priv->wq = alloc_ordered_workqueue("omapdrm", 0); -- cgit v1.2.3 From 50638ae569dc097a95218eb70140e68aa213b07c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:42 +0200 Subject: drm: omapdrm: dispc: Pass DISPC pointer to dispc_ops operations This removes the need to access the global DISPC private data in those functions (both for the current accesses and the future ones that will be introduced when allocating the DISPC private data dynamically). In order to allow the omapdrm side to call the dispc_ops with a DISPC pointer, we also introduce a new function dss_get_dispc() to retrieve the DISPC corresponding to the DSS. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/base.c | 6 + drivers/gpu/drm/omapdrm/dss/dispc.c | 223 ++++++++++++++++++---------------- drivers/gpu/drm/omapdrm/dss/dpi.c | 6 +- drivers/gpu/drm/omapdrm/dss/dsi.c | 4 +- drivers/gpu/drm/omapdrm/dss/dss.h | 6 +- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 7 +- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 7 +- drivers/gpu/drm/omapdrm/dss/omapdss.h | 95 +++++++++------ drivers/gpu/drm/omapdrm/dss/sdi.c | 6 +- drivers/gpu/drm/omapdrm/dss/venc.c | 4 +- drivers/gpu/drm/omapdrm/omap_crtc.c | 31 +++-- drivers/gpu/drm/omapdrm/omap_drv.c | 13 +- drivers/gpu/drm/omapdrm/omap_drv.h | 1 + drivers/gpu/drm/omapdrm/omap_irq.c | 32 ++--- drivers/gpu/drm/omapdrm/omap_plane.c | 12 +- 15 files changed, 257 insertions(+), 196 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index c248c3c31904..99e8cb8dc65b 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -44,6 +44,12 @@ void omapdss_set_dss(struct dss_device *dss) } EXPORT_SYMBOL(omapdss_set_dss); +struct dispc_device *dispc_get_dispc(struct dss_device *dss) +{ + return dss->dispc; +} +EXPORT_SYMBOL(dispc_get_dispc); + const struct dispc_ops *dispc_get_ops(struct dss_device *dss) { return dss->dispc_ops; diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index aae6037f499f..6d8228f976f9 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -162,7 +162,7 @@ struct dispc_features { #define DISPC_MAX_NR_FIFOS 5 #define DISPC_MAX_CHANNEL_GAMMA 4 -static struct { +struct dispc_device { struct platform_device *pdev; void __iomem *base; struct dss_device *dss; @@ -194,7 +194,9 @@ static struct { /* DISPC_CONTROL & DISPC_CONFIG lock*/ spinlock_t control_lock; -} dispc; +}; + +static struct dispc_device dispc; enum omap_color_component { /* used for all color formats for OMAP3 and earlier @@ -361,9 +363,7 @@ static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel); static unsigned long dispc_plane_pclk_rate(enum omap_plane_id plane); static unsigned long dispc_plane_lclk_rate(enum omap_plane_id plane); -static void dispc_clear_irqstatus(u32 mask); -static bool dispc_mgr_is_enabled(enum omap_channel channel); -static void dispc_clear_irqstatus(u32 mask); +static void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask); static inline void dispc_write_reg(const u16 idx, u32 val) { @@ -396,14 +396,14 @@ static void mgr_fld_write(enum omap_channel channel, spin_unlock_irqrestore(&dispc.control_lock, flags); } -static int dispc_get_num_ovls(void) +static int dispc_get_num_ovls(struct dispc_device *dispc) { - return dispc.feat->num_ovls; + return dispc->feat->num_ovls; } -static int dispc_get_num_mgrs(void) +static int dispc_get_num_mgrs(struct dispc_device *dispc) { - return dispc.feat->num_mgrs; + return dispc->feat->num_mgrs; } static void dispc_get_reg_field(enum dispc_feat_reg_field id, @@ -455,7 +455,7 @@ static void dispc_save_context(void) SR(CONFIG3); } - for (i = 0; i < dispc_get_num_mgrs(); i++) { + for (i = 0; i < dispc_get_num_mgrs(&dispc); i++) { SR(DEFAULT_COLOR(i)); SR(TRANS_COLOR(i)); SR(SIZE_MGR(i)); @@ -477,7 +477,7 @@ static void dispc_save_context(void) } } - for (i = 0; i < dispc_get_num_ovls(); i++) { + for (i = 0; i < dispc_get_num_ovls(&dispc); i++) { SR(OVL_BA0(i)); SR(OVL_BA1(i)); SR(OVL_POSITION(i)); @@ -561,7 +561,7 @@ static void dispc_restore_context(void) if (dispc_has_feature(FEAT_MGR_LCD3)) RR(CONFIG3); - for (i = 0; i < dispc_get_num_mgrs(); i++) { + for (i = 0; i < dispc_get_num_mgrs(&dispc); i++) { RR(DEFAULT_COLOR(i)); RR(TRANS_COLOR(i)); RR(SIZE_MGR(i)); @@ -583,7 +583,7 @@ static void dispc_restore_context(void) } } - for (i = 0; i < dispc_get_num_ovls(); i++) { + for (i = 0; i < dispc_get_num_ovls(&dispc); i++) { RR(OVL_BA0(i)); RR(OVL_BA1(i)); RR(OVL_POSITION(i)); @@ -648,7 +648,7 @@ static void dispc_restore_context(void) if (dispc_has_feature(FEAT_MGR_LCD3)) RR(CONTROL3); /* clear spurious SYNC_LOST_DIGIT interrupts */ - dispc_clear_irqstatus(DISPC_IRQ_SYNC_LOST_DIGIT); + dispc_clear_irqstatus(&dispc, DISPC_IRQ_SYNC_LOST_DIGIT); /* * enable last so IRQs won't trigger before @@ -662,41 +662,44 @@ static void dispc_restore_context(void) #undef SR #undef RR -int dispc_runtime_get(void) +int dispc_runtime_get(struct dispc_device *dispc) { int r; DSSDBG("dispc_runtime_get\n"); - r = pm_runtime_get_sync(&dispc.pdev->dev); + r = pm_runtime_get_sync(&dispc->pdev->dev); WARN_ON(r < 0); return r < 0 ? r : 0; } -void dispc_runtime_put(void) +void dispc_runtime_put(struct dispc_device *dispc) { int r; DSSDBG("dispc_runtime_put\n"); - r = pm_runtime_put_sync(&dispc.pdev->dev); + r = pm_runtime_put_sync(&dispc->pdev->dev); WARN_ON(r < 0 && r != -ENOSYS); } -static u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) +static u32 dispc_mgr_get_vsync_irq(struct dispc_device *dispc, + enum omap_channel channel) { return mgr_desc[channel].vsync_irq; } -static u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) +static u32 dispc_mgr_get_framedone_irq(struct dispc_device *dispc, + enum omap_channel channel) { - if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv) + if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc->feat->no_framedone_tv) return 0; return mgr_desc[channel].framedone_irq; } -static u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel) +static u32 dispc_mgr_get_sync_lost_irq(struct dispc_device *dispc, + enum omap_channel channel) { return mgr_desc[channel].sync_lost_irq; } @@ -706,27 +709,30 @@ u32 dispc_wb_get_framedone_irq(void) return DISPC_IRQ_FRAMEDONEWB; } -static void dispc_mgr_enable(enum omap_channel channel, bool enable) +static void dispc_mgr_enable(struct dispc_device *dispc, + enum omap_channel channel, bool enable) { mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable); /* flush posted write */ mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); } -static bool dispc_mgr_is_enabled(enum omap_channel channel) +static bool dispc_mgr_is_enabled(struct dispc_device *dispc, + enum omap_channel channel) { return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); } -static bool dispc_mgr_go_busy(enum omap_channel channel) +static bool dispc_mgr_go_busy(struct dispc_device *dispc, + enum omap_channel channel) { return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; } -static void dispc_mgr_go(enum omap_channel channel) +static void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel) { - WARN_ON(!dispc_mgr_is_enabled(channel)); - WARN_ON(dispc_mgr_go_busy(channel)); + WARN_ON(!dispc_mgr_is_enabled(dispc, channel)); + WARN_ON(dispc_mgr_go_busy(dispc, channel)); DSSDBG("GO %s\n", mgr_desc[channel].name); @@ -864,7 +870,7 @@ static void dispc_ovl_write_color_conv_coef(enum omap_plane_id plane, static void dispc_setup_color_conv_coef(void) { int i; - int num_ovl = dispc_get_num_ovls(); + int num_ovl = dispc_get_num_ovls(&dispc); const struct color_conv_coef ctbl_bt601_5_ovl = { /* YUV -> RGB */ 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, @@ -956,7 +962,7 @@ static void dispc_ovl_enable_zorder_planes(void) if (!dispc_has_feature(FEAT_ALPHA_FREE_ZORDER)) return; - for (i = 0; i < dispc_get_num_ovls(); i++) + for (i = 0; i < dispc_get_num_ovls(&dispc); i++) REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); } @@ -1213,7 +1219,7 @@ static void dispc_configure_burst_sizes(void) const int burst_size = BURST_SIZE_X8; /* Configure burst size always to maximum size */ - for (i = 0; i < dispc_get_num_ovls(); ++i) + for (i = 0; i < dispc_get_num_ovls(&dispc); ++i) dispc_ovl_set_burst_size(i, burst_size); if (dispc.feat->has_writeback) dispc_ovl_set_burst_size(OMAP_DSS_WB, burst_size); @@ -1240,9 +1246,10 @@ static bool dispc_ovl_color_mode_supported(enum omap_plane_id plane, u32 fourcc) return false; } -static const u32 *dispc_ovl_get_color_modes(enum omap_plane_id plane) +static const u32 *dispc_ovl_get_color_modes(struct dispc_device *dispc, + enum omap_plane_id plane) { - return dispc.feat->supported_color_modes[plane]; + return dispc->feat->supported_color_modes[plane]; } static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) @@ -1359,7 +1366,7 @@ static void dispc_init_fifos(void) /* * Setup default fifo thresholds. */ - for (i = 0; i < dispc_get_num_ovls(); ++i) { + for (i = 0; i < dispc_get_num_ovls(&dispc); ++i) { u32 low, high; const bool use_fifomerge = false; const bool manual_update = false; @@ -1462,7 +1469,7 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, if (use_fifomerge) { total_fifo_size = 0; - for (i = 0; i < dispc_get_num_ovls(); ++i) + for (i = 0; i < dispc_get_num_ovls(&dispc); ++i) total_fifo_size += dispc_ovl_get_fifo_size(i); } else { total_fifo_size = ovl_fifo_size; @@ -1528,7 +1535,7 @@ static void dispc_init_mflag(void) (1 << 0) | /* MFLAG_CTRL = force always on */ (0 << 2)); /* MFLAG_START = disable */ - for (i = 0; i < dispc_get_num_ovls(); ++i) { + for (i = 0; i < dispc_get_num_ovls(&dispc); ++i) { u32 size = dispc_ovl_get_fifo_size(i); u32 unit = dispc.feat->buffer_size_unit; u32 low, high; @@ -2631,13 +2638,14 @@ static int dispc_ovl_setup_common(enum omap_plane_id plane, return 0; } -static int dispc_ovl_setup(enum omap_plane_id plane, - const struct omap_overlay_info *oi, - const struct videomode *vm, bool mem_to_mem, - enum omap_channel channel) +static int dispc_ovl_setup(struct dispc_device *dispc, + enum omap_plane_id plane, + const struct omap_overlay_info *oi, + const struct videomode *vm, bool mem_to_mem, + enum omap_channel channel) { int r; - enum omap_overlay_caps caps = dispc.feat->overlay_caps[plane]; + enum omap_overlay_caps caps = dispc->feat->overlay_caps[plane]; const bool replication = true; DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->" @@ -2724,7 +2732,8 @@ int dispc_wb_setup(const struct omap_dss_writeback_info *wi, return r; } -static int dispc_ovl_enable(enum omap_plane_id plane, bool enable) +static int dispc_ovl_enable(struct dispc_device *dispc, + enum omap_plane_id plane, bool enable) { DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); @@ -2733,9 +2742,11 @@ static int dispc_ovl_enable(enum omap_plane_id plane, bool enable) return 0; } -static enum omap_dss_output_id dispc_mgr_get_supported_outputs(enum omap_channel channel) +static enum omap_dss_output_id +dispc_mgr_get_supported_outputs(struct dispc_device *dispc, + enum omap_channel channel) { - return dss_get_supported_outputs(dispc.dss, channel); + return dss_get_supported_outputs(dispc->dss, channel); } static void dispc_lcd_enable_signal_polarity(bool act_high) @@ -2810,8 +2821,9 @@ static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); } -static void dispc_mgr_setup(enum omap_channel channel, - const struct omap_overlay_manager_info *info) +static void dispc_mgr_setup(struct dispc_device *dispc, + enum omap_channel channel, + const struct omap_overlay_manager_info *info) { dispc_mgr_set_default_color(channel, info->default_color); dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key); @@ -2883,8 +2895,9 @@ static void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable) mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable); } -static void dispc_mgr_set_lcd_config(enum omap_channel channel, - const struct dss_lcd_mgr_config *config) +static void dispc_mgr_set_lcd_config(struct dispc_device *dispc, + enum omap_channel channel, + const struct dss_lcd_mgr_config *config) { dispc_mgr_set_io_pad_mode(config->io_pad_mode); @@ -3039,8 +3052,9 @@ static int vm_flag_to_int(enum display_flags flags, enum display_flags high, } /* change name to mode? */ -static void dispc_mgr_set_timings(enum omap_channel channel, - const struct videomode *vm) +static void dispc_mgr_set_timings(struct dispc_device *dispc, + enum omap_channel channel, + const struct videomode *vm) { unsigned int xtot, ytot; unsigned long ht, vt; @@ -3078,7 +3092,7 @@ static void dispc_mgr_set_timings(enum omap_channel channel, if (t.flags & DISPLAY_FLAGS_INTERLACED) t.vactive /= 2; - if (dispc.feat->supports_double_pixel) + if (dispc->feat->supports_double_pixel) REG_FLD_MOD(DISPC_CONTROL, !!(t.flags & DISPLAY_FLAGS_DOUBLECLK), 19, 17); @@ -3241,7 +3255,7 @@ void dispc_dump_clocks(struct seq_file *s) u32 l; enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(dispc.dss); - if (dispc_runtime_get()) + if (dispc_runtime_get(&dispc)) return; seq_printf(s, "- DISPC -\n"); @@ -3267,7 +3281,7 @@ void dispc_dump_clocks(struct seq_file *s) if (dispc_has_feature(FEAT_MGR_LCD3)) dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3); - dispc_runtime_put(); + dispc_runtime_put(&dispc); } static int dispc_dump_regs(struct seq_file *s, void *p) @@ -3290,7 +3304,7 @@ static int dispc_dump_regs(struct seq_file *s, void *p) #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r)) - if (dispc_runtime_get()) + if (dispc_runtime_get(&dispc)) return 0; /* DISPC common registers */ @@ -3328,7 +3342,7 @@ static int dispc_dump_regs(struct seq_file *s, void *p) p_names = mgr_names; /* DISPC channel specific registers */ - for (i = 0; i < dispc_get_num_mgrs(); i++) { + for (i = 0; i < dispc_get_num_mgrs(&dispc); i++) { DUMPREG(i, DISPC_DEFAULT_COLOR); DUMPREG(i, DISPC_TRANS_COLOR); DUMPREG(i, DISPC_SIZE_MGR); @@ -3354,7 +3368,7 @@ static int dispc_dump_regs(struct seq_file *s, void *p) p_names = ovl_names; - for (i = 0; i < dispc_get_num_ovls(); i++) { + for (i = 0; i < dispc_get_num_ovls(&dispc); i++) { DUMPREG(i, DISPC_OVL_BA0); DUMPREG(i, DISPC_OVL_BA1); DUMPREG(i, DISPC_OVL_POSITION); @@ -3432,7 +3446,7 @@ static int dispc_dump_regs(struct seq_file *s, void *p) /* Video pipeline coefficient registers */ /* start from OMAP_DSS_VIDEO1 */ - for (i = 1; i < dispc_get_num_ovls(); i++) { + for (i = 1; i < dispc_get_num_ovls(&dispc); i++) { for (j = 0; j < 8; j++) DUMPREG(i, DISPC_OVL_FIR_COEF_H, j); @@ -3459,7 +3473,7 @@ static int dispc_dump_regs(struct seq_file *s, void *p) } } - dispc_runtime_put(); + dispc_runtime_put(&dispc); #undef DISPC_REG #undef DUMPREG @@ -3567,22 +3581,22 @@ int dispc_mgr_get_clock_div(enum omap_channel channel, return 0; } -static u32 dispc_read_irqstatus(void) +static u32 dispc_read_irqstatus(struct dispc_device *dispc) { return dispc_read_reg(DISPC_IRQSTATUS); } -static void dispc_clear_irqstatus(u32 mask) +static void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask) { dispc_write_reg(DISPC_IRQSTATUS, mask); } -static void dispc_write_irqenable(u32 mask) +static void dispc_write_irqenable(struct dispc_device *dispc, u32 mask) { u32 old_mask = dispc_read_reg(DISPC_IRQENABLE); /* clear the irqstatus for newly enabled irqs */ - dispc_clear_irqstatus((mask ^ old_mask) & mask); + dispc_clear_irqstatus(dispc, (mask ^ old_mask) & mask); dispc_write_reg(DISPC_IRQENABLE, mask); @@ -3600,11 +3614,12 @@ void dispc_disable_sidle(void) REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ } -static u32 dispc_mgr_gamma_size(enum omap_channel channel) +static u32 dispc_mgr_gamma_size(struct dispc_device *dispc, + enum omap_channel channel) { const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; - if (!dispc.feat->has_gamma_table) + if (!dispc->feat->has_gamma_table) return 0; return gdesc->len; @@ -3653,18 +3668,19 @@ static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = { { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, }, }; -static void dispc_mgr_set_gamma(enum omap_channel channel, - const struct drm_color_lut *lut, - unsigned int length) +static void dispc_mgr_set_gamma(struct dispc_device *dispc, + enum omap_channel channel, + const struct drm_color_lut *lut, + unsigned int length) { const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; - u32 *table = dispc.gamma_table[channel]; + u32 *table = dispc->gamma_table[channel]; uint i; DSSDBG("%s: channel %d, lut len %u, hw len %u\n", __func__, channel, length, gdesc->len); - if (!dispc.feat->has_gamma_table) + if (!dispc->feat->has_gamma_table) return; if (lut == NULL || length < 2) { @@ -3696,7 +3712,7 @@ static void dispc_mgr_set_gamma(enum omap_channel channel, } } - if (dispc.is_enabled) + if (dispc->is_enabled) dispc_mgr_write_gamma_table(channel); } @@ -3726,7 +3742,7 @@ static int dispc_init_gamma_tables(void) dispc.gamma_table[channel] = gt; - dispc_mgr_set_gamma(channel, NULL, 0); + dispc_mgr_set_gamma(&dispc, channel, NULL, 0); } return 0; } @@ -4296,43 +4312,44 @@ static irqreturn_t dispc_irq_handler(int irq, void *arg) return dispc.user_handler(irq, dispc.user_data); } -static int dispc_request_irq(irq_handler_t handler, void *dev_id) +static int dispc_request_irq(struct dispc_device *dispc, irq_handler_t handler, + void *dev_id) { int r; - if (dispc.user_handler != NULL) + if (dispc->user_handler != NULL) return -EBUSY; - dispc.user_handler = handler; - dispc.user_data = dev_id; + dispc->user_handler = handler; + dispc->user_data = dev_id; /* ensure the dispc_irq_handler sees the values above */ smp_wmb(); - r = devm_request_irq(&dispc.pdev->dev, dispc.irq, dispc_irq_handler, - IRQF_SHARED, "OMAP DISPC", &dispc); + r = devm_request_irq(&dispc->pdev->dev, dispc->irq, dispc_irq_handler, + IRQF_SHARED, "OMAP DISPC", dispc); if (r) { - dispc.user_handler = NULL; - dispc.user_data = NULL; + dispc->user_handler = NULL; + dispc->user_data = NULL; } return r; } -static void dispc_free_irq(void *dev_id) +static void dispc_free_irq(struct dispc_device *dispc, void *dev_id) { - devm_free_irq(&dispc.pdev->dev, dispc.irq, &dispc); + devm_free_irq(&dispc->pdev->dev, dispc->irq, dispc); - dispc.user_handler = NULL; - dispc.user_data = NULL; + dispc->user_handler = NULL; + dispc->user_data = NULL; } -static u32 dispc_get_memory_bandwidth_limit(void) +static u32 dispc_get_memory_bandwidth_limit(struct dispc_device *dispc) { u32 limit = 0; /* Optional maximum memory bandwidth */ - of_property_read_u32(dispc.pdev->dev.of_node, "max-memory-bandwidth", + of_property_read_u32(dispc->pdev->dev.of_node, "max-memory-bandwidth", &limit); return limit; @@ -4439,7 +4456,8 @@ static void dispc_errata_i734_wa_fini(void) static void dispc_errata_i734_wa(void) { - u32 framedone_irq = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_LCD); + u32 framedone_irq = dispc_mgr_get_framedone_irq(&dispc, + OMAP_DSS_CHANNEL_LCD); struct omap_overlay_info ovli; struct dss_lcd_mgr_config lcd_conf; u32 gatestate; @@ -4458,39 +4476,39 @@ static void dispc_errata_i734_wa(void) REG_FLD_MOD(DISPC_CONFIG, 0x1f, 8, 4); /* Setup and enable GFX plane */ - dispc_ovl_setup(OMAP_DSS_GFX, &ovli, &i734.vm, false, - OMAP_DSS_CHANNEL_LCD); - dispc_ovl_enable(OMAP_DSS_GFX, true); + dispc_ovl_setup(&dispc, OMAP_DSS_GFX, &ovli, &i734.vm, false, + OMAP_DSS_CHANNEL_LCD); + dispc_ovl_enable(&dispc, OMAP_DSS_GFX, true); /* Set up and enable display manager for LCD1 */ - dispc_mgr_setup(OMAP_DSS_CHANNEL_LCD, &i734.mgri); + dispc_mgr_setup(&dispc, OMAP_DSS_CHANNEL_LCD, &i734.mgri); dispc_calc_clock_rates(dss_get_dispc_clk_rate(dispc.dss), &lcd_conf.clock_info); - dispc_mgr_set_lcd_config(OMAP_DSS_CHANNEL_LCD, &lcd_conf); - dispc_mgr_set_timings(OMAP_DSS_CHANNEL_LCD, &i734.vm); + dispc_mgr_set_lcd_config(&dispc, OMAP_DSS_CHANNEL_LCD, &lcd_conf); + dispc_mgr_set_timings(&dispc, OMAP_DSS_CHANNEL_LCD, &i734.vm); - dispc_clear_irqstatus(framedone_irq); + dispc_clear_irqstatus(&dispc, framedone_irq); /* Enable and shut the channel to produce just one frame */ - dispc_mgr_enable(OMAP_DSS_CHANNEL_LCD, true); - dispc_mgr_enable(OMAP_DSS_CHANNEL_LCD, false); + dispc_mgr_enable(&dispc, OMAP_DSS_CHANNEL_LCD, true); + dispc_mgr_enable(&dispc, OMAP_DSS_CHANNEL_LCD, false); /* Busy wait for framedone. We can't fiddle with irq handlers * in PM resume. Typically the loop runs less than 5 times and * waits less than a micro second. */ count = 0; - while (!(dispc_read_irqstatus() & framedone_irq)) { + while (!(dispc_read_irqstatus(&dispc) & framedone_irq)) { if (count++ > 10000) { dev_err(&dispc.pdev->dev, "%s: framedone timeout\n", __func__); break; } } - dispc_ovl_enable(OMAP_DSS_GFX, false); + dispc_ovl_enable(&dispc, OMAP_DSS_GFX, false); /* Clear all irq bits before continuing */ - dispc_clear_irqstatus(0xffffffff); + dispc_clear_irqstatus(&dispc, 0xffffffff); /* Restore the original state to LCD1 output gates */ REG_FLD_MOD(DISPC_CONFIG, gatestate, 8, 4); @@ -4610,7 +4628,7 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) pm_runtime_enable(&pdev->dev); - r = dispc_runtime_get(); + r = dispc_runtime_get(&dispc); if (r) goto err_runtime_get; @@ -4620,8 +4638,9 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - dispc_runtime_put(); + dispc_runtime_put(&dispc); + dss->dispc = &dispc; dss->dispc_ops = &dispc_ops; dispc.debugfs = dss_debugfs_create_file(dss, "dispc", dispc_dump_regs, @@ -4634,13 +4653,13 @@ err_runtime_get: return r; } -static void dispc_unbind(struct device *dev, struct device *master, - void *data) +static void dispc_unbind(struct device *dev, struct device *master, void *data) { struct dss_device *dss = dispc.dss; dss_debugfs_remove_file(dispc.debugfs); + dss->dispc = NULL; dss->dispc_ops = NULL; pm_runtime_disable(dev); diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index e818e7836cbb..d524094b8394 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -406,7 +406,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) goto err_reg_enable; } - r = dispc_runtime_get(); + r = dispc_runtime_get(dpi->dss->dispc); if (r) goto err_get_dispc; @@ -442,7 +442,7 @@ err_set_mode: dss_pll_disable(dpi->pll); err_pll_init: err_src_sel: - dispc_runtime_put(); + dispc_runtime_put(dpi->dss->dispc); err_get_dispc: if (dpi->vdds_dsi_reg) regulator_disable(dpi->vdds_dsi_reg); @@ -466,7 +466,7 @@ static void dpi_display_disable(struct omap_dss_device *dssdev) dss_pll_disable(dpi->pll); } - dispc_runtime_put(); + dispc_runtime_put(dpi->dss->dispc); if (dpi->vdds_dsi_reg) regulator_disable(dpi->vdds_dsi_reg); diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 66c4d973e7eb..c07326a46c01 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -5523,7 +5523,7 @@ static int dsi_runtime_suspend(struct device *dev) /* wait for current handler to finish before turning the DSI off */ synchronize_irq(dsi->irq); - dispc_runtime_put(); + dispc_runtime_put(dsi->dss->dispc); return 0; } @@ -5533,7 +5533,7 @@ static int dsi_runtime_resume(struct device *dev) struct dsi_data *dsi = dev_get_drvdata(dev); int r; - r = dispc_runtime_get(); + r = dispc_runtime_get(dsi->dss->dispc); if (r) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 348378f1b5a5..f3acfd62031c 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -25,6 +25,7 @@ #include "omapdss.h" +struct dispc_device; struct dss_debugfs_entry; struct platform_device; struct seq_file; @@ -272,6 +273,7 @@ struct dss_device { struct dss_pll *video1_pll; struct dss_pll *video2_pll; + struct dispc_device *dispc; const struct dispc_ops *dispc_ops; }; @@ -407,8 +409,8 @@ static inline void dpi_uninit_port(struct device_node *port) /* DISPC */ void dispc_dump_clocks(struct seq_file *s); -int dispc_runtime_get(void); -void dispc_runtime_put(void); +int dispc_runtime_get(struct dispc_device *dispc); +void dispc_runtime_put(struct dispc_device *dispc); void dispc_enable_sidle(void); void dispc_disable_sidle(void); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 096542fb75d2..5c55fa3f593a 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -819,16 +819,19 @@ static int hdmi4_remove(struct platform_device *pdev) static int hdmi_runtime_suspend(struct device *dev) { - dispc_runtime_put(); + struct omap_hdmi *hdmi = dev_get_drvdata(dev); + + dispc_runtime_put(hdmi->dss->dispc); return 0; } static int hdmi_runtime_resume(struct device *dev) { + struct omap_hdmi *hdmi = dev_get_drvdata(dev); int r; - r = dispc_runtime_get(); + r = dispc_runtime_get(hdmi->dss->dispc); if (r < 0) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 597baebd959c..e896f63480f1 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -814,16 +814,19 @@ static int hdmi5_remove(struct platform_device *pdev) static int hdmi_runtime_suspend(struct device *dev) { - dispc_runtime_put(); + struct omap_hdmi *hdmi = dev_get_drvdata(dev); + + dispc_runtime_put(hdmi->dss->dispc); return 0; } static int hdmi_runtime_resume(struct device *dev) { + struct omap_hdmi *hdmi = dev_get_drvdata(dev); int r; - r = dispc_runtime_get(); + r = dispc_runtime_get(hdmi->dss->dispc); if (r < 0) return r; diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 4bf7843b4aec..a4f71e082c1c 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -62,6 +62,8 @@ struct dss_device; struct omap_drm_private; struct omap_dss_device; +struct dispc_device; +struct dss_device; struct dss_lcd_mgr_config; struct snd_aes_iec958; struct snd_cea_861_aud_if; @@ -690,49 +692,64 @@ void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev, /* dispc ops */ struct dispc_ops { - u32 (*read_irqstatus)(void); - void (*clear_irqstatus)(u32 mask); - void (*write_irqenable)(u32 mask); - - int (*request_irq)(irq_handler_t handler, void *dev_id); - void (*free_irq)(void *dev_id); - - int (*runtime_get)(void); - void (*runtime_put)(void); - - int (*get_num_ovls)(void); - int (*get_num_mgrs)(void); - - u32 (*get_memory_bandwidth_limit)(void); - - void (*mgr_enable)(enum omap_channel channel, bool enable); - bool (*mgr_is_enabled)(enum omap_channel channel); - u32 (*mgr_get_vsync_irq)(enum omap_channel channel); - u32 (*mgr_get_framedone_irq)(enum omap_channel channel); - u32 (*mgr_get_sync_lost_irq)(enum omap_channel channel); - bool (*mgr_go_busy)(enum omap_channel channel); - void (*mgr_go)(enum omap_channel channel); - void (*mgr_set_lcd_config)(enum omap_channel channel, - const struct dss_lcd_mgr_config *config); - void (*mgr_set_timings)(enum omap_channel channel, - const struct videomode *vm); - void (*mgr_setup)(enum omap_channel channel, - const struct omap_overlay_manager_info *info); - enum omap_dss_output_id (*mgr_get_supported_outputs)(enum omap_channel channel); - u32 (*mgr_gamma_size)(enum omap_channel channel); - void (*mgr_set_gamma)(enum omap_channel channel, - const struct drm_color_lut *lut, - unsigned int length); - - int (*ovl_enable)(enum omap_plane_id plane, bool enable); - int (*ovl_setup)(enum omap_plane_id plane, + u32 (*read_irqstatus)(struct dispc_device *dispc); + void (*clear_irqstatus)(struct dispc_device *dispc, u32 mask); + void (*write_irqenable)(struct dispc_device *dispc, u32 mask); + + int (*request_irq)(struct dispc_device *dispc, irq_handler_t handler, + void *dev_id); + void (*free_irq)(struct dispc_device *dispc, void *dev_id); + + int (*runtime_get)(struct dispc_device *dispc); + void (*runtime_put)(struct dispc_device *dispc); + + int (*get_num_ovls)(struct dispc_device *dispc); + int (*get_num_mgrs)(struct dispc_device *dispc); + + u32 (*get_memory_bandwidth_limit)(struct dispc_device *dispc); + + void (*mgr_enable)(struct dispc_device *dispc, + enum omap_channel channel, bool enable); + bool (*mgr_is_enabled)(struct dispc_device *dispc, + enum omap_channel channel); + u32 (*mgr_get_vsync_irq)(struct dispc_device *dispc, + enum omap_channel channel); + u32 (*mgr_get_framedone_irq)(struct dispc_device *dispc, + enum omap_channel channel); + u32 (*mgr_get_sync_lost_irq)(struct dispc_device *dispc, + enum omap_channel channel); + bool (*mgr_go_busy)(struct dispc_device *dispc, + enum omap_channel channel); + void (*mgr_go)(struct dispc_device *dispc, enum omap_channel channel); + void (*mgr_set_lcd_config)(struct dispc_device *dispc, + enum omap_channel channel, + const struct dss_lcd_mgr_config *config); + void (*mgr_set_timings)(struct dispc_device *dispc, + enum omap_channel channel, + const struct videomode *vm); + void (*mgr_setup)(struct dispc_device *dispc, enum omap_channel channel, + const struct omap_overlay_manager_info *info); + enum omap_dss_output_id (*mgr_get_supported_outputs)( + struct dispc_device *dispc, enum omap_channel channel); + u32 (*mgr_gamma_size)(struct dispc_device *dispc, + enum omap_channel channel); + void (*mgr_set_gamma)(struct dispc_device *dispc, + enum omap_channel channel, + const struct drm_color_lut *lut, + unsigned int length); + + int (*ovl_enable)(struct dispc_device *dispc, enum omap_plane_id plane, + bool enable); + int (*ovl_setup)(struct dispc_device *dispc, enum omap_plane_id plane, const struct omap_overlay_info *oi, - const struct videomode *vm, bool mem_to_mem, - enum omap_channel channel); + const struct videomode *vm, bool mem_to_mem, + enum omap_channel channel); - const u32 *(*ovl_get_color_modes)(enum omap_plane_id plane); + const u32 *(*ovl_get_color_modes)(struct dispc_device *dispc, + enum omap_plane_id plane); }; +struct dispc_device *dispc_get_dispc(struct dss_device *dss); const struct dispc_ops *dispc_get_ops(struct dss_device *dss); bool omapdss_component_is_display(struct device_node *node); diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index bf225ae69b06..b1d0e706a1ec 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -141,7 +141,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_reg_enable; - r = dispc_runtime_get(); + r = dispc_runtime_get(sdi.dss->dispc); if (r) goto err_get_dispc; @@ -203,7 +203,7 @@ err_mgr_enable: err_sdi_enable: err_set_dss_clock_div: err_calc_clock_div: - dispc_runtime_put(); + dispc_runtime_put(sdi.dss->dispc); err_get_dispc: regulator_disable(sdi.vdds_sdi_reg); err_reg_enable: @@ -216,7 +216,7 @@ static void sdi_display_disable(struct omap_dss_device *dssdev) dss_sdi_disable(sdi.dss); - dispc_runtime_put(); + dispc_runtime_put(sdi.dss->dispc); regulator_disable(sdi.vdds_sdi_reg); } diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index bed3b54b70b2..546271389189 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -956,7 +956,7 @@ static int venc_runtime_suspend(struct device *dev) if (venc.tv_dac_clk) clk_disable_unprepare(venc.tv_dac_clk); - dispc_runtime_put(); + dispc_runtime_put(venc.dss->dispc); return 0; } @@ -965,7 +965,7 @@ static int venc_runtime_resume(struct device *dev) { int r; - r = dispc_runtime_get(); + r = dispc_runtime_get(venc.dss->dispc); if (r < 0) return r; diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index ffe4f698d291..6c4d40b824e4 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -117,10 +117,13 @@ static int omap_crtc_dss_connect(struct omap_drm_private *priv, enum omap_channel channel, struct omap_dss_device *dst) { + const struct dispc_ops *dispc_ops = priv->dispc_ops; + struct dispc_device *dispc = priv->dispc; + if (omap_crtc_output[channel]) return -EINVAL; - if (!(priv->dispc_ops->mgr_get_supported_outputs(channel) & dst->id)) + if (!(dispc_ops->mgr_get_supported_outputs(dispc, channel) & dst->id)) return -EINVAL; omap_crtc_output[channel] = dst; @@ -157,7 +160,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) return; if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) { - priv->dispc_ops->mgr_enable(channel, enable); + priv->dispc_ops->mgr_enable(priv->dispc, channel, enable); omap_crtc->enabled = enable; return; } @@ -170,8 +173,9 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) omap_crtc->ignore_digit_sync_lost = true; } - framedone_irq = priv->dispc_ops->mgr_get_framedone_irq(channel); - vsync_irq = priv->dispc_ops->mgr_get_vsync_irq(channel); + framedone_irq = priv->dispc_ops->mgr_get_framedone_irq(priv->dispc, + channel); + vsync_irq = priv->dispc_ops->mgr_get_vsync_irq(priv->dispc, channel); if (enable) { wait = omap_irq_wait_init(dev, vsync_irq, 1); @@ -191,7 +195,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) wait = omap_irq_wait_init(dev, vsync_irq, 2); } - priv->dispc_ops->mgr_enable(channel, enable); + priv->dispc_ops->mgr_enable(priv->dispc, channel, enable); omap_crtc->enabled = enable; ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); @@ -213,7 +217,8 @@ static int omap_crtc_dss_enable(struct omap_drm_private *priv, { struct omap_crtc *omap_crtc = omap_crtcs[channel]; - priv->dispc_ops->mgr_set_timings(omap_crtc->channel, &omap_crtc->vm); + priv->dispc_ops->mgr_set_timings(priv->dispc, omap_crtc->channel, + &omap_crtc->vm); omap_crtc_set_enabled(&omap_crtc->base, true); return 0; @@ -243,7 +248,8 @@ static void omap_crtc_dss_set_lcd_config(struct omap_drm_private *priv, struct omap_crtc *omap_crtc = omap_crtcs[channel]; DBG("%s", omap_crtc->name); - priv->dispc_ops->mgr_set_lcd_config(omap_crtc->channel, config); + priv->dispc_ops->mgr_set_lcd_config(priv->dispc, omap_crtc->channel, + config); } static int omap_crtc_dss_register_framedone( @@ -300,7 +306,7 @@ void omap_crtc_vblank_irq(struct drm_crtc *crtc) * If the dispc is busy we're racing the flush operation. Try again on * the next vblank interrupt. */ - if (priv->dispc_ops->mgr_go_busy(omap_crtc->channel)) { + if (priv->dispc_ops->mgr_go_busy(priv->dispc, omap_crtc->channel)) { spin_unlock(&crtc->dev->event_lock); return; } @@ -337,7 +343,7 @@ static void omap_crtc_write_crtc_properties(struct drm_crtc *crtc) info.partial_alpha_enabled = false; info.cpr_enable = false; - priv->dispc_ops->mgr_setup(omap_crtc->channel, &info); + priv->dispc_ops->mgr_setup(priv->dispc, omap_crtc->channel, &info); } /* ----------------------------------------------------------------------------- @@ -537,7 +543,8 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, length = crtc->state->gamma_lut->length / sizeof(*lut); } - priv->dispc_ops->mgr_set_gamma(omap_crtc->channel, lut, length); + priv->dispc_ops->mgr_set_gamma(priv->dispc, omap_crtc->channel, + lut, length); } omap_crtc_write_crtc_properties(crtc); @@ -552,7 +559,7 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, WARN_ON(ret != 0); spin_lock_irq(&crtc->dev->event_lock); - priv->dispc_ops->mgr_go(omap_crtc->channel); + priv->dispc_ops->mgr_go(priv->dispc, omap_crtc->channel); omap_crtc_arm_event(crtc); spin_unlock_irq(&crtc->dev->event_lock); } @@ -734,7 +741,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, * extracted with dispc_mgr_gamma_size(). If it returns 0 * gamma table is not supprted. */ - if (priv->dispc_ops->mgr_gamma_size(channel)) { + if (priv->dispc_ops->mgr_gamma_size(priv->dispc, channel)) { unsigned int gamma_lut_size = 256; drm_crtc_enable_color_mgmt(crtc, 0, false, gamma_lut_size); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index a93916cd0258..65a567dcf3ab 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -69,7 +69,7 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) struct drm_device *dev = old_state->dev; struct omap_drm_private *priv = dev->dev_private; - priv->dispc_ops->runtime_get(); + priv->dispc_ops->runtime_get(priv->dispc); /* Apply the atomic update. */ drm_atomic_helper_commit_modeset_disables(dev, old_state); @@ -113,7 +113,7 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) drm_atomic_helper_cleanup_planes(dev, old_state); - priv->dispc_ops->runtime_put(); + priv->dispc_ops->runtime_put(priv->dispc); } static const struct drm_mode_config_helper_funcs omap_mode_config_helper_funcs = { @@ -191,7 +191,7 @@ cleanup: static int omap_modeset_init_properties(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; - unsigned int num_planes = priv->dispc_ops->get_num_ovls(); + unsigned int num_planes = priv->dispc_ops->get_num_ovls(priv->dispc); priv->zorder_prop = drm_property_create_range(dev, 0, "zorder", 0, num_planes - 1); @@ -205,8 +205,8 @@ static int omap_modeset_init(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_dss_device *dssdev = NULL; - int num_ovls = priv->dispc_ops->get_num_ovls(); - int num_mgrs = priv->dispc_ops->get_num_mgrs(); + int num_ovls = priv->dispc_ops->get_num_ovls(priv->dispc); + int num_mgrs = priv->dispc_ops->get_num_mgrs(priv->dispc); int num_crtcs, crtc_idx, plane_idx; int ret; u32 plane_crtc_mask; @@ -521,6 +521,7 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) priv->dev = dev; priv->dss = omapdss_get_dss(); + priv->dispc = dispc_get_dispc(priv->dss); priv->dispc_ops = dispc_get_ops(priv->dss); omap_crtc_pre_init(priv); @@ -549,7 +550,7 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) /* Get memory bandwidth limits */ if (priv->dispc_ops->get_memory_bandwidth_limit) priv->max_bandwidth = - priv->dispc_ops->get_memory_bandwidth_limit(); + priv->dispc_ops->get_memory_bandwidth_limit(priv->dispc); omap_gem_init(ddev); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index a7962c14fc7c..6eaee4df4559 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -51,6 +51,7 @@ struct omap_drm_private { u32 omaprev; struct dss_device *dss; + struct dispc_device *dispc; const struct dispc_ops *dispc_ops; unsigned int num_crtcs; diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c index 976dc0e44482..c85115049f86 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/drivers/gpu/drm/omapdrm/omap_irq.c @@ -38,7 +38,7 @@ static void omap_irq_update(struct drm_device *dev) DBG("irqmask=%08x", irqmask); - priv->dispc_ops->write_irqenable(irqmask); + priv->dispc_ops->write_irqenable(priv->dispc, irqmask); } static void omap_irq_wait_handler(struct omap_irq_wait *wait) @@ -108,7 +108,8 @@ int omap_irq_enable_vblank(struct drm_crtc *crtc) DBG("dev=%p, crtc=%u", dev, channel); spin_lock_irqsave(&priv->wait_lock, flags); - priv->irq_mask |= priv->dispc_ops->mgr_get_vsync_irq(channel); + priv->irq_mask |= priv->dispc_ops->mgr_get_vsync_irq(priv->dispc, + channel); omap_irq_update(dev); spin_unlock_irqrestore(&priv->wait_lock, flags); @@ -134,7 +135,8 @@ void omap_irq_disable_vblank(struct drm_crtc *crtc) DBG("dev=%p, crtc=%u", dev, channel); spin_lock_irqsave(&priv->wait_lock, flags); - priv->irq_mask &= ~priv->dispc_ops->mgr_get_vsync_irq(channel); + priv->irq_mask &= ~priv->dispc_ops->mgr_get_vsync_irq(priv->dispc, + channel); omap_irq_update(dev); spin_unlock_irqrestore(&priv->wait_lock, flags); } @@ -198,9 +200,9 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) unsigned int id; u32 irqstatus; - irqstatus = priv->dispc_ops->read_irqstatus(); - priv->dispc_ops->clear_irqstatus(irqstatus); - priv->dispc_ops->read_irqstatus(); /* flush posted write */ + irqstatus = priv->dispc_ops->read_irqstatus(priv->dispc); + priv->dispc_ops->clear_irqstatus(priv->dispc, irqstatus); + priv->dispc_ops->read_irqstatus(priv->dispc); /* flush posted write */ VERB("irqs: %08x", irqstatus); @@ -208,12 +210,12 @@ static irqreturn_t omap_irq_handler(int irq, void *arg) struct drm_crtc *crtc = priv->crtcs[id]; enum omap_channel channel = omap_crtc_channel(crtc); - if (irqstatus & priv->dispc_ops->mgr_get_vsync_irq(channel)) { + if (irqstatus & priv->dispc_ops->mgr_get_vsync_irq(priv->dispc, channel)) { drm_handle_vblank(dev, id); omap_crtc_vblank_irq(crtc); } - if (irqstatus & priv->dispc_ops->mgr_get_sync_lost_irq(channel)) + if (irqstatus & priv->dispc_ops->mgr_get_sync_lost_irq(priv->dispc, channel)) omap_crtc_error_irq(crtc, irqstatus); } @@ -247,7 +249,7 @@ static const u32 omap_underflow_irqs[] = { int omap_drm_irq_install(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; - unsigned int num_mgrs = priv->dispc_ops->get_num_mgrs(); + unsigned int num_mgrs = priv->dispc_ops->get_num_mgrs(priv->dispc); unsigned int max_planes; unsigned int i; int ret; @@ -265,13 +267,13 @@ int omap_drm_irq_install(struct drm_device *dev) } for (i = 0; i < num_mgrs; ++i) - priv->irq_mask |= priv->dispc_ops->mgr_get_sync_lost_irq(i); + priv->irq_mask |= priv->dispc_ops->mgr_get_sync_lost_irq(priv->dispc, i); - priv->dispc_ops->runtime_get(); - priv->dispc_ops->clear_irqstatus(0xffffffff); - priv->dispc_ops->runtime_put(); + priv->dispc_ops->runtime_get(priv->dispc); + priv->dispc_ops->clear_irqstatus(priv->dispc, 0xffffffff); + priv->dispc_ops->runtime_put(priv->dispc); - ret = priv->dispc_ops->request_irq(omap_irq_handler, dev); + ret = priv->dispc_ops->request_irq(priv->dispc, omap_irq_handler, dev); if (ret < 0) return ret; @@ -289,5 +291,5 @@ void omap_drm_irq_uninstall(struct drm_device *dev) dev->irq_enabled = false; - priv->dispc_ops->free_irq(dev); + priv->dispc_ops->free_irq(priv->dispc, dev); } diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 0665ed9fe395..2899435cad6e 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -77,17 +77,17 @@ static void omap_plane_atomic_update(struct drm_plane *plane, &info.paddr, &info.p_uv_addr); /* and finally, update omapdss: */ - ret = priv->dispc_ops->ovl_setup(omap_plane->id, &info, + ret = priv->dispc_ops->ovl_setup(priv->dispc, omap_plane->id, &info, omap_crtc_timings(state->crtc), false, omap_crtc_channel(state->crtc)); if (ret) { dev_err(plane->dev->dev, "Failed to setup plane %s\n", omap_plane->name); - priv->dispc_ops->ovl_enable(omap_plane->id, false); + priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, false); return; } - priv->dispc_ops->ovl_enable(omap_plane->id, true); + priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, true); } static void omap_plane_atomic_disable(struct drm_plane *plane, @@ -100,7 +100,7 @@ static void omap_plane_atomic_disable(struct drm_plane *plane, plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : omap_plane->id; - priv->dispc_ops->ovl_enable(omap_plane->id, false); + priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, false); } static int omap_plane_atomic_check(struct drm_plane *plane, @@ -259,7 +259,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, u32 possible_crtcs) { struct omap_drm_private *priv = dev->dev_private; - unsigned int num_planes = priv->dispc_ops->get_num_ovls(); + unsigned int num_planes = priv->dispc_ops->get_num_ovls(priv->dispc); struct drm_plane *plane; struct omap_plane *omap_plane; enum omap_plane_id id; @@ -278,7 +278,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, if (!omap_plane) return ERR_PTR(-ENOMEM); - formats = priv->dispc_ops->ovl_get_color_modes(id); + formats = priv->dispc_ops->ovl_get_color_modes(priv->dispc, id); for (nformats = 0; formats[nformats]; ++nformats) ; omap_plane->id = id; -- cgit v1.2.3 From 8a7eda7686675b73d74c22c0d5b83059f9d783f6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:43 +0200 Subject: drm: omapdrm: dispc: Pass DISPC pointer to remaining dispc API functions This removes the need to access the global DISPC private data in those functions (both for the current accesses and the future ones that will be introduced when allocating the DISPC private data dynamically). Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dispc.c | 102 ++++++++++++++++++++---------------- drivers/gpu/drm/omapdrm/dss/dpi.c | 12 +++-- drivers/gpu/drm/omapdrm/dss/dsi.c | 22 ++++---- drivers/gpu/drm/omapdrm/dss/dss.c | 14 ++--- drivers/gpu/drm/omapdrm/dss/dss.h | 74 ++++++++++++++------------ drivers/gpu/drm/omapdrm/dss/hdmi4.c | 4 +- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 4 +- drivers/gpu/drm/omapdrm/dss/sdi.c | 9 ++-- drivers/gpu/drm/omapdrm/dss/venc.c | 2 +- 9 files changed, 133 insertions(+), 110 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 6d8228f976f9..bd014bfc1cb6 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -704,7 +704,7 @@ static u32 dispc_mgr_get_sync_lost_irq(struct dispc_device *dispc, return mgr_desc[channel].sync_lost_irq; } -u32 dispc_wb_get_framedone_irq(void) +u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc) { return DISPC_IRQ_FRAMEDONEWB; } @@ -739,12 +739,12 @@ static void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel) mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); } -bool dispc_wb_go_busy(void) +bool dispc_wb_go_busy(struct dispc_device *dispc) { return REG_GET(DISPC_CONTROL2, 6, 6) == 1; } -void dispc_wb_go(void) +void dispc_wb_go(struct dispc_device *dispc) { enum omap_plane_id plane = OMAP_DSS_WB; bool enable, go; @@ -1196,7 +1196,8 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane_id plane) } } -void dispc_wb_set_channel_in(enum dss_writeback_channel channel) +void dispc_wb_set_channel_in(struct dispc_device *dispc, + enum dss_writeback_channel channel) { enum omap_plane_id plane = OMAP_DSS_WB; @@ -1371,10 +1372,10 @@ static void dispc_init_fifos(void) const bool use_fifomerge = false; const bool manual_update = false; - dispc_ovl_compute_fifo_thresholds(i, &low, &high, + dispc_ovl_compute_fifo_thresholds(&dispc, i, &low, &high, use_fifomerge, manual_update); - dispc_ovl_set_fifo_threshold(i, low, high); + dispc_ovl_set_fifo_threshold(&dispc, i, low, high); } if (dispc.feat->has_writeback) { @@ -1382,10 +1383,11 @@ static void dispc_init_fifos(void) const bool use_fifomerge = false; const bool manual_update = false; - dispc_ovl_compute_fifo_thresholds(OMAP_DSS_WB, &low, &high, - use_fifomerge, manual_update); + dispc_ovl_compute_fifo_thresholds(&dispc, OMAP_DSS_WB, + &low, &high, + use_fifomerge, manual_update); - dispc_ovl_set_fifo_threshold(OMAP_DSS_WB, low, high); + dispc_ovl_set_fifo_threshold(&dispc, OMAP_DSS_WB, low, high); } } @@ -1402,13 +1404,14 @@ static u32 dispc_ovl_get_fifo_size(enum omap_plane_id plane) return size; } -void dispc_ovl_set_fifo_threshold(enum omap_plane_id plane, u32 low, - u32 high) +void dispc_ovl_set_fifo_threshold(struct dispc_device *dispc, + enum omap_plane_id plane, + u32 low, u32 high) { u8 hi_start, hi_end, lo_start, lo_end; u32 unit; - unit = dispc.feat->buffer_size_unit; + unit = dispc->feat->buffer_size_unit; WARN_ON(low % unit != 0); WARN_ON(high % unit != 0); @@ -1436,12 +1439,12 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane_id plane, u32 low, * large for the preload field, set the threshold to the maximum value * that can be held by the preload register */ - if (dispc_has_feature(FEAT_PRELOAD) && dispc.feat->set_max_preload && + if (dispc_has_feature(FEAT_PRELOAD) && dispc->feat->set_max_preload && plane != OMAP_DSS_WB) dispc_write_reg(DISPC_OVL_PRELOAD(plane), min(high, 0xfffu)); } -void dispc_enable_fifomerge(bool enable) +void dispc_enable_fifomerge(struct dispc_device *dispc, bool enable) { if (!dispc_has_feature(FEAT_FIFO_MERGE)) { WARN_ON(enable); @@ -1452,15 +1455,16 @@ void dispc_enable_fifomerge(bool enable) REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); } -void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, - u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, - bool manual_update) +void dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc, + enum omap_plane_id plane, + u32 *fifo_low, u32 *fifo_high, + bool use_fifomerge, bool manual_update) { /* * All sizes are in bytes. Both the buffer and burst are made of * buffer_units, and the fifo thresholds must be buffer_unit aligned. */ - unsigned int buf_unit = dispc.feat->buffer_size_unit; + unsigned int buf_unit = dispc->feat->buffer_size_unit; unsigned int ovl_fifo_size, total_fifo_size, burst_size; int i; @@ -1469,7 +1473,7 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, if (use_fifomerge) { total_fifo_size = 0; - for (i = 0; i < dispc_get_num_ovls(&dispc); ++i) + for (i = 0; i < dispc_get_num_ovls(dispc); ++i) total_fifo_size += dispc_ovl_get_fifo_size(i); } else { total_fifo_size = ovl_fifo_size; @@ -2665,8 +2669,9 @@ static int dispc_ovl_setup(struct dispc_device *dispc, return r; } -int dispc_wb_setup(const struct omap_dss_writeback_info *wi, - bool mem_to_mem, const struct videomode *vm) +int dispc_wb_setup(struct dispc_device *dispc, + const struct omap_dss_writeback_info *wi, + bool mem_to_mem, const struct videomode *vm) { int r; u32 l; @@ -2757,7 +2762,7 @@ static void dispc_lcd_enable_signal_polarity(bool act_high) REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29); } -void dispc_lcd_enable_signal(bool enable) +void dispc_lcd_enable_signal(struct dispc_device *dispc, bool enable) { if (!dispc_has_feature(FEAT_LCDENABLESIGNAL)) return; @@ -2765,7 +2770,7 @@ void dispc_lcd_enable_signal(bool enable) REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28); } -void dispc_pck_free_enable(bool enable) +void dispc_pck_free_enable(struct dispc_device *dispc, bool enable) { if (!dispc_has_feature(FEAT_PCKFREEENABLE)) return; @@ -2904,7 +2909,7 @@ static void dispc_mgr_set_lcd_config(struct dispc_device *dispc, dispc_mgr_enable_stallmode(channel, config->stallmode); dispc_mgr_enable_fifohandcheck(channel, config->fifohandcheck); - dispc_mgr_set_clock_div(channel, &config->clock_info); + dispc_mgr_set_clock_div(dispc, channel, &config->clock_info); dispc_mgr_set_tft_data_lines(channel, config->video_port_width); @@ -2941,7 +2946,8 @@ static bool _dispc_mgr_pclk_ok(enum omap_channel channel, return pclk <= dispc.feat->max_tv_pclk; } -bool dispc_mgr_timings_ok(enum omap_channel channel, const struct videomode *vm) +bool dispc_mgr_timings_ok(struct dispc_device *dispc, enum omap_channel channel, + const struct videomode *vm) { if (!_dispc_mgr_size_ok(vm->hactive, vm->vactive)) return false; @@ -3062,7 +3068,7 @@ static void dispc_mgr_set_timings(struct dispc_device *dispc, DSSDBG("channel %d xres %u yres %u\n", channel, t.hactive, t.vactive); - if (!dispc_mgr_timings_ok(channel, &t)) { + if (!dispc_mgr_timings_ok(dispc, channel, &t)) { BUG(); return; } @@ -3195,9 +3201,9 @@ static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) } } -void dispc_set_tv_pclk(unsigned long pclk) +void dispc_set_tv_pclk(struct dispc_device *dispc, unsigned long pclk) { - dispc.tv_pclk_rate = pclk; + dispc->tv_pclk_rate = pclk; } static unsigned long dispc_core_clk_rate(void) @@ -3249,17 +3255,18 @@ static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel chan dispc_mgr_pclk_rate(channel), pcd); } -void dispc_dump_clocks(struct seq_file *s) +void dispc_dump_clocks(struct dispc_device *dispc, struct seq_file *s) { + enum dss_clk_source dispc_clk_src; int lcd; u32 l; - enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(dispc.dss); - if (dispc_runtime_get(&dispc)) + if (dispc_runtime_get(dispc)) return; seq_printf(s, "- DISPC -\n"); + dispc_clk_src = dss_get_dispc_clk_source(dispc->dss); seq_printf(s, "dispc fclk source = %s\n", dss_get_clk_source_name(dispc_clk_src)); @@ -3281,7 +3288,7 @@ void dispc_dump_clocks(struct seq_file *s) if (dispc_has_feature(FEAT_MGR_LCD3)) dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3); - dispc_runtime_put(&dispc); + dispc_runtime_put(dispc); } static int dispc_dump_regs(struct seq_file *s, void *p) @@ -3482,8 +3489,9 @@ static int dispc_dump_regs(struct seq_file *s, void *p) } /* calculate clock rates using dividers in cinfo */ -int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, - struct dispc_clock_info *cinfo) +int dispc_calc_clock_rates(struct dispc_device *dispc, + unsigned long dispc_fclk_rate, + struct dispc_clock_info *cinfo) { if (cinfo->lck_div > 255 || cinfo->lck_div == 0) return -EINVAL; @@ -3496,9 +3504,9 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, return 0; } -bool dispc_div_calc(unsigned long dispc_freq, - unsigned long pck_min, unsigned long pck_max, - dispc_div_calc_func func, void *data) +bool dispc_div_calc(struct dispc_device *dispc, unsigned long dispc_freq, + unsigned long pck_min, unsigned long pck_max, + dispc_div_calc_func func, void *data) { int lckd, lckd_start, lckd_stop; int pckd, pckd_start, pckd_stop; @@ -3514,10 +3522,10 @@ bool dispc_div_calc(unsigned long dispc_freq, min_fck_per_pck = 0; #endif - pckd_hw_min = dispc.feat->min_pcd; + pckd_hw_min = dispc->feat->min_pcd; pckd_hw_max = 255; - lck_max = dss_get_max_fck_rate(dispc.dss); + lck_max = dss_get_max_fck_rate(dispc->dss); pck_min = pck_min ? pck_min : 1; pck_max = pck_max ? pck_max : ULONG_MAX; @@ -3556,8 +3564,9 @@ bool dispc_div_calc(unsigned long dispc_freq, return false; } -void dispc_mgr_set_clock_div(enum omap_channel channel, - const struct dispc_clock_info *cinfo) +void dispc_mgr_set_clock_div(struct dispc_device *dispc, + enum omap_channel channel, + const struct dispc_clock_info *cinfo) { DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); @@ -3565,8 +3574,9 @@ void dispc_mgr_set_clock_div(enum omap_channel channel, dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div); } -int dispc_mgr_get_clock_div(enum omap_channel channel, - struct dispc_clock_info *cinfo) +int dispc_mgr_get_clock_div(struct dispc_device *dispc, + enum omap_channel channel, + struct dispc_clock_info *cinfo) { unsigned long fck; @@ -3604,12 +3614,12 @@ static void dispc_write_irqenable(struct dispc_device *dispc, u32 mask) dispc_read_reg(DISPC_IRQENABLE); } -void dispc_enable_sidle(void) +void dispc_enable_sidle(struct dispc_device *dispc) { REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */ } -void dispc_disable_sidle(void) +void dispc_disable_sidle(struct dispc_device *dispc) { REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ } @@ -4482,7 +4492,7 @@ static void dispc_errata_i734_wa(void) /* Set up and enable display manager for LCD1 */ dispc_mgr_setup(&dispc, OMAP_DSS_CHANNEL_LCD, &i734.mgri); - dispc_calc_clock_rates(dss_get_dispc_clk_rate(dispc.dss), + dispc_calc_clock_rates(&dispc, dss_get_dispc_clk_rate(dispc.dss), &lcd_conf.clock_info); dispc_mgr_set_lcd_config(&dispc, OMAP_DSS_CHANNEL_LCD, &lcd_conf); dispc_mgr_set_timings(&dispc, OMAP_DSS_CHANNEL_LCD, &i734.vm); diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index d524094b8394..fb1c27f69e3a 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -191,8 +191,9 @@ static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc, ctx->pll_cinfo.mX[ctx->clkout_idx] = m_dispc; ctx->pll_cinfo.clkout[ctx->clkout_idx] = dispc; - return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max, - dpi_calc_dispc_cb, ctx); + return dispc_div_calc(ctx->pll->dss->dispc, dispc, + ctx->pck_min, ctx->pck_max, + dpi_calc_dispc_cb, ctx); } @@ -218,8 +219,9 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data) ctx->fck = fck; - return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max, - dpi_calc_dispc_cb, ctx); + return dispc_div_calc(ctx->pll->dss->dispc, fck, + ctx->pck_min, ctx->pck_max, + dpi_calc_dispc_cb, ctx); } static bool dpi_pll_clk_calc(struct dpi_data *dpi, unsigned long pck, @@ -514,7 +516,7 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, if (vm->hactive % 8 != 0) return -EINVAL; - if (!dispc_mgr_timings_ok(channel, vm)) + if (!dispc_mgr_timings_ok(dpi->dss->dispc, channel, vm)) return -EINVAL; if (vm->pixelclock == 0) diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index c07326a46c01..d4a680629825 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -1394,18 +1394,18 @@ static int dsi_pll_enable(struct dss_pll *pll) } /* XXX PLL does not come out of reset without this... */ - dispc_pck_free_enable(1); + dispc_pck_free_enable(dsi->dss->dispc, 1); if (!wait_for_bit_change(dsi, DSI_PLL_STATUS, 0, 1)) { DSSERR("PLL not coming out of reset.\n"); r = -ENODEV; - dispc_pck_free_enable(0); + dispc_pck_free_enable(dsi->dss->dispc, 0); goto err1; } /* XXX ... but if left on, we get problems when planes do not * fill the whole display. No idea about this */ - dispc_pck_free_enable(0); + dispc_pck_free_enable(dsi->dss->dispc, 0); r = dsi_pll_power(dsi, DSI_PLL_POWER_ON_ALL); @@ -3972,7 +3972,7 @@ static void dsi_update_screen_dispc(struct dsi_data *dsi) * the same goes for any DSS interrupts, but for some reason I have not * seen the problem anywhere else than here. */ - dispc_disable_sidle(); + dispc_disable_sidle(dsi->dss->dispc); dsi_perf_mark_start(dsi); @@ -4007,7 +4007,7 @@ static void dsi_te_timeout(struct timer_list *unused) static void dsi_handle_framedone(struct dsi_data *dsi, int error) { /* SIDLEMODE back to smart-idle */ - dispc_enable_sidle(); + dispc_enable_sidle(dsi->dss->dispc); if (dsi->te_enabled) { /* enable LP_RX_TO again after the TE */ @@ -4088,7 +4088,7 @@ static int dsi_configure_dispc_clocks(struct dsi_data *dsi) dispc_cinfo.lck_div = dsi->user_dispc_cinfo.lck_div; dispc_cinfo.pck_div = dsi->user_dispc_cinfo.pck_div; - r = dispc_calc_clock_rates(fck, &dispc_cinfo); + r = dispc_calc_clock_rates(dsi->dss->dispc, fck, &dispc_cinfo); if (r) { DSSERR("Failed to calc dispc clocks\n"); return r; @@ -4439,8 +4439,9 @@ static bool dsi_cm_calc_hsdiv_cb(int m_dispc, unsigned long dispc, ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc; ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc; - return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max, - dsi_cm_calc_dispc_cb, ctx); + return dispc_div_calc(ctx->dsi->dss->dispc, dispc, + ctx->req_pck_min, ctx->req_pck_max, + dsi_cm_calc_dispc_cb, ctx); } static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint, @@ -4739,8 +4740,9 @@ static bool dsi_vm_calc_hsdiv_cb(int m_dispc, unsigned long dispc, else pck_max = ctx->req_pck_max; - return dispc_div_calc(dispc, ctx->req_pck_min, pck_max, - dsi_vm_calc_dispc_cb, ctx); + return dispc_div_calc(ctx->dsi->dss->dispc, dispc, + ctx->req_pck_min, pck_max, + dsi_vm_calc_dispc_cb, ctx); } static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint, diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index ca2efb937d42..4a08bd1fc522 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -274,7 +274,7 @@ int dss_sdi_enable(struct dss_device *dss) { unsigned long timeout; - dispc_pck_free_enable(1); + dispc_pck_free_enable(dss->dispc, 1); /* Reset SDI PLL */ REG_FLD_MOD(dss, DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */ @@ -304,7 +304,7 @@ int dss_sdi_enable(struct dss_device *dss) } } - dispc_lcd_enable_signal(1); + dispc_lcd_enable_signal(dss->dispc, 1); /* Waiting for SDI reset to complete */ timeout = jiffies + msecs_to_jiffies(500); @@ -318,21 +318,21 @@ int dss_sdi_enable(struct dss_device *dss) return 0; err2: - dispc_lcd_enable_signal(0); + dispc_lcd_enable_signal(dss->dispc, 0); err1: /* Reset SDI PLL */ REG_FLD_MOD(dss, DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ - dispc_pck_free_enable(0); + dispc_pck_free_enable(dss->dispc, 0); return -ETIMEDOUT; } void dss_sdi_disable(struct dss_device *dss) { - dispc_lcd_enable_signal(0); + dispc_lcd_enable_signal(dss->dispc, 0); - dispc_pck_free_enable(0); + dispc_pck_free_enable(dss->dispc, 0); /* Reset SDI PLL */ REG_FLD_MOD(dss, DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ @@ -894,7 +894,7 @@ static int dss_debug_dump_clocks(struct seq_file *s, void *p) struct dss_device *dss = s->private; dss_dump_clocks(dss, s); - dispc_dump_clocks(s); + dispc_dump_clocks(dss->dispc, s); #ifdef CONFIG_OMAP2_DSS_DSI dsi_dump_clocks(s); #endif diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index f3acfd62031c..6f6fd3d1b159 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -407,47 +407,55 @@ static inline void dpi_uninit_port(struct device_node *port) #endif /* DISPC */ -void dispc_dump_clocks(struct seq_file *s); +void dispc_dump_clocks(struct dispc_device *dispc, struct seq_file *s); int dispc_runtime_get(struct dispc_device *dispc); void dispc_runtime_put(struct dispc_device *dispc); -void dispc_enable_sidle(void); -void dispc_disable_sidle(void); +void dispc_enable_sidle(struct dispc_device *dispc); +void dispc_disable_sidle(struct dispc_device *dispc); -void dispc_lcd_enable_signal(bool enable); -void dispc_pck_free_enable(bool enable); -void dispc_enable_fifomerge(bool enable); +void dispc_lcd_enable_signal(struct dispc_device *dispc, bool enable); +void dispc_pck_free_enable(struct dispc_device *dispc, bool enable); +void dispc_enable_fifomerge(struct dispc_device *dispc, bool enable); typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck, unsigned long pck, void *data); -bool dispc_div_calc(unsigned long dispc, - unsigned long pck_min, unsigned long pck_max, - dispc_div_calc_func func, void *data); - -bool dispc_mgr_timings_ok(enum omap_channel channel, const struct videomode *vm); -int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, - struct dispc_clock_info *cinfo); - - -void dispc_ovl_set_fifo_threshold(enum omap_plane_id plane, u32 low, - u32 high); -void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane, - u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, - bool manual_update); - -void dispc_mgr_set_clock_div(enum omap_channel channel, - const struct dispc_clock_info *cinfo); -int dispc_mgr_get_clock_div(enum omap_channel channel, - struct dispc_clock_info *cinfo); -void dispc_set_tv_pclk(unsigned long pclk); - -u32 dispc_wb_get_framedone_irq(void); -bool dispc_wb_go_busy(void); -void dispc_wb_go(void); -void dispc_wb_set_channel_in(enum dss_writeback_channel channel); -int dispc_wb_setup(const struct omap_dss_writeback_info *wi, - bool mem_to_mem, const struct videomode *vm); +bool dispc_div_calc(struct dispc_device *dispc, unsigned long dispc_freq, + unsigned long pck_min, unsigned long pck_max, + dispc_div_calc_func func, void *data); + +bool dispc_mgr_timings_ok(struct dispc_device *dispc, + enum omap_channel channel, + const struct videomode *vm); +int dispc_calc_clock_rates(struct dispc_device *dispc, + unsigned long dispc_fclk_rate, + struct dispc_clock_info *cinfo); + + +void dispc_ovl_set_fifo_threshold(struct dispc_device *dispc, + enum omap_plane_id plane, u32 low, u32 high); +void dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc, + enum omap_plane_id plane, + u32 *fifo_low, u32 *fifo_high, + bool use_fifomerge, bool manual_update); + +void dispc_mgr_set_clock_div(struct dispc_device *dispc, + enum omap_channel channel, + const struct dispc_clock_info *cinfo); +int dispc_mgr_get_clock_div(struct dispc_device *dispc, + enum omap_channel channel, + struct dispc_clock_info *cinfo); +void dispc_set_tv_pclk(struct dispc_device *dispc, unsigned long pclk); + +u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc); +bool dispc_wb_go_busy(struct dispc_device *dispc); +void dispc_wb_go(struct dispc_device *dispc); +void dispc_wb_set_channel_in(struct dispc_device *dispc, + enum dss_writeback_channel channel); +int dispc_wb_setup(struct dispc_device *dispc, + const struct omap_dss_writeback_info *wi, + bool mem_to_mem, const struct videomode *vm); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS static inline void dss_collect_irq_stats(u32 irqstatus, unsigned int *irq_arr) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 5c55fa3f593a..815865c09ac1 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -276,7 +276,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev) static int hdmi_display_check_timing(struct omap_dss_device *dssdev, struct videomode *vm) { - if (!dispc_mgr_timings_ok(dssdev->dispc_channel, vm)) + if (!dispc_mgr_timings_ok(hdmi.dss->dispc, dssdev->dispc_channel, vm)) return -EINVAL; return 0; @@ -289,7 +289,7 @@ static void hdmi_display_set_timing(struct omap_dss_device *dssdev, hdmi.cfg.vm = *vm; - dispc_set_tv_pclk(vm->pixelclock); + dispc_set_tv_pclk(hdmi.dss->dispc, vm->pixelclock); mutex_unlock(&hdmi.lock); } diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index e896f63480f1..a83d70144f85 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -272,7 +272,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev) static int hdmi_display_check_timing(struct omap_dss_device *dssdev, struct videomode *vm) { - if (!dispc_mgr_timings_ok(dssdev->dispc_channel, vm)) + if (!dispc_mgr_timings_ok(hdmi.dss->dispc, dssdev->dispc_channel, vm)) return -EINVAL; return 0; @@ -285,7 +285,7 @@ static void hdmi_display_set_timing(struct omap_dss_device *dssdev, hdmi.cfg.vm = *vm; - dispc_set_tv_pclk(vm->pixelclock); + dispc_set_tv_pclk(hdmi.dss->dispc, vm->pixelclock); mutex_unlock(&hdmi.lock); } diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index b1d0e706a1ec..9c2ed56a70c1 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -71,8 +71,9 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data) ctx->fck = fck; - return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max, - dpi_calc_dispc_cb, ctx); + return dispc_div_calc(sdi.dss->dispc, fck, + ctx->pck_min, ctx->pck_max, + dpi_calc_dispc_cb, ctx); } static int sdi_calc_clock_div(unsigned long pclk, @@ -183,7 +184,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) * need to care about the shadow register mechanism for pck-free. The * exact reason for this is unknown. */ - dispc_mgr_set_clock_div(sdi.output.dispc_channel, + dispc_mgr_set_clock_div(sdi.dss->dispc, sdi.output.dispc_channel, &sdi.mgr_config.clock_info); dss_sdi_init(sdi.dss, sdi.datapairs); @@ -238,7 +239,7 @@ static int sdi_check_timings(struct omap_dss_device *dssdev, { enum omap_channel channel = dssdev->dispc_channel; - if (!dispc_mgr_timings_ok(channel, vm)) + if (!dispc_mgr_timings_ok(sdi.dss->dispc, channel, vm)) return -EINVAL; if (vm->pixelclock == 0) diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 546271389189..12a0ac4e1eb1 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -586,7 +586,7 @@ static void venc_set_timings(struct omap_dss_device *dssdev, venc.vm = actual_vm; - dispc_set_tv_pclk(13500000); + dispc_set_tv_pclk(venc.dss->dispc, 13500000); mutex_unlock(&venc.venc_lock); } -- cgit v1.2.3 From 1f6b6b6267ebe6f36f3640bccb93d54e9699c131 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:44 +0200 Subject: drm: omapdrm: dispc: Allocate the dispc private data structure dynamically The dispc private data structure is currently stored as a global variable. While no platform with multiple DISPC currently exists nor is planned, this doesn't comply with the kernel device model and should thus be fixed. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/dispc.c | 1934 +++++++++++++++++++---------------- 1 file changed, 1039 insertions(+), 895 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index bd014bfc1cb6..ce470b51e326 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -47,6 +47,8 @@ #include "dss.h" #include "dispc.h" +struct dispc_device; + /* DISPC */ #define DISPC_SZ_REGS SZ_4K @@ -56,11 +58,12 @@ enum omap_burst_size { BURST_SIZE_X8 = 2, }; -#define REG_GET(idx, start, end) \ - FLD_GET(dispc_read_reg(idx), start, end) +#define REG_GET(dispc, idx, start, end) \ + FLD_GET(dispc_read_reg(dispc, idx), start, end) -#define REG_FLD_MOD(idx, val, start, end) \ - dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end)) +#define REG_FLD_MOD(dispc, idx, val, start, end) \ + dispc_write_reg(dispc, idx, \ + FLD_MOD(dispc_read_reg(dispc, idx), val, start, end)) /* DISPC has feature id */ enum dispc_feature_id { @@ -105,7 +108,8 @@ struct dispc_features { unsigned int max_downscale; unsigned int max_line_width; unsigned int min_pcd; - int (*calc_scaling) (unsigned long pclk, unsigned long lclk, + int (*calc_scaling)(struct dispc_device *dispc, + unsigned long pclk, unsigned long lclk, const struct videomode *vm, u16 width, u16 height, u16 out_width, u16 out_height, u32 fourcc, bool *five_taps, @@ -196,8 +200,6 @@ struct dispc_device { spinlock_t control_lock; }; -static struct dispc_device dispc; - enum omap_color_component { /* used for all color formats for OMAP3 and earlier * and for RGB and Y color component on OMAP4 @@ -355,45 +357,52 @@ struct color_conv_coef { int full_range; }; -static unsigned long dispc_fclk_rate(void); -static unsigned long dispc_core_clk_rate(void); -static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel); -static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel); +static unsigned long dispc_fclk_rate(struct dispc_device *dispc); +static unsigned long dispc_core_clk_rate(struct dispc_device *dispc); +static unsigned long dispc_mgr_lclk_rate(struct dispc_device *dispc, + enum omap_channel channel); +static unsigned long dispc_mgr_pclk_rate(struct dispc_device *dispc, + enum omap_channel channel); -static unsigned long dispc_plane_pclk_rate(enum omap_plane_id plane); -static unsigned long dispc_plane_lclk_rate(enum omap_plane_id plane); +static unsigned long dispc_plane_pclk_rate(struct dispc_device *dispc, + enum omap_plane_id plane); +static unsigned long dispc_plane_lclk_rate(struct dispc_device *dispc, + enum omap_plane_id plane); static void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask); -static inline void dispc_write_reg(const u16 idx, u32 val) +static inline void dispc_write_reg(struct dispc_device *dispc, u16 idx, u32 val) { - __raw_writel(val, dispc.base + idx); + __raw_writel(val, dispc->base + idx); } -static inline u32 dispc_read_reg(const u16 idx) +static inline u32 dispc_read_reg(struct dispc_device *dispc, u16 idx) { - return __raw_readl(dispc.base + idx); + return __raw_readl(dispc->base + idx); } -static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld) +static u32 mgr_fld_read(struct dispc_device *dispc, enum omap_channel channel, + enum mgr_reg_fields regfld) { const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld]; - return REG_GET(rfld.reg, rfld.high, rfld.low); + + return REG_GET(dispc, rfld.reg, rfld.high, rfld.low); } -static void mgr_fld_write(enum omap_channel channel, - enum mgr_reg_fields regfld, int val) { +static void mgr_fld_write(struct dispc_device *dispc, enum omap_channel channel, + enum mgr_reg_fields regfld, int val) +{ const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld]; const bool need_lock = rfld.reg == DISPC_CONTROL || rfld.reg == DISPC_CONFIG; unsigned long flags; if (need_lock) - spin_lock_irqsave(&dispc.control_lock, flags); + spin_lock_irqsave(&dispc->control_lock, flags); - REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low); + REG_FLD_MOD(dispc, rfld.reg, val, rfld.high, rfld.low); if (need_lock) - spin_unlock_irqrestore(&dispc.control_lock, flags); + spin_unlock_irqrestore(&dispc->control_lock, flags); } static int dispc_get_num_ovls(struct dispc_device *dispc) @@ -406,255 +415,257 @@ static int dispc_get_num_mgrs(struct dispc_device *dispc) return dispc->feat->num_mgrs; } -static void dispc_get_reg_field(enum dispc_feat_reg_field id, +static void dispc_get_reg_field(struct dispc_device *dispc, + enum dispc_feat_reg_field id, u8 *start, u8 *end) { - if (id >= dispc.feat->num_reg_fields) + if (id >= dispc->feat->num_reg_fields) BUG(); - *start = dispc.feat->reg_fields[id].start; - *end = dispc.feat->reg_fields[id].end; + *start = dispc->feat->reg_fields[id].start; + *end = dispc->feat->reg_fields[id].end; } -static bool dispc_has_feature(enum dispc_feature_id id) +static bool dispc_has_feature(struct dispc_device *dispc, + enum dispc_feature_id id) { unsigned int i; - for (i = 0; i < dispc.feat->num_features; i++) { - if (dispc.feat->features[i] == id) + for (i = 0; i < dispc->feat->num_features; i++) { + if (dispc->feat->features[i] == id) return true; } return false; } -#define SR(reg) \ - dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg) -#define RR(reg) \ - dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)]) +#define SR(dispc, reg) \ + dispc->ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(dispc, DISPC_##reg) +#define RR(dispc, reg) \ + dispc_write_reg(dispc, DISPC_##reg, dispc->ctx[DISPC_##reg / sizeof(u32)]) -static void dispc_save_context(void) +static void dispc_save_context(struct dispc_device *dispc) { int i, j; DSSDBG("dispc_save_context\n"); - SR(IRQENABLE); - SR(CONTROL); - SR(CONFIG); - SR(LINE_NUMBER); - if (dispc_has_feature(FEAT_ALPHA_FIXED_ZORDER) || - dispc_has_feature(FEAT_ALPHA_FREE_ZORDER)) - SR(GLOBAL_ALPHA); - if (dispc_has_feature(FEAT_MGR_LCD2)) { - SR(CONTROL2); - SR(CONFIG2); + SR(dispc, IRQENABLE); + SR(dispc, CONTROL); + SR(dispc, CONFIG); + SR(dispc, LINE_NUMBER); + if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) || + dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER)) + SR(dispc, GLOBAL_ALPHA); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) { + SR(dispc, CONTROL2); + SR(dispc, CONFIG2); } - if (dispc_has_feature(FEAT_MGR_LCD3)) { - SR(CONTROL3); - SR(CONFIG3); + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) { + SR(dispc, CONTROL3); + SR(dispc, CONFIG3); } - for (i = 0; i < dispc_get_num_mgrs(&dispc); i++) { - SR(DEFAULT_COLOR(i)); - SR(TRANS_COLOR(i)); - SR(SIZE_MGR(i)); + for (i = 0; i < dispc_get_num_mgrs(dispc); i++) { + SR(dispc, DEFAULT_COLOR(i)); + SR(dispc, TRANS_COLOR(i)); + SR(dispc, SIZE_MGR(i)); if (i == OMAP_DSS_CHANNEL_DIGIT) continue; - SR(TIMING_H(i)); - SR(TIMING_V(i)); - SR(POL_FREQ(i)); - SR(DIVISORo(i)); - - SR(DATA_CYCLE1(i)); - SR(DATA_CYCLE2(i)); - SR(DATA_CYCLE3(i)); - - if (dispc_has_feature(FEAT_CPR)) { - SR(CPR_COEF_R(i)); - SR(CPR_COEF_G(i)); - SR(CPR_COEF_B(i)); + SR(dispc, TIMING_H(i)); + SR(dispc, TIMING_V(i)); + SR(dispc, POL_FREQ(i)); + SR(dispc, DIVISORo(i)); + + SR(dispc, DATA_CYCLE1(i)); + SR(dispc, DATA_CYCLE2(i)); + SR(dispc, DATA_CYCLE3(i)); + + if (dispc_has_feature(dispc, FEAT_CPR)) { + SR(dispc, CPR_COEF_R(i)); + SR(dispc, CPR_COEF_G(i)); + SR(dispc, CPR_COEF_B(i)); } } - for (i = 0; i < dispc_get_num_ovls(&dispc); i++) { - SR(OVL_BA0(i)); - SR(OVL_BA1(i)); - SR(OVL_POSITION(i)); - SR(OVL_SIZE(i)); - SR(OVL_ATTRIBUTES(i)); - SR(OVL_FIFO_THRESHOLD(i)); - SR(OVL_ROW_INC(i)); - SR(OVL_PIXEL_INC(i)); - if (dispc_has_feature(FEAT_PRELOAD)) - SR(OVL_PRELOAD(i)); + for (i = 0; i < dispc_get_num_ovls(dispc); i++) { + SR(dispc, OVL_BA0(i)); + SR(dispc, OVL_BA1(i)); + SR(dispc, OVL_POSITION(i)); + SR(dispc, OVL_SIZE(i)); + SR(dispc, OVL_ATTRIBUTES(i)); + SR(dispc, OVL_FIFO_THRESHOLD(i)); + SR(dispc, OVL_ROW_INC(i)); + SR(dispc, OVL_PIXEL_INC(i)); + if (dispc_has_feature(dispc, FEAT_PRELOAD)) + SR(dispc, OVL_PRELOAD(i)); if (i == OMAP_DSS_GFX) { - SR(OVL_WINDOW_SKIP(i)); - SR(OVL_TABLE_BA(i)); + SR(dispc, OVL_WINDOW_SKIP(i)); + SR(dispc, OVL_TABLE_BA(i)); continue; } - SR(OVL_FIR(i)); - SR(OVL_PICTURE_SIZE(i)); - SR(OVL_ACCU0(i)); - SR(OVL_ACCU1(i)); + SR(dispc, OVL_FIR(i)); + SR(dispc, OVL_PICTURE_SIZE(i)); + SR(dispc, OVL_ACCU0(i)); + SR(dispc, OVL_ACCU1(i)); for (j = 0; j < 8; j++) - SR(OVL_FIR_COEF_H(i, j)); + SR(dispc, OVL_FIR_COEF_H(i, j)); for (j = 0; j < 8; j++) - SR(OVL_FIR_COEF_HV(i, j)); + SR(dispc, OVL_FIR_COEF_HV(i, j)); for (j = 0; j < 5; j++) - SR(OVL_CONV_COEF(i, j)); + SR(dispc, OVL_CONV_COEF(i, j)); - if (dispc_has_feature(FEAT_FIR_COEF_V)) { + if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) { for (j = 0; j < 8; j++) - SR(OVL_FIR_COEF_V(i, j)); + SR(dispc, OVL_FIR_COEF_V(i, j)); } - if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - SR(OVL_BA0_UV(i)); - SR(OVL_BA1_UV(i)); - SR(OVL_FIR2(i)); - SR(OVL_ACCU2_0(i)); - SR(OVL_ACCU2_1(i)); + if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { + SR(dispc, OVL_BA0_UV(i)); + SR(dispc, OVL_BA1_UV(i)); + SR(dispc, OVL_FIR2(i)); + SR(dispc, OVL_ACCU2_0(i)); + SR(dispc, OVL_ACCU2_1(i)); for (j = 0; j < 8; j++) - SR(OVL_FIR_COEF_H2(i, j)); + SR(dispc, OVL_FIR_COEF_H2(i, j)); for (j = 0; j < 8; j++) - SR(OVL_FIR_COEF_HV2(i, j)); + SR(dispc, OVL_FIR_COEF_HV2(i, j)); for (j = 0; j < 8; j++) - SR(OVL_FIR_COEF_V2(i, j)); + SR(dispc, OVL_FIR_COEF_V2(i, j)); } - if (dispc_has_feature(FEAT_ATTR2)) - SR(OVL_ATTRIBUTES2(i)); + if (dispc_has_feature(dispc, FEAT_ATTR2)) + SR(dispc, OVL_ATTRIBUTES2(i)); } - if (dispc_has_feature(FEAT_CORE_CLK_DIV)) - SR(DIVISOR); + if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) + SR(dispc, DIVISOR); - dispc.ctx_valid = true; + dispc->ctx_valid = true; DSSDBG("context saved\n"); } -static void dispc_restore_context(void) +static void dispc_restore_context(struct dispc_device *dispc) { int i, j; DSSDBG("dispc_restore_context\n"); - if (!dispc.ctx_valid) + if (!dispc->ctx_valid) return; - /*RR(IRQENABLE);*/ - /*RR(CONTROL);*/ - RR(CONFIG); - RR(LINE_NUMBER); - if (dispc_has_feature(FEAT_ALPHA_FIXED_ZORDER) || - dispc_has_feature(FEAT_ALPHA_FREE_ZORDER)) - RR(GLOBAL_ALPHA); - if (dispc_has_feature(FEAT_MGR_LCD2)) - RR(CONFIG2); - if (dispc_has_feature(FEAT_MGR_LCD3)) - RR(CONFIG3); - - for (i = 0; i < dispc_get_num_mgrs(&dispc); i++) { - RR(DEFAULT_COLOR(i)); - RR(TRANS_COLOR(i)); - RR(SIZE_MGR(i)); + /*RR(dispc, IRQENABLE);*/ + /*RR(dispc, CONTROL);*/ + RR(dispc, CONFIG); + RR(dispc, LINE_NUMBER); + if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) || + dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER)) + RR(dispc, GLOBAL_ALPHA); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) + RR(dispc, CONFIG2); + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) + RR(dispc, CONFIG3); + + for (i = 0; i < dispc_get_num_mgrs(dispc); i++) { + RR(dispc, DEFAULT_COLOR(i)); + RR(dispc, TRANS_COLOR(i)); + RR(dispc, SIZE_MGR(i)); if (i == OMAP_DSS_CHANNEL_DIGIT) continue; - RR(TIMING_H(i)); - RR(TIMING_V(i)); - RR(POL_FREQ(i)); - RR(DIVISORo(i)); - - RR(DATA_CYCLE1(i)); - RR(DATA_CYCLE2(i)); - RR(DATA_CYCLE3(i)); - - if (dispc_has_feature(FEAT_CPR)) { - RR(CPR_COEF_R(i)); - RR(CPR_COEF_G(i)); - RR(CPR_COEF_B(i)); + RR(dispc, TIMING_H(i)); + RR(dispc, TIMING_V(i)); + RR(dispc, POL_FREQ(i)); + RR(dispc, DIVISORo(i)); + + RR(dispc, DATA_CYCLE1(i)); + RR(dispc, DATA_CYCLE2(i)); + RR(dispc, DATA_CYCLE3(i)); + + if (dispc_has_feature(dispc, FEAT_CPR)) { + RR(dispc, CPR_COEF_R(i)); + RR(dispc, CPR_COEF_G(i)); + RR(dispc, CPR_COEF_B(i)); } } - for (i = 0; i < dispc_get_num_ovls(&dispc); i++) { - RR(OVL_BA0(i)); - RR(OVL_BA1(i)); - RR(OVL_POSITION(i)); - RR(OVL_SIZE(i)); - RR(OVL_ATTRIBUTES(i)); - RR(OVL_FIFO_THRESHOLD(i)); - RR(OVL_ROW_INC(i)); - RR(OVL_PIXEL_INC(i)); - if (dispc_has_feature(FEAT_PRELOAD)) - RR(OVL_PRELOAD(i)); + for (i = 0; i < dispc_get_num_ovls(dispc); i++) { + RR(dispc, OVL_BA0(i)); + RR(dispc, OVL_BA1(i)); + RR(dispc, OVL_POSITION(i)); + RR(dispc, OVL_SIZE(i)); + RR(dispc, OVL_ATTRIBUTES(i)); + RR(dispc, OVL_FIFO_THRESHOLD(i)); + RR(dispc, OVL_ROW_INC(i)); + RR(dispc, OVL_PIXEL_INC(i)); + if (dispc_has_feature(dispc, FEAT_PRELOAD)) + RR(dispc, OVL_PRELOAD(i)); if (i == OMAP_DSS_GFX) { - RR(OVL_WINDOW_SKIP(i)); - RR(OVL_TABLE_BA(i)); + RR(dispc, OVL_WINDOW_SKIP(i)); + RR(dispc, OVL_TABLE_BA(i)); continue; } - RR(OVL_FIR(i)); - RR(OVL_PICTURE_SIZE(i)); - RR(OVL_ACCU0(i)); - RR(OVL_ACCU1(i)); + RR(dispc, OVL_FIR(i)); + RR(dispc, OVL_PICTURE_SIZE(i)); + RR(dispc, OVL_ACCU0(i)); + RR(dispc, OVL_ACCU1(i)); for (j = 0; j < 8; j++) - RR(OVL_FIR_COEF_H(i, j)); + RR(dispc, OVL_FIR_COEF_H(i, j)); for (j = 0; j < 8; j++) - RR(OVL_FIR_COEF_HV(i, j)); + RR(dispc, OVL_FIR_COEF_HV(i, j)); for (j = 0; j < 5; j++) - RR(OVL_CONV_COEF(i, j)); + RR(dispc, OVL_CONV_COEF(i, j)); - if (dispc_has_feature(FEAT_FIR_COEF_V)) { + if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) { for (j = 0; j < 8; j++) - RR(OVL_FIR_COEF_V(i, j)); + RR(dispc, OVL_FIR_COEF_V(i, j)); } - if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - RR(OVL_BA0_UV(i)); - RR(OVL_BA1_UV(i)); - RR(OVL_FIR2(i)); - RR(OVL_ACCU2_0(i)); - RR(OVL_ACCU2_1(i)); + if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { + RR(dispc, OVL_BA0_UV(i)); + RR(dispc, OVL_BA1_UV(i)); + RR(dispc, OVL_FIR2(i)); + RR(dispc, OVL_ACCU2_0(i)); + RR(dispc, OVL_ACCU2_1(i)); for (j = 0; j < 8; j++) - RR(OVL_FIR_COEF_H2(i, j)); + RR(dispc, OVL_FIR_COEF_H2(i, j)); for (j = 0; j < 8; j++) - RR(OVL_FIR_COEF_HV2(i, j)); + RR(dispc, OVL_FIR_COEF_HV2(i, j)); for (j = 0; j < 8; j++) - RR(OVL_FIR_COEF_V2(i, j)); + RR(dispc, OVL_FIR_COEF_V2(i, j)); } - if (dispc_has_feature(FEAT_ATTR2)) - RR(OVL_ATTRIBUTES2(i)); + if (dispc_has_feature(dispc, FEAT_ATTR2)) + RR(dispc, OVL_ATTRIBUTES2(i)); } - if (dispc_has_feature(FEAT_CORE_CLK_DIV)) - RR(DIVISOR); + if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) + RR(dispc, DIVISOR); /* enable last, because LCD & DIGIT enable are here */ - RR(CONTROL); - if (dispc_has_feature(FEAT_MGR_LCD2)) - RR(CONTROL2); - if (dispc_has_feature(FEAT_MGR_LCD3)) - RR(CONTROL3); + RR(dispc, CONTROL); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) + RR(dispc, CONTROL2); + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) + RR(dispc, CONTROL3); /* clear spurious SYNC_LOST_DIGIT interrupts */ - dispc_clear_irqstatus(&dispc, DISPC_IRQ_SYNC_LOST_DIGIT); + dispc_clear_irqstatus(dispc, DISPC_IRQ_SYNC_LOST_DIGIT); /* * enable last so IRQs won't trigger before * the context is fully restored */ - RR(IRQENABLE); + RR(dispc, IRQENABLE); DSSDBG("context restored\n"); } @@ -712,21 +723,21 @@ u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc) static void dispc_mgr_enable(struct dispc_device *dispc, enum omap_channel channel, bool enable) { - mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_ENABLE, enable); /* flush posted write */ - mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); + mgr_fld_read(dispc, channel, DISPC_MGR_FLD_ENABLE); } static bool dispc_mgr_is_enabled(struct dispc_device *dispc, enum omap_channel channel) { - return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); + return !!mgr_fld_read(dispc, channel, DISPC_MGR_FLD_ENABLE); } static bool dispc_mgr_go_busy(struct dispc_device *dispc, enum omap_channel channel) { - return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; + return mgr_fld_read(dispc, channel, DISPC_MGR_FLD_GO) == 1; } static void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel) @@ -736,12 +747,12 @@ static void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel) DSSDBG("GO %s\n", mgr_desc[channel].name); - mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_GO, 1); } bool dispc_wb_go_busy(struct dispc_device *dispc) { - return REG_GET(DISPC_CONTROL2, 6, 6) == 1; + return REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1; } void dispc_wb_go(struct dispc_device *dispc) @@ -749,65 +760,72 @@ void dispc_wb_go(struct dispc_device *dispc) enum omap_plane_id plane = OMAP_DSS_WB; bool enable, go; - enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1; + enable = REG_GET(dispc, DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1; if (!enable) return; - go = REG_GET(DISPC_CONTROL2, 6, 6) == 1; + go = REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1; if (go) { DSSERR("GO bit not down for WB\n"); return; } - REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6); + REG_FLD_MOD(dispc, DISPC_CONTROL2, 1, 6, 6); } -static void dispc_ovl_write_firh_reg(enum omap_plane_id plane, int reg, +static void dispc_ovl_write_firh_reg(struct dispc_device *dispc, + enum omap_plane_id plane, int reg, u32 value) { - dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); + dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_H(plane, reg), value); } -static void dispc_ovl_write_firhv_reg(enum omap_plane_id plane, int reg, +static void dispc_ovl_write_firhv_reg(struct dispc_device *dispc, + enum omap_plane_id plane, int reg, u32 value) { - dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value); + dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_HV(plane, reg), value); } -static void dispc_ovl_write_firv_reg(enum omap_plane_id plane, int reg, +static void dispc_ovl_write_firv_reg(struct dispc_device *dispc, + enum omap_plane_id plane, int reg, u32 value) { - dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value); + dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_V(plane, reg), value); } -static void dispc_ovl_write_firh2_reg(enum omap_plane_id plane, int reg, +static void dispc_ovl_write_firh2_reg(struct dispc_device *dispc, + enum omap_plane_id plane, int reg, u32 value) { BUG_ON(plane == OMAP_DSS_GFX); - dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value); + dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_H2(plane, reg), value); } -static void dispc_ovl_write_firhv2_reg(enum omap_plane_id plane, int reg, - u32 value) +static void dispc_ovl_write_firhv2_reg(struct dispc_device *dispc, + enum omap_plane_id plane, int reg, + u32 value) { BUG_ON(plane == OMAP_DSS_GFX); - dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value); + dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_HV2(plane, reg), value); } -static void dispc_ovl_write_firv2_reg(enum omap_plane_id plane, int reg, +static void dispc_ovl_write_firv2_reg(struct dispc_device *dispc, + enum omap_plane_id plane, int reg, u32 value) { BUG_ON(plane == OMAP_DSS_GFX); - dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); + dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_V2(plane, reg), value); } -static void dispc_ovl_set_scale_coef(enum omap_plane_id plane, int fir_hinc, - int fir_vinc, int five_taps, - enum omap_color_component color_comp) +static void dispc_ovl_set_scale_coef(struct dispc_device *dispc, + enum omap_plane_id plane, int fir_hinc, + int fir_vinc, int five_taps, + enum omap_color_component color_comp) { const struct dispc_coef *h_coef, *v_coef; int i; @@ -828,11 +846,11 @@ static void dispc_ovl_set_scale_coef(enum omap_plane_id plane, int fir_hinc, | FLD_VAL(v_coef[i].hc3_vc2, 31, 24); if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { - dispc_ovl_write_firh_reg(plane, i, h); - dispc_ovl_write_firhv_reg(plane, i, hv); + dispc_ovl_write_firh_reg(dispc, plane, i, h); + dispc_ovl_write_firhv_reg(dispc, plane, i, hv); } else { - dispc_ovl_write_firh2_reg(plane, i, h); - dispc_ovl_write_firhv2_reg(plane, i, hv); + dispc_ovl_write_firh2_reg(dispc, plane, i, h); + dispc_ovl_write_firhv2_reg(dispc, plane, i, hv); } } @@ -843,34 +861,35 @@ static void dispc_ovl_set_scale_coef(enum omap_plane_id plane, int fir_hinc, v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0) | FLD_VAL(v_coef[i].hc4_vc22, 15, 8); if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) - dispc_ovl_write_firv_reg(plane, i, v); + dispc_ovl_write_firv_reg(dispc, plane, i, v); else - dispc_ovl_write_firv2_reg(plane, i, v); + dispc_ovl_write_firv2_reg(dispc, plane, i, v); } } } -static void dispc_ovl_write_color_conv_coef(enum omap_plane_id plane, - const struct color_conv_coef *ct) +static void dispc_ovl_write_color_conv_coef(struct dispc_device *dispc, + enum omap_plane_id plane, + const struct color_conv_coef *ct) { #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) - dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry)); - dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb)); - dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr)); - dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by)); - dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb)); - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); #undef CVAL } -static void dispc_setup_color_conv_coef(void) +static void dispc_setup_color_conv_coef(struct dispc_device *dispc) { int i; - int num_ovl = dispc_get_num_ovls(&dispc); + int num_ovl = dispc_get_num_ovls(dispc); const struct color_conv_coef ctbl_bt601_5_ovl = { /* YUV -> RGB */ 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, @@ -881,34 +900,40 @@ static void dispc_setup_color_conv_coef(void) }; for (i = 1; i < num_ovl; i++) - dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl); + dispc_ovl_write_color_conv_coef(dispc, i, &ctbl_bt601_5_ovl); - if (dispc.feat->has_writeback) - dispc_ovl_write_color_conv_coef(OMAP_DSS_WB, &ctbl_bt601_5_wb); + if (dispc->feat->has_writeback) + dispc_ovl_write_color_conv_coef(dispc, OMAP_DSS_WB, + &ctbl_bt601_5_wb); } -static void dispc_ovl_set_ba0(enum omap_plane_id plane, u32 paddr) +static void dispc_ovl_set_ba0(struct dispc_device *dispc, + enum omap_plane_id plane, u32 paddr) { - dispc_write_reg(DISPC_OVL_BA0(plane), paddr); + dispc_write_reg(dispc, DISPC_OVL_BA0(plane), paddr); } -static void dispc_ovl_set_ba1(enum omap_plane_id plane, u32 paddr) +static void dispc_ovl_set_ba1(struct dispc_device *dispc, + enum omap_plane_id plane, u32 paddr) { - dispc_write_reg(DISPC_OVL_BA1(plane), paddr); + dispc_write_reg(dispc, DISPC_OVL_BA1(plane), paddr); } -static void dispc_ovl_set_ba0_uv(enum omap_plane_id plane, u32 paddr) +static void dispc_ovl_set_ba0_uv(struct dispc_device *dispc, + enum omap_plane_id plane, u32 paddr) { - dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr); + dispc_write_reg(dispc, DISPC_OVL_BA0_UV(plane), paddr); } -static void dispc_ovl_set_ba1_uv(enum omap_plane_id plane, u32 paddr) +static void dispc_ovl_set_ba1_uv(struct dispc_device *dispc, + enum omap_plane_id plane, u32 paddr) { - dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); + dispc_write_reg(dispc, DISPC_OVL_BA1_UV(plane), paddr); } -static void dispc_ovl_set_pos(enum omap_plane_id plane, - enum omap_overlay_caps caps, int x, int y) +static void dispc_ovl_set_pos(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_overlay_caps caps, int x, int y) { u32 val; @@ -917,22 +942,24 @@ static void dispc_ovl_set_pos(enum omap_plane_id plane, val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); - dispc_write_reg(DISPC_OVL_POSITION(plane), val); + dispc_write_reg(dispc, DISPC_OVL_POSITION(plane), val); } -static void dispc_ovl_set_input_size(enum omap_plane_id plane, int width, - int height) +static void dispc_ovl_set_input_size(struct dispc_device *dispc, + enum omap_plane_id plane, int width, + int height) { u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB) - dispc_write_reg(DISPC_OVL_SIZE(plane), val); + dispc_write_reg(dispc, DISPC_OVL_SIZE(plane), val); else - dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); + dispc_write_reg(dispc, DISPC_OVL_PICTURE_SIZE(plane), val); } -static void dispc_ovl_set_output_size(enum omap_plane_id plane, int width, - int height) +static void dispc_ovl_set_output_size(struct dispc_device *dispc, + enum omap_plane_id plane, int width, + int height) { u32 val; @@ -941,42 +968,47 @@ static void dispc_ovl_set_output_size(enum omap_plane_id plane, int width, val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); if (plane == OMAP_DSS_WB) - dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); + dispc_write_reg(dispc, DISPC_OVL_PICTURE_SIZE(plane), val); else - dispc_write_reg(DISPC_OVL_SIZE(plane), val); + dispc_write_reg(dispc, DISPC_OVL_SIZE(plane), val); } -static void dispc_ovl_set_zorder(enum omap_plane_id plane, - enum omap_overlay_caps caps, u8 zorder) +static void dispc_ovl_set_zorder(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_overlay_caps caps, u8 zorder) { if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) return; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); } -static void dispc_ovl_enable_zorder_planes(void) +static void dispc_ovl_enable_zorder_planes(struct dispc_device *dispc) { int i; - if (!dispc_has_feature(FEAT_ALPHA_FREE_ZORDER)) + if (!dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER)) return; - for (i = 0; i < dispc_get_num_ovls(&dispc); i++) - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); + for (i = 0; i < dispc_get_num_ovls(dispc); i++) + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); } -static void dispc_ovl_set_pre_mult_alpha(enum omap_plane_id plane, - enum omap_overlay_caps caps, bool enable) +static void dispc_ovl_set_pre_mult_alpha(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_overlay_caps caps, + bool enable) { if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) return; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); } -static void dispc_ovl_setup_global_alpha(enum omap_plane_id plane, - enum omap_overlay_caps caps, u8 global_alpha) +static void dispc_ovl_setup_global_alpha(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_overlay_caps caps, + u8 global_alpha) { static const unsigned int shifts[] = { 0, 8, 16, 24, }; int shift; @@ -985,20 +1017,23 @@ static void dispc_ovl_setup_global_alpha(enum omap_plane_id plane, return; shift = shifts[plane]; - REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift); + REG_FLD_MOD(dispc, DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift); } -static void dispc_ovl_set_pix_inc(enum omap_plane_id plane, s32 inc) +static void dispc_ovl_set_pix_inc(struct dispc_device *dispc, + enum omap_plane_id plane, s32 inc) { - dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc); + dispc_write_reg(dispc, DISPC_OVL_PIXEL_INC(plane), inc); } -static void dispc_ovl_set_row_inc(enum omap_plane_id plane, s32 inc) +static void dispc_ovl_set_row_inc(struct dispc_device *dispc, + enum omap_plane_id plane, s32 inc) { - dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc); + dispc_write_reg(dispc, DISPC_OVL_ROW_INC(plane), inc); } -static void dispc_ovl_set_color_mode(enum omap_plane_id plane, u32 fourcc) +static void dispc_ovl_set_color_mode(struct dispc_device *dispc, + enum omap_plane_id plane, u32 fourcc) { u32 m = 0; if (plane != OMAP_DSS_GFX) { @@ -1067,7 +1102,7 @@ static void dispc_ovl_set_color_mode(enum omap_plane_id plane, u32 fourcc) } } - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); } static bool format_is_yuv(u32 fourcc) @@ -1082,19 +1117,21 @@ static bool format_is_yuv(u32 fourcc) } } -static void dispc_ovl_configure_burst_type(enum omap_plane_id plane, - enum omap_dss_rotation_type rotation_type) +static void dispc_ovl_configure_burst_type(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_dss_rotation_type rotation) { - if (dispc_has_feature(FEAT_BURST_2D) == 0) + if (dispc_has_feature(dispc, FEAT_BURST_2D) == 0) return; - if (rotation_type == OMAP_DSS_ROT_TILER) - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29); + if (rotation == OMAP_DSS_ROT_TILER) + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29); else - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29); } -static void dispc_ovl_set_channel_out(enum omap_plane_id plane, +static void dispc_ovl_set_channel_out(struct dispc_device *dispc, + enum omap_plane_id plane, enum omap_channel channel) { int shift; @@ -1115,8 +1152,8 @@ static void dispc_ovl_set_channel_out(enum omap_plane_id plane, return; } - val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); - if (dispc_has_feature(FEAT_MGR_LCD2)) { + val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) { switch (channel) { case OMAP_DSS_CHANNEL_LCD: chan = 0; @@ -1131,7 +1168,7 @@ static void dispc_ovl_set_channel_out(enum omap_plane_id plane, chan2 = 1; break; case OMAP_DSS_CHANNEL_LCD3: - if (dispc_has_feature(FEAT_MGR_LCD3)) { + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) { chan = 0; chan2 = 2; } else { @@ -1153,10 +1190,11 @@ static void dispc_ovl_set_channel_out(enum omap_plane_id plane, } else { val = FLD_MOD(val, channel, shift, shift); } - dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); + dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), val); } -static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane_id plane) +static enum omap_channel dispc_ovl_get_channel_out(struct dispc_device *dispc, + enum omap_plane_id plane) { int shift; u32 val; @@ -1175,12 +1213,12 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane_id plane) return 0; } - val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); if (FLD_GET(val, shift, shift) == 1) return OMAP_DSS_CHANNEL_DIGIT; - if (!dispc_has_feature(FEAT_MGR_LCD2)) + if (!dispc_has_feature(dispc, FEAT_MGR_LCD2)) return OMAP_DSS_CHANNEL_LCD; switch (FLD_GET(val, 31, 30)) { @@ -1201,43 +1239,47 @@ void dispc_wb_set_channel_in(struct dispc_device *dispc, { enum omap_plane_id plane = OMAP_DSS_WB; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16); } -static void dispc_ovl_set_burst_size(enum omap_plane_id plane, - enum omap_burst_size burst_size) +static void dispc_ovl_set_burst_size(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_burst_size burst_size) { static const unsigned int shifts[] = { 6, 14, 14, 14, 14, }; int shift; shift = shifts[plane]; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), burst_size, + shift + 1, shift); } -static void dispc_configure_burst_sizes(void) +static void dispc_configure_burst_sizes(struct dispc_device *dispc) { int i; const int burst_size = BURST_SIZE_X8; /* Configure burst size always to maximum size */ - for (i = 0; i < dispc_get_num_ovls(&dispc); ++i) - dispc_ovl_set_burst_size(i, burst_size); - if (dispc.feat->has_writeback) - dispc_ovl_set_burst_size(OMAP_DSS_WB, burst_size); + for (i = 0; i < dispc_get_num_ovls(dispc); ++i) + dispc_ovl_set_burst_size(dispc, i, burst_size); + if (dispc->feat->has_writeback) + dispc_ovl_set_burst_size(dispc, OMAP_DSS_WB, burst_size); } -static u32 dispc_ovl_get_burst_size(enum omap_plane_id plane) +static u32 dispc_ovl_get_burst_size(struct dispc_device *dispc, + enum omap_plane_id plane) { /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */ - return dispc.feat->burst_size_unit * 8; + return dispc->feat->burst_size_unit * 8; } -static bool dispc_ovl_color_mode_supported(enum omap_plane_id plane, u32 fourcc) +static bool dispc_ovl_color_mode_supported(struct dispc_device *dispc, + enum omap_plane_id plane, u32 fourcc) { const u32 *modes; unsigned int i; - modes = dispc.feat->supported_color_modes[plane]; + modes = dispc->feat->supported_color_modes[plane]; for (i = 0; modes[i]; ++i) { if (modes[i] == fourcc) @@ -1253,16 +1295,18 @@ static const u32 *dispc_ovl_get_color_modes(struct dispc_device *dispc, return dispc->feat->supported_color_modes[plane]; } -static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) +static void dispc_mgr_enable_cpr(struct dispc_device *dispc, + enum omap_channel channel, bool enable) { if (channel == OMAP_DSS_CHANNEL_DIGIT) return; - mgr_fld_write(channel, DISPC_MGR_FLD_CPR, enable); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_CPR, enable); } -static void dispc_mgr_set_cpr_coef(enum omap_channel channel, - const struct omap_dss_cpr_coefs *coefs) +static void dispc_mgr_set_cpr_coef(struct dispc_device *dispc, + enum omap_channel channel, + const struct omap_dss_cpr_coefs *coefs) { u32 coef_r, coef_g, coef_b; @@ -1276,25 +1320,27 @@ static void dispc_mgr_set_cpr_coef(enum omap_channel channel, coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) | FLD_VAL(coefs->bb, 9, 0); - dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r); - dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g); - dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b); + dispc_write_reg(dispc, DISPC_CPR_COEF_R(channel), coef_r); + dispc_write_reg(dispc, DISPC_CPR_COEF_G(channel), coef_g); + dispc_write_reg(dispc, DISPC_CPR_COEF_B(channel), coef_b); } -static void dispc_ovl_set_vid_color_conv(enum omap_plane_id plane, - bool enable) +static void dispc_ovl_set_vid_color_conv(struct dispc_device *dispc, + enum omap_plane_id plane, bool enable) { u32 val; BUG_ON(plane == OMAP_DSS_GFX); - val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); val = FLD_MOD(val, enable, 9, 9); - dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); + dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), val); } -static void dispc_ovl_enable_replication(enum omap_plane_id plane, - enum omap_overlay_caps caps, bool enable) +static void dispc_ovl_enable_replication(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_overlay_caps caps, + bool enable) { static const unsigned int shifts[] = { 5, 10, 10, 10 }; int shift; @@ -1303,21 +1349,21 @@ static void dispc_ovl_enable_replication(enum omap_plane_id plane, return; shift = shifts[plane]; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); } -static void dispc_mgr_set_size(enum omap_channel channel, u16 width, - u16 height) +static void dispc_mgr_set_size(struct dispc_device *dispc, + enum omap_channel channel, u16 width, u16 height) { u32 val; - val = FLD_VAL(height - 1, dispc.feat->mgr_height_start, 16) | - FLD_VAL(width - 1, dispc.feat->mgr_width_start, 0); + val = FLD_VAL(height - 1, dispc->feat->mgr_height_start, 16) | + FLD_VAL(width - 1, dispc->feat->mgr_width_start, 0); - dispc_write_reg(DISPC_SIZE_MGR(channel), val); + dispc_write_reg(dispc, DISPC_SIZE_MGR(channel), val); } -static void dispc_init_fifos(void) +static void dispc_init_fifos(struct dispc_device *dispc) { u32 size; int fifo; @@ -1325,20 +1371,21 @@ static void dispc_init_fifos(void) u32 unit; int i; - unit = dispc.feat->buffer_size_unit; + unit = dispc->feat->buffer_size_unit; - dispc_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); + dispc_get_reg_field(dispc, FEAT_REG_FIFOSIZE, &start, &end); - for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { - size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end); + for (fifo = 0; fifo < dispc->feat->num_fifos; ++fifo) { + size = REG_GET(dispc, DISPC_OVL_FIFO_SIZE_STATUS(fifo), + start, end); size *= unit; - dispc.fifo_size[fifo] = size; + dispc->fifo_size[fifo] = size; /* * By default fifos are mapped directly to overlays, fifo 0 to * ovl 0, fifo 1 to ovl 1, etc. */ - dispc.fifo_assignment[fifo] = fifo; + dispc->fifo_assignment[fifo] = fifo; } /* @@ -1348,57 +1395,58 @@ static void dispc_init_fifos(void) * giving GFX plane a larger fifo. WB but should work fine with a * smaller fifo. */ - if (dispc.feat->gfx_fifo_workaround) { + if (dispc->feat->gfx_fifo_workaround) { u32 v; - v = dispc_read_reg(DISPC_GLOBAL_BUFFER); + v = dispc_read_reg(dispc, DISPC_GLOBAL_BUFFER); v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */ v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */ v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */ v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */ - dispc_write_reg(DISPC_GLOBAL_BUFFER, v); + dispc_write_reg(dispc, DISPC_GLOBAL_BUFFER, v); - dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB; - dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX; + dispc->fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB; + dispc->fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX; } /* * Setup default fifo thresholds. */ - for (i = 0; i < dispc_get_num_ovls(&dispc); ++i) { + for (i = 0; i < dispc_get_num_ovls(dispc); ++i) { u32 low, high; const bool use_fifomerge = false; const bool manual_update = false; - dispc_ovl_compute_fifo_thresholds(&dispc, i, &low, &high, - use_fifomerge, manual_update); + dispc_ovl_compute_fifo_thresholds(dispc, i, &low, &high, + use_fifomerge, manual_update); - dispc_ovl_set_fifo_threshold(&dispc, i, low, high); + dispc_ovl_set_fifo_threshold(dispc, i, low, high); } - if (dispc.feat->has_writeback) { + if (dispc->feat->has_writeback) { u32 low, high; const bool use_fifomerge = false; const bool manual_update = false; - dispc_ovl_compute_fifo_thresholds(&dispc, OMAP_DSS_WB, - &low, &high, - use_fifomerge, manual_update); + dispc_ovl_compute_fifo_thresholds(dispc, OMAP_DSS_WB, + &low, &high, use_fifomerge, + manual_update); - dispc_ovl_set_fifo_threshold(&dispc, OMAP_DSS_WB, low, high); + dispc_ovl_set_fifo_threshold(dispc, OMAP_DSS_WB, low, high); } } -static u32 dispc_ovl_get_fifo_size(enum omap_plane_id plane) +static u32 dispc_ovl_get_fifo_size(struct dispc_device *dispc, + enum omap_plane_id plane) { int fifo; u32 size = 0; - for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { - if (dispc.fifo_assignment[fifo] == plane) - size += dispc.fifo_size[fifo]; + for (fifo = 0; fifo < dispc->feat->num_fifos; ++fifo) { + if (dispc->fifo_assignment[fifo] == plane) + size += dispc->fifo_size[fifo]; } return size; @@ -1419,18 +1467,20 @@ void dispc_ovl_set_fifo_threshold(struct dispc_device *dispc, low /= unit; high /= unit; - dispc_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end); - dispc_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end); + dispc_get_reg_field(dispc, FEAT_REG_FIFOHIGHTHRESHOLD, + &hi_start, &hi_end); + dispc_get_reg_field(dispc, FEAT_REG_FIFOLOWTHRESHOLD, + &lo_start, &lo_end); DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n", plane, - REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), + REG_GET(dispc, DISPC_OVL_FIFO_THRESHOLD(plane), lo_start, lo_end) * unit, - REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), + REG_GET(dispc, DISPC_OVL_FIFO_THRESHOLD(plane), hi_start, hi_end) * unit, low * unit, high * unit); - dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane), + dispc_write_reg(dispc, DISPC_OVL_FIFO_THRESHOLD(plane), FLD_VAL(high, hi_start, hi_end) | FLD_VAL(low, lo_start, lo_end)); @@ -1439,20 +1489,21 @@ void dispc_ovl_set_fifo_threshold(struct dispc_device *dispc, * large for the preload field, set the threshold to the maximum value * that can be held by the preload register */ - if (dispc_has_feature(FEAT_PRELOAD) && dispc->feat->set_max_preload && - plane != OMAP_DSS_WB) - dispc_write_reg(DISPC_OVL_PRELOAD(plane), min(high, 0xfffu)); + if (dispc_has_feature(dispc, FEAT_PRELOAD) && + dispc->feat->set_max_preload && plane != OMAP_DSS_WB) + dispc_write_reg(dispc, DISPC_OVL_PRELOAD(plane), + min(high, 0xfffu)); } void dispc_enable_fifomerge(struct dispc_device *dispc, bool enable) { - if (!dispc_has_feature(FEAT_FIFO_MERGE)) { + if (!dispc_has_feature(dispc, FEAT_FIFO_MERGE)) { WARN_ON(enable); return; } DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); - REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); + REG_FLD_MOD(dispc, DISPC_CONFIG, enable ? 1 : 0, 14, 14); } void dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc, @@ -1468,13 +1519,13 @@ void dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc, unsigned int ovl_fifo_size, total_fifo_size, burst_size; int i; - burst_size = dispc_ovl_get_burst_size(plane); - ovl_fifo_size = dispc_ovl_get_fifo_size(plane); + burst_size = dispc_ovl_get_burst_size(dispc, plane); + ovl_fifo_size = dispc_ovl_get_fifo_size(dispc, plane); if (use_fifomerge) { total_fifo_size = 0; for (i = 0; i < dispc_get_num_ovls(dispc); ++i) - total_fifo_size += dispc_ovl_get_fifo_size(i); + total_fifo_size += dispc_ovl_get_fifo_size(dispc, i); } else { total_fifo_size = ovl_fifo_size; } @@ -1485,7 +1536,7 @@ void dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc, * combined fifo size */ - if (manual_update && dispc_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { + if (manual_update && dispc_has_feature(dispc, FEAT_OMAP3_DSI_FIFO_BUG)) { *fifo_low = ovl_fifo_size - burst_size * 2; *fifo_high = total_fifo_size - burst_size; } else if (plane == OMAP_DSS_WB) { @@ -1502,7 +1553,8 @@ void dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc, } } -static void dispc_ovl_set_mflag(enum omap_plane_id plane, bool enable) +static void dispc_ovl_set_mflag(struct dispc_device *dispc, + enum omap_plane_id plane, bool enable) { int bit; @@ -1511,17 +1563,18 @@ static void dispc_ovl_set_mflag(enum omap_plane_id plane, bool enable) else bit = 23; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); } -static void dispc_ovl_set_mflag_threshold(enum omap_plane_id plane, - int low, int high) +static void dispc_ovl_set_mflag_threshold(struct dispc_device *dispc, + enum omap_plane_id plane, + int low, int high) { - dispc_write_reg(DISPC_OVL_MFLAG_THRESHOLD(plane), + dispc_write_reg(dispc, DISPC_OVL_MFLAG_THRESHOLD(plane), FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0)); } -static void dispc_init_mflag(void) +static void dispc_init_mflag(struct dispc_device *dispc) { int i; @@ -1535,16 +1588,16 @@ static void dispc_init_mflag(void) * * As a work-around, set force MFLAG to always on. */ - dispc_write_reg(DISPC_GLOBAL_MFLAG_ATTRIBUTE, + dispc_write_reg(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, (1 << 0) | /* MFLAG_CTRL = force always on */ (0 << 2)); /* MFLAG_START = disable */ - for (i = 0; i < dispc_get_num_ovls(&dispc); ++i) { - u32 size = dispc_ovl_get_fifo_size(i); - u32 unit = dispc.feat->buffer_size_unit; + for (i = 0; i < dispc_get_num_ovls(dispc); ++i) { + u32 size = dispc_ovl_get_fifo_size(dispc, i); + u32 unit = dispc->feat->buffer_size_unit; u32 low, high; - dispc_ovl_set_mflag(i, true); + dispc_ovl_set_mflag(dispc, i, true); /* * Simulation team suggests below thesholds: @@ -1555,15 +1608,15 @@ static void dispc_init_mflag(void) low = size * 4 / 8 / unit; high = size * 5 / 8 / unit; - dispc_ovl_set_mflag_threshold(i, low, high); + dispc_ovl_set_mflag_threshold(dispc, i, low, high); } - if (dispc.feat->has_writeback) { - u32 size = dispc_ovl_get_fifo_size(OMAP_DSS_WB); - u32 unit = dispc.feat->buffer_size_unit; + if (dispc->feat->has_writeback) { + u32 size = dispc_ovl_get_fifo_size(dispc, OMAP_DSS_WB); + u32 unit = dispc->feat->buffer_size_unit; u32 low, high; - dispc_ovl_set_mflag(OMAP_DSS_WB, true); + dispc_ovl_set_mflag(dispc, OMAP_DSS_WB, true); /* * Simulation team suggests below thesholds: @@ -1574,98 +1627,112 @@ static void dispc_init_mflag(void) low = size * 4 / 8 / unit; high = size * 5 / 8 / unit; - dispc_ovl_set_mflag_threshold(OMAP_DSS_WB, low, high); + dispc_ovl_set_mflag_threshold(dispc, OMAP_DSS_WB, low, high); } } -static void dispc_ovl_set_fir(enum omap_plane_id plane, - int hinc, int vinc, - enum omap_color_component color_comp) +static void dispc_ovl_set_fir(struct dispc_device *dispc, + enum omap_plane_id plane, + int hinc, int vinc, + enum omap_color_component color_comp) { u32 val; if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { u8 hinc_start, hinc_end, vinc_start, vinc_end; - dispc_get_reg_field(FEAT_REG_FIRHINC, &hinc_start, &hinc_end); - dispc_get_reg_field(FEAT_REG_FIRVINC, &vinc_start, &vinc_end); + dispc_get_reg_field(dispc, FEAT_REG_FIRHINC, + &hinc_start, &hinc_end); + dispc_get_reg_field(dispc, FEAT_REG_FIRVINC, + &vinc_start, &vinc_end); val = FLD_VAL(vinc, vinc_start, vinc_end) | FLD_VAL(hinc, hinc_start, hinc_end); - dispc_write_reg(DISPC_OVL_FIR(plane), val); + dispc_write_reg(dispc, DISPC_OVL_FIR(plane), val); } else { val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0); - dispc_write_reg(DISPC_OVL_FIR2(plane), val); + dispc_write_reg(dispc, DISPC_OVL_FIR2(plane), val); } } -static void dispc_ovl_set_vid_accu0(enum omap_plane_id plane, int haccu, +static void dispc_ovl_set_vid_accu0(struct dispc_device *dispc, + enum omap_plane_id plane, int haccu, int vaccu) { u32 val; u8 hor_start, hor_end, vert_start, vert_end; - dispc_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end); - dispc_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end); + dispc_get_reg_field(dispc, FEAT_REG_HORIZONTALACCU, + &hor_start, &hor_end); + dispc_get_reg_field(dispc, FEAT_REG_VERTICALACCU, + &vert_start, &vert_end); val = FLD_VAL(vaccu, vert_start, vert_end) | FLD_VAL(haccu, hor_start, hor_end); - dispc_write_reg(DISPC_OVL_ACCU0(plane), val); + dispc_write_reg(dispc, DISPC_OVL_ACCU0(plane), val); } -static void dispc_ovl_set_vid_accu1(enum omap_plane_id plane, int haccu, +static void dispc_ovl_set_vid_accu1(struct dispc_device *dispc, + enum omap_plane_id plane, int haccu, int vaccu) { u32 val; u8 hor_start, hor_end, vert_start, vert_end; - dispc_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end); - dispc_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end); + dispc_get_reg_field(dispc, FEAT_REG_HORIZONTALACCU, + &hor_start, &hor_end); + dispc_get_reg_field(dispc, FEAT_REG_VERTICALACCU, + &vert_start, &vert_end); val = FLD_VAL(vaccu, vert_start, vert_end) | FLD_VAL(haccu, hor_start, hor_end); - dispc_write_reg(DISPC_OVL_ACCU1(plane), val); + dispc_write_reg(dispc, DISPC_OVL_ACCU1(plane), val); } -static void dispc_ovl_set_vid_accu2_0(enum omap_plane_id plane, int haccu, - int vaccu) +static void dispc_ovl_set_vid_accu2_0(struct dispc_device *dispc, + enum omap_plane_id plane, int haccu, + int vaccu) { u32 val; val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0); - dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val); + dispc_write_reg(dispc, DISPC_OVL_ACCU2_0(plane), val); } -static void dispc_ovl_set_vid_accu2_1(enum omap_plane_id plane, int haccu, - int vaccu) +static void dispc_ovl_set_vid_accu2_1(struct dispc_device *dispc, + enum omap_plane_id plane, int haccu, + int vaccu) { u32 val; val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0); - dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val); + dispc_write_reg(dispc, DISPC_OVL_ACCU2_1(plane), val); } -static void dispc_ovl_set_scale_param(enum omap_plane_id plane, - u16 orig_width, u16 orig_height, - u16 out_width, u16 out_height, - bool five_taps, u8 rotation, - enum omap_color_component color_comp) +static void dispc_ovl_set_scale_param(struct dispc_device *dispc, + enum omap_plane_id plane, + u16 orig_width, u16 orig_height, + u16 out_width, u16 out_height, + bool five_taps, u8 rotation, + enum omap_color_component color_comp) { int fir_hinc, fir_vinc; fir_hinc = 1024 * orig_width / out_width; fir_vinc = 1024 * orig_height / out_height; - dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps, - color_comp); - dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); + dispc_ovl_set_scale_coef(dispc, plane, fir_hinc, fir_vinc, five_taps, + color_comp); + dispc_ovl_set_fir(dispc, plane, fir_hinc, fir_vinc, color_comp); } -static void dispc_ovl_set_accu_uv(enum omap_plane_id plane, - u16 orig_width, u16 orig_height, u16 out_width, u16 out_height, - bool ilace, u32 fourcc, u8 rotation) +static void dispc_ovl_set_accu_uv(struct dispc_device *dispc, + enum omap_plane_id plane, + u16 orig_width, u16 orig_height, + u16 out_width, u16 out_height, + bool ilace, u32 fourcc, u8 rotation) { int h_accu2_0, h_accu2_1; int v_accu2_0, v_accu2_1; @@ -1746,25 +1813,26 @@ static void dispc_ovl_set_accu_uv(enum omap_plane_id plane, v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024; v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024; - dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0); - dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1); + dispc_ovl_set_vid_accu2_0(dispc, plane, h_accu2_0, v_accu2_0); + dispc_ovl_set_vid_accu2_1(dispc, plane, h_accu2_1, v_accu2_1); } -static void dispc_ovl_set_scaling_common(enum omap_plane_id plane, - u16 orig_width, u16 orig_height, - u16 out_width, u16 out_height, - bool ilace, bool five_taps, - bool fieldmode, u32 fourcc, - u8 rotation) +static void dispc_ovl_set_scaling_common(struct dispc_device *dispc, + enum omap_plane_id plane, + u16 orig_width, u16 orig_height, + u16 out_width, u16 out_height, + bool ilace, bool five_taps, + bool fieldmode, u32 fourcc, + u8 rotation) { int accu0 = 0; int accu1 = 0; u32 l; - dispc_ovl_set_scale_param(plane, orig_width, orig_height, - out_width, out_height, five_taps, - rotation, DISPC_COLOR_COMPONENT_RGB_Y); - l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + dispc_ovl_set_scale_param(dispc, plane, orig_width, orig_height, + out_width, out_height, five_taps, + rotation, DISPC_COLOR_COMPONENT_RGB_Y); + l = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); /* RESIZEENABLE and VERTICALTAPS */ l &= ~((0x3 << 5) | (0x1 << 21)); @@ -1773,19 +1841,19 @@ static void dispc_ovl_set_scaling_common(enum omap_plane_id plane, l |= five_taps ? (1 << 21) : 0; /* VRESIZECONF and HRESIZECONF */ - if (dispc_has_feature(FEAT_RESIZECONF)) { + if (dispc_has_feature(dispc, FEAT_RESIZECONF)) { l &= ~(0x3 << 7); l |= (orig_width <= out_width) ? 0 : (1 << 7); l |= (orig_height <= out_height) ? 0 : (1 << 8); } /* LINEBUFFERSPLIT */ - if (dispc_has_feature(FEAT_LINEBUFFERSPLIT)) { + if (dispc_has_feature(dispc, FEAT_LINEBUFFERSPLIT)) { l &= ~(0x1 << 22); l |= five_taps ? (1 << 22) : 0; } - dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l); + dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), l); /* * field 0 = even field = bottom field @@ -1800,33 +1868,35 @@ static void dispc_ovl_set_scaling_common(enum omap_plane_id plane, } } - dispc_ovl_set_vid_accu0(plane, 0, accu0); - dispc_ovl_set_vid_accu1(plane, 0, accu1); + dispc_ovl_set_vid_accu0(dispc, plane, 0, accu0); + dispc_ovl_set_vid_accu1(dispc, plane, 0, accu1); } -static void dispc_ovl_set_scaling_uv(enum omap_plane_id plane, - u16 orig_width, u16 orig_height, - u16 out_width, u16 out_height, - bool ilace, bool five_taps, - bool fieldmode, u32 fourcc, - u8 rotation) +static void dispc_ovl_set_scaling_uv(struct dispc_device *dispc, + enum omap_plane_id plane, + u16 orig_width, u16 orig_height, + u16 out_width, u16 out_height, + bool ilace, bool five_taps, + bool fieldmode, u32 fourcc, + u8 rotation) { int scale_x = out_width != orig_width; int scale_y = out_height != orig_height; bool chroma_upscale = plane != OMAP_DSS_WB; - if (!dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) + if (!dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) return; if (!format_is_yuv(fourcc)) { /* reset chroma resampling for RGB formats */ if (plane != OMAP_DSS_WB) - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), + 0, 8, 8); return; } - dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width, - out_height, ilace, fourcc, rotation); + dispc_ovl_set_accu_uv(dispc, plane, orig_width, orig_height, out_width, + out_height, ilace, fourcc, rotation); switch (fourcc) { case DRM_FORMAT_NV12: @@ -1868,46 +1938,43 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane_id plane, if (out_height != orig_height) scale_y = true; - dispc_ovl_set_scale_param(plane, orig_width, orig_height, - out_width, out_height, five_taps, - rotation, DISPC_COLOR_COMPONENT_UV); + dispc_ovl_set_scale_param(dispc, plane, orig_width, orig_height, + out_width, out_height, five_taps, + rotation, DISPC_COLOR_COMPONENT_UV); if (plane != OMAP_DSS_WB) - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), (scale_x || scale_y) ? 1 : 0, 8, 8); /* set H scaling */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); /* set V scaling */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6); } -static void dispc_ovl_set_scaling(enum omap_plane_id plane, - u16 orig_width, u16 orig_height, - u16 out_width, u16 out_height, - bool ilace, bool five_taps, - bool fieldmode, u32 fourcc, - u8 rotation) +static void dispc_ovl_set_scaling(struct dispc_device *dispc, + enum omap_plane_id plane, + u16 orig_width, u16 orig_height, + u16 out_width, u16 out_height, + bool ilace, bool five_taps, + bool fieldmode, u32 fourcc, + u8 rotation) { BUG_ON(plane == OMAP_DSS_GFX); - dispc_ovl_set_scaling_common(plane, - orig_width, orig_height, - out_width, out_height, - ilace, five_taps, - fieldmode, fourcc, - rotation); + dispc_ovl_set_scaling_common(dispc, plane, orig_width, orig_height, + out_width, out_height, ilace, five_taps, + fieldmode, fourcc, rotation); - dispc_ovl_set_scaling_uv(plane, - orig_width, orig_height, - out_width, out_height, - ilace, five_taps, - fieldmode, fourcc, - rotation); + dispc_ovl_set_scaling_uv(dispc, plane, orig_width, orig_height, + out_width, out_height, ilace, five_taps, + fieldmode, fourcc, rotation); } -static void dispc_ovl_set_rotation_attrs(enum omap_plane_id plane, u8 rotation, - enum omap_dss_rotation_type rotation_type, u32 fourcc) +static void dispc_ovl_set_rotation_attrs(struct dispc_device *dispc, + enum omap_plane_id plane, u8 rotation, + enum omap_dss_rotation_type rotation_type, + u32 fourcc) { bool row_repeat = false; int vidrot = 0; @@ -1961,19 +2028,20 @@ static void dispc_ovl_set_rotation_attrs(enum omap_plane_id plane, u8 rotation, if (fourcc == DRM_FORMAT_NV12 && rotation_type != OMAP_DSS_ROT_TILER) vidrot = 1; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12); - if (dispc_has_feature(FEAT_ROWREPEATENABLE)) - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12); + if (dispc_has_feature(dispc, FEAT_ROWREPEATENABLE)) + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), row_repeat ? 1 : 0, 18, 18); - if (dispc_ovl_color_mode_supported(plane, DRM_FORMAT_NV12)) { + if (dispc_ovl_color_mode_supported(dispc, plane, DRM_FORMAT_NV12)) { bool doublestride = fourcc == DRM_FORMAT_NV12 && rotation_type == OMAP_DSS_ROT_TILER && !drm_rotation_90_or_270(rotation); /* DOUBLESTRIDE */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), + doublestride, 22, 22); } } @@ -2210,27 +2278,31 @@ static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width, return pclk; } -static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk, - const struct videomode *vm, - u16 width, u16 height, u16 out_width, u16 out_height, - u32 fourcc, bool *five_taps, - int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, - u16 pos_x, unsigned long *core_clk, bool mem_to_mem) +static int dispc_ovl_calc_scaling_24xx(struct dispc_device *dispc, + unsigned long pclk, unsigned long lclk, + const struct videomode *vm, + u16 width, u16 height, + u16 out_width, u16 out_height, + u32 fourcc, bool *five_taps, + int *x_predecim, int *y_predecim, + int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, + bool mem_to_mem) { int error; u16 in_width, in_height; int min_factor = min(*decim_x, *decim_y); - const int maxsinglelinewidth = dispc.feat->max_line_width; + const int maxsinglelinewidth = dispc->feat->max_line_width; *five_taps = false; do { in_height = height / *decim_y; in_width = width / *decim_x; - *core_clk = dispc.feat->calc_core_clk(pclk, in_width, + *core_clk = dispc->feat->calc_core_clk(pclk, in_width, in_height, out_width, out_height, mem_to_mem); error = (in_width > maxsinglelinewidth || !*core_clk || - *core_clk > dispc_core_clk_rate()); + *core_clk > dispc_core_clk_rate(dispc)); if (error) { if (*decim_x == *decim_y) { *decim_x = min_factor; @@ -2255,16 +2327,20 @@ static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk, return 0; } -static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk, - const struct videomode *vm, - u16 width, u16 height, u16 out_width, u16 out_height, - u32 fourcc, bool *five_taps, - int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, - u16 pos_x, unsigned long *core_clk, bool mem_to_mem) +static int dispc_ovl_calc_scaling_34xx(struct dispc_device *dispc, + unsigned long pclk, unsigned long lclk, + const struct videomode *vm, + u16 width, u16 height, + u16 out_width, u16 out_height, + u32 fourcc, bool *five_taps, + int *x_predecim, int *y_predecim, + int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, + bool mem_to_mem) { int error; u16 in_width, in_height; - const int maxsinglelinewidth = dispc.feat->max_line_width; + const int maxsinglelinewidth = dispc->feat->max_line_width; do { in_height = height / *decim_y; @@ -2281,7 +2357,7 @@ again: in_width, in_height, out_width, out_height, fourcc); else - *core_clk = dispc.feat->calc_core_clk(pclk, in_width, + *core_clk = dispc->feat->calc_core_clk(pclk, in_width, in_height, out_width, out_height, mem_to_mem); @@ -2295,7 +2371,7 @@ again: error = (error || in_width > maxsinglelinewidth * 2 || (in_width > maxsinglelinewidth && *five_taps) || - !*core_clk || *core_clk > dispc_core_clk_rate()); + !*core_clk || *core_clk > dispc_core_clk_rate(dispc)); if (!error) { /* verify that we're inside the limits of scaler */ @@ -2339,24 +2415,28 @@ again: return 0; } -static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, - const struct videomode *vm, - u16 width, u16 height, u16 out_width, u16 out_height, - u32 fourcc, bool *five_taps, - int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, - u16 pos_x, unsigned long *core_clk, bool mem_to_mem) +static int dispc_ovl_calc_scaling_44xx(struct dispc_device *dispc, + unsigned long pclk, unsigned long lclk, + const struct videomode *vm, + u16 width, u16 height, + u16 out_width, u16 out_height, + u32 fourcc, bool *five_taps, + int *x_predecim, int *y_predecim, + int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, + bool mem_to_mem) { u16 in_width, in_width_max; int decim_x_min = *decim_x; u16 in_height = height / *decim_y; - const int maxsinglelinewidth = dispc.feat->max_line_width; - const int maxdownscale = dispc.feat->max_downscale; + const int maxsinglelinewidth = dispc->feat->max_line_width; + const int maxdownscale = dispc->feat->max_downscale; if (mem_to_mem) { in_width_max = out_width * maxdownscale; } else { - in_width_max = dispc_core_clk_rate() / - DIV_ROUND_UP(pclk, out_width); + in_width_max = dispc_core_clk_rate(dispc) + / DIV_ROUND_UP(pclk, out_width); } *decim_x = DIV_ROUND_UP(width, in_width_max); @@ -2394,7 +2474,7 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, return -EINVAL; } - *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height, + *core_clk = dispc->feat->calc_core_clk(pclk, in_width, in_height, out_width, out_height, mem_to_mem); return 0; } @@ -2402,15 +2482,18 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, #define DIV_FRAC(dividend, divisor) \ ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100)) -static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, - enum omap_overlay_caps caps, - const struct videomode *vm, - u16 width, u16 height, u16 out_width, u16 out_height, - u32 fourcc, bool *five_taps, - int *x_predecim, int *y_predecim, u16 pos_x, - enum omap_dss_rotation_type rotation_type, bool mem_to_mem) -{ - const int maxdownscale = dispc.feat->max_downscale; +static int dispc_ovl_calc_scaling(struct dispc_device *dispc, + unsigned long pclk, unsigned long lclk, + enum omap_overlay_caps caps, + const struct videomode *vm, + u16 width, u16 height, + u16 out_width, u16 out_height, + u32 fourcc, bool *five_taps, + int *x_predecim, int *y_predecim, u16 pos_x, + enum omap_dss_rotation_type rotation_type, + bool mem_to_mem) +{ + const int maxdownscale = dispc->feat->max_downscale; const int max_decim_limit = 16; unsigned long core_clk = 0; int decim_x, decim_y, ret; @@ -2431,7 +2514,7 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, } else { *x_predecim = max_decim_limit; *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && - dispc_has_feature(FEAT_BURST_2D)) ? + dispc_has_feature(dispc, FEAT_BURST_2D)) ? 2 : max_decim_limit; } @@ -2444,10 +2527,11 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, if (decim_y > *y_predecim || out_height > height * 8) return -EINVAL; - ret = dispc.feat->calc_scaling(pclk, lclk, vm, width, height, - out_width, out_height, fourcc, five_taps, - x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk, - mem_to_mem); + ret = dispc->feat->calc_scaling(dispc, pclk, lclk, vm, width, height, + out_width, out_height, fourcc, + five_taps, x_predecim, y_predecim, + &decim_x, &decim_y, pos_x, &core_clk, + mem_to_mem); if (ret) return ret; @@ -2463,13 +2547,13 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y), *five_taps ? 5 : 3, - core_clk, dispc_core_clk_rate()); + core_clk, dispc_core_clk_rate(dispc)); - if (!core_clk || core_clk > dispc_core_clk_rate()) { + if (!core_clk || core_clk > dispc_core_clk_rate(dispc)) { DSSERR("failed to set up scaling, " "required core clk rate = %lu Hz, " "current core clk rate = %lu Hz\n", - core_clk, dispc_core_clk_rate()); + core_clk, dispc_core_clk_rate(dispc)); return -EINVAL; } @@ -2478,14 +2562,18 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, return 0; } -static int dispc_ovl_setup_common(enum omap_plane_id plane, - enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr, - u16 screen_width, int pos_x, int pos_y, u16 width, u16 height, - u16 out_width, u16 out_height, u32 fourcc, - u8 rotation, u8 zorder, u8 pre_mult_alpha, - u8 global_alpha, enum omap_dss_rotation_type rotation_type, - bool replication, const struct videomode *vm, - bool mem_to_mem) +static int dispc_ovl_setup_common(struct dispc_device *dispc, + enum omap_plane_id plane, + enum omap_overlay_caps caps, + u32 paddr, u32 p_uv_addr, + u16 screen_width, int pos_x, int pos_y, + u16 width, u16 height, + u16 out_width, u16 out_height, + u32 fourcc, u8 rotation, u8 zorder, + u8 pre_mult_alpha, u8 global_alpha, + enum omap_dss_rotation_type rotation_type, + bool replication, const struct videomode *vm, + bool mem_to_mem) { bool five_taps = true; bool fieldmode = false; @@ -2499,8 +2587,8 @@ static int dispc_ovl_setup_common(enum omap_plane_id plane, u16 in_width = width; int x_predecim = 1, y_predecim = 1; bool ilace = !!(vm->flags & DISPLAY_FLAGS_INTERLACED); - unsigned long pclk = dispc_plane_pclk_rate(plane); - unsigned long lclk = dispc_plane_lclk_rate(plane); + unsigned long pclk = dispc_plane_pclk_rate(dispc, plane); + unsigned long lclk = dispc_plane_lclk_rate(dispc, plane); if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER) return -EINVAL; @@ -2527,13 +2615,13 @@ static int dispc_ovl_setup_common(enum omap_plane_id plane, out_height); } - if (!dispc_ovl_color_mode_supported(plane, fourcc)) + if (!dispc_ovl_color_mode_supported(dispc, plane, fourcc)) return -EINVAL; - r = dispc_ovl_calc_scaling(pclk, lclk, caps, vm, in_width, - in_height, out_width, out_height, fourcc, - &five_taps, &x_predecim, &y_predecim, pos_x, - rotation_type, mem_to_mem); + r = dispc_ovl_calc_scaling(dispc, pclk, lclk, caps, vm, in_width, + in_height, out_width, out_height, fourcc, + &five_taps, &x_predecim, &y_predecim, pos_x, + rotation_type, mem_to_mem); if (r) return r; @@ -2595,49 +2683,50 @@ static int dispc_ovl_setup_common(enum omap_plane_id plane, DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", offset0, offset1, row_inc, pix_inc); - dispc_ovl_set_color_mode(plane, fourcc); + dispc_ovl_set_color_mode(dispc, plane, fourcc); - dispc_ovl_configure_burst_type(plane, rotation_type); + dispc_ovl_configure_burst_type(dispc, plane, rotation_type); - if (dispc.feat->reverse_ilace_field_order) + if (dispc->feat->reverse_ilace_field_order) swap(offset0, offset1); - dispc_ovl_set_ba0(plane, paddr + offset0); - dispc_ovl_set_ba1(plane, paddr + offset1); + dispc_ovl_set_ba0(dispc, plane, paddr + offset0); + dispc_ovl_set_ba1(dispc, plane, paddr + offset1); if (fourcc == DRM_FORMAT_NV12) { - dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0); - dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1); + dispc_ovl_set_ba0_uv(dispc, plane, p_uv_addr + offset0); + dispc_ovl_set_ba1_uv(dispc, plane, p_uv_addr + offset1); } - if (dispc.feat->last_pixel_inc_missing) + if (dispc->feat->last_pixel_inc_missing) row_inc += pix_inc - 1; - dispc_ovl_set_row_inc(plane, row_inc); - dispc_ovl_set_pix_inc(plane, pix_inc); + dispc_ovl_set_row_inc(dispc, plane, row_inc); + dispc_ovl_set_pix_inc(dispc, plane, pix_inc); DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width, in_height, out_width, out_height); - dispc_ovl_set_pos(plane, caps, pos_x, pos_y); + dispc_ovl_set_pos(dispc, plane, caps, pos_x, pos_y); - dispc_ovl_set_input_size(plane, in_width, in_height); + dispc_ovl_set_input_size(dispc, plane, in_width, in_height); if (caps & OMAP_DSS_OVL_CAP_SCALE) { - dispc_ovl_set_scaling(plane, in_width, in_height, out_width, - out_height, ilace, five_taps, fieldmode, - fourcc, rotation); - dispc_ovl_set_output_size(plane, out_width, out_height); - dispc_ovl_set_vid_color_conv(plane, cconv); + dispc_ovl_set_scaling(dispc, plane, in_width, in_height, + out_width, out_height, ilace, five_taps, + fieldmode, fourcc, rotation); + dispc_ovl_set_output_size(dispc, plane, out_width, out_height); + dispc_ovl_set_vid_color_conv(dispc, plane, cconv); } - dispc_ovl_set_rotation_attrs(plane, rotation, rotation_type, fourcc); + dispc_ovl_set_rotation_attrs(dispc, plane, rotation, rotation_type, + fourcc); - dispc_ovl_set_zorder(plane, caps, zorder); - dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha); - dispc_ovl_setup_global_alpha(plane, caps, global_alpha); + dispc_ovl_set_zorder(dispc, plane, caps, zorder); + dispc_ovl_set_pre_mult_alpha(dispc, plane, caps, pre_mult_alpha); + dispc_ovl_setup_global_alpha(dispc, plane, caps, global_alpha); - dispc_ovl_enable_replication(plane, caps, replication); + dispc_ovl_enable_replication(dispc, plane, caps, replication); return 0; } @@ -2658,9 +2747,9 @@ static int dispc_ovl_setup(struct dispc_device *dispc, oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, oi->fourcc, oi->rotation, channel, replication); - dispc_ovl_set_channel_out(plane, channel); + dispc_ovl_set_channel_out(dispc, plane, channel); - r = dispc_ovl_setup_common(plane, caps, oi->paddr, oi->p_uv_addr, + r = dispc_ovl_setup_common(dispc, plane, caps, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, oi->fourcc, oi->rotation, oi->zorder, oi->pre_mult_alpha, oi->global_alpha, @@ -2689,7 +2778,7 @@ int dispc_wb_setup(struct dispc_device *dispc, "rot %d\n", wi->paddr, wi->p_uv_addr, in_width, in_height, wi->width, wi->height, wi->fourcc, wi->rotation); - r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr, + r = dispc_ovl_setup_common(dispc, plane, caps, wi->paddr, wi->p_uv_addr, wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width, wi->height, wi->fourcc, wi->rotation, zorder, wi->pre_mult_alpha, global_alpha, wi->rotation_type, @@ -2712,18 +2801,18 @@ int dispc_wb_setup(struct dispc_device *dispc, } /* setup extra DISPC_WB_ATTRIBUTES */ - l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + l = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */ l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */ if (mem_to_mem) l = FLD_MOD(l, 1, 26, 24); /* CAPTUREMODE */ else l = FLD_MOD(l, 0, 26, 24); /* CAPTUREMODE */ - dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l); + dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), l); if (mem_to_mem) { /* WBDELAYCOUNT */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0); } else { int wbdelay; @@ -2731,7 +2820,7 @@ int dispc_wb_setup(struct dispc_device *dispc, vm->vsync_len + vm->vback_porch, (u32)255); /* WBDELAYCOUNT */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0); } return r; @@ -2742,7 +2831,7 @@ static int dispc_ovl_enable(struct dispc_device *dispc, { DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); return 0; } @@ -2754,94 +2843,106 @@ dispc_mgr_get_supported_outputs(struct dispc_device *dispc, return dss_get_supported_outputs(dispc->dss, channel); } -static void dispc_lcd_enable_signal_polarity(bool act_high) +static void dispc_lcd_enable_signal_polarity(struct dispc_device *dispc, + bool act_high) { - if (!dispc_has_feature(FEAT_LCDENABLEPOL)) + if (!dispc_has_feature(dispc, FEAT_LCDENABLEPOL)) return; - REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29); + REG_FLD_MOD(dispc, DISPC_CONTROL, act_high ? 1 : 0, 29, 29); } void dispc_lcd_enable_signal(struct dispc_device *dispc, bool enable) { - if (!dispc_has_feature(FEAT_LCDENABLESIGNAL)) + if (!dispc_has_feature(dispc, FEAT_LCDENABLESIGNAL)) return; - REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28); + REG_FLD_MOD(dispc, DISPC_CONTROL, enable ? 1 : 0, 28, 28); } void dispc_pck_free_enable(struct dispc_device *dispc, bool enable) { - if (!dispc_has_feature(FEAT_PCKFREEENABLE)) + if (!dispc_has_feature(dispc, FEAT_PCKFREEENABLE)) return; - REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); + REG_FLD_MOD(dispc, DISPC_CONTROL, enable ? 1 : 0, 27, 27); } -static void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable) +static void dispc_mgr_enable_fifohandcheck(struct dispc_device *dispc, + enum omap_channel channel, + bool enable) { - mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable); } -static void dispc_mgr_set_lcd_type_tft(enum omap_channel channel) +static void dispc_mgr_set_lcd_type_tft(struct dispc_device *dispc, + enum omap_channel channel) { - mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_STNTFT, 1); } -static void dispc_set_loadmode(enum omap_dss_load_mode mode) +static void dispc_set_loadmode(struct dispc_device *dispc, + enum omap_dss_load_mode mode) { - REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1); + REG_FLD_MOD(dispc, DISPC_CONFIG, mode, 2, 1); } -static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) +static void dispc_mgr_set_default_color(struct dispc_device *dispc, + enum omap_channel channel, u32 color) { - dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); + dispc_write_reg(dispc, DISPC_DEFAULT_COLOR(channel), color); } -static void dispc_mgr_set_trans_key(enum omap_channel ch, - enum omap_dss_trans_key_type type, - u32 trans_key) +static void dispc_mgr_set_trans_key(struct dispc_device *dispc, + enum omap_channel ch, + enum omap_dss_trans_key_type type, + u32 trans_key) { - mgr_fld_write(ch, DISPC_MGR_FLD_TCKSELECTION, type); + mgr_fld_write(dispc, ch, DISPC_MGR_FLD_TCKSELECTION, type); - dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); + dispc_write_reg(dispc, DISPC_TRANS_COLOR(ch), trans_key); } -static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) +static void dispc_mgr_enable_trans_key(struct dispc_device *dispc, + enum omap_channel ch, bool enable) { - mgr_fld_write(ch, DISPC_MGR_FLD_TCKENABLE, enable); + mgr_fld_write(dispc, ch, DISPC_MGR_FLD_TCKENABLE, enable); } -static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, - bool enable) +static void dispc_mgr_enable_alpha_fixed_zorder(struct dispc_device *dispc, + enum omap_channel ch, + bool enable) { - if (!dispc_has_feature(FEAT_ALPHA_FIXED_ZORDER)) + if (!dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER)) return; if (ch == OMAP_DSS_CHANNEL_LCD) - REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); + REG_FLD_MOD(dispc, DISPC_CONFIG, enable, 18, 18); else if (ch == OMAP_DSS_CHANNEL_DIGIT) - REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); + REG_FLD_MOD(dispc, DISPC_CONFIG, enable, 19, 19); } static void dispc_mgr_setup(struct dispc_device *dispc, enum omap_channel channel, const struct omap_overlay_manager_info *info) { - dispc_mgr_set_default_color(channel, info->default_color); - dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key); - dispc_mgr_enable_trans_key(channel, info->trans_enabled); - dispc_mgr_enable_alpha_fixed_zorder(channel, + dispc_mgr_set_default_color(dispc, channel, info->default_color); + dispc_mgr_set_trans_key(dispc, channel, info->trans_key_type, + info->trans_key); + dispc_mgr_enable_trans_key(dispc, channel, info->trans_enabled); + dispc_mgr_enable_alpha_fixed_zorder(dispc, channel, info->partial_alpha_enabled); - if (dispc_has_feature(FEAT_CPR)) { - dispc_mgr_enable_cpr(channel, info->cpr_enable); - dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs); + if (dispc_has_feature(dispc, FEAT_CPR)) { + dispc_mgr_enable_cpr(dispc, channel, info->cpr_enable); + dispc_mgr_set_cpr_coef(dispc, channel, &info->cpr_coefs); } } -static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) +static void dispc_mgr_set_tft_data_lines(struct dispc_device *dispc, + enum omap_channel channel, + u8 data_lines) { int code; @@ -2863,10 +2964,11 @@ static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_line return; } - mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_TFTDATALINES, code); } -static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) +static void dispc_mgr_set_io_pad_mode(struct dispc_device *dispc, + enum dss_io_pad_mode mode) { u32 l; int gpout0, gpout1; @@ -2889,70 +2991,74 @@ static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) return; } - l = dispc_read_reg(DISPC_CONTROL); + l = dispc_read_reg(dispc, DISPC_CONTROL); l = FLD_MOD(l, gpout0, 15, 15); l = FLD_MOD(l, gpout1, 16, 16); - dispc_write_reg(DISPC_CONTROL, l); + dispc_write_reg(dispc, DISPC_CONTROL, l); } -static void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable) +static void dispc_mgr_enable_stallmode(struct dispc_device *dispc, + enum omap_channel channel, bool enable) { - mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable); + mgr_fld_write(dispc, channel, DISPC_MGR_FLD_STALLMODE, enable); } static void dispc_mgr_set_lcd_config(struct dispc_device *dispc, enum omap_channel channel, const struct dss_lcd_mgr_config *config) { - dispc_mgr_set_io_pad_mode(config->io_pad_mode); + dispc_mgr_set_io_pad_mode(dispc, config->io_pad_mode); - dispc_mgr_enable_stallmode(channel, config->stallmode); - dispc_mgr_enable_fifohandcheck(channel, config->fifohandcheck); + dispc_mgr_enable_stallmode(dispc, channel, config->stallmode); + dispc_mgr_enable_fifohandcheck(dispc, channel, config->fifohandcheck); dispc_mgr_set_clock_div(dispc, channel, &config->clock_info); - dispc_mgr_set_tft_data_lines(channel, config->video_port_width); + dispc_mgr_set_tft_data_lines(dispc, channel, config->video_port_width); - dispc_lcd_enable_signal_polarity(config->lcden_sig_polarity); + dispc_lcd_enable_signal_polarity(dispc, config->lcden_sig_polarity); - dispc_mgr_set_lcd_type_tft(channel); + dispc_mgr_set_lcd_type_tft(dispc, channel); } -static bool _dispc_mgr_size_ok(u16 width, u16 height) +static bool _dispc_mgr_size_ok(struct dispc_device *dispc, + u16 width, u16 height) { - return width <= dispc.feat->mgr_width_max && - height <= dispc.feat->mgr_height_max; + return width <= dispc->feat->mgr_width_max && + height <= dispc->feat->mgr_height_max; } -static bool _dispc_lcd_timings_ok(int hsync_len, int hfp, int hbp, - int vsw, int vfp, int vbp) +static bool _dispc_lcd_timings_ok(struct dispc_device *dispc, + int hsync_len, int hfp, int hbp, + int vsw, int vfp, int vbp) { - if (hsync_len < 1 || hsync_len > dispc.feat->sw_max || - hfp < 1 || hfp > dispc.feat->hp_max || - hbp < 1 || hbp > dispc.feat->hp_max || - vsw < 1 || vsw > dispc.feat->sw_max || - vfp < 0 || vfp > dispc.feat->vp_max || - vbp < 0 || vbp > dispc.feat->vp_max) + if (hsync_len < 1 || hsync_len > dispc->feat->sw_max || + hfp < 1 || hfp > dispc->feat->hp_max || + hbp < 1 || hbp > dispc->feat->hp_max || + vsw < 1 || vsw > dispc->feat->sw_max || + vfp < 0 || vfp > dispc->feat->vp_max || + vbp < 0 || vbp > dispc->feat->vp_max) return false; return true; } -static bool _dispc_mgr_pclk_ok(enum omap_channel channel, - unsigned long pclk) +static bool _dispc_mgr_pclk_ok(struct dispc_device *dispc, + enum omap_channel channel, + unsigned long pclk) { if (dss_mgr_is_lcd(channel)) - return pclk <= dispc.feat->max_lcd_pclk; + return pclk <= dispc->feat->max_lcd_pclk; else - return pclk <= dispc.feat->max_tv_pclk; + return pclk <= dispc->feat->max_tv_pclk; } bool dispc_mgr_timings_ok(struct dispc_device *dispc, enum omap_channel channel, const struct videomode *vm) { - if (!_dispc_mgr_size_ok(vm->hactive, vm->vactive)) + if (!_dispc_mgr_size_ok(dispc, vm->hactive, vm->vactive)) return false; - if (!_dispc_mgr_pclk_ok(channel, vm->pixelclock)) + if (!_dispc_mgr_pclk_ok(dispc, channel, vm->pixelclock)) return false; if (dss_mgr_is_lcd(channel)) { @@ -2960,7 +3066,7 @@ bool dispc_mgr_timings_ok(struct dispc_device *dispc, enum omap_channel channel, if (vm->flags & DISPLAY_FLAGS_INTERLACED) return false; - if (!_dispc_lcd_timings_ok(vm->hsync_len, + if (!_dispc_lcd_timings_ok(dispc, vm->hsync_len, vm->hfront_porch, vm->hback_porch, vm->vsync_len, vm->vfront_porch, vm->vback_porch)) @@ -2970,21 +3076,22 @@ bool dispc_mgr_timings_ok(struct dispc_device *dispc, enum omap_channel channel, return true; } -static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, +static void _dispc_mgr_set_lcd_timings(struct dispc_device *dispc, + enum omap_channel channel, const struct videomode *vm) { u32 timing_h, timing_v, l; bool onoff, rf, ipc, vs, hs, de; - timing_h = FLD_VAL(vm->hsync_len - 1, dispc.feat->sw_start, 0) | - FLD_VAL(vm->hfront_porch - 1, dispc.feat->fp_start, 8) | - FLD_VAL(vm->hback_porch - 1, dispc.feat->bp_start, 20); - timing_v = FLD_VAL(vm->vsync_len - 1, dispc.feat->sw_start, 0) | - FLD_VAL(vm->vfront_porch, dispc.feat->fp_start, 8) | - FLD_VAL(vm->vback_porch, dispc.feat->bp_start, 20); + timing_h = FLD_VAL(vm->hsync_len - 1, dispc->feat->sw_start, 0) | + FLD_VAL(vm->hfront_porch - 1, dispc->feat->fp_start, 8) | + FLD_VAL(vm->hback_porch - 1, dispc->feat->bp_start, 20); + timing_v = FLD_VAL(vm->vsync_len - 1, dispc->feat->sw_start, 0) | + FLD_VAL(vm->vfront_porch, dispc->feat->fp_start, 8) | + FLD_VAL(vm->vback_porch, dispc->feat->bp_start, 20); - dispc_write_reg(DISPC_TIMING_H(channel), timing_h); - dispc_write_reg(DISPC_TIMING_V(channel), timing_v); + dispc_write_reg(dispc, DISPC_TIMING_H(channel), timing_h); + dispc_write_reg(dispc, DISPC_TIMING_V(channel), timing_v); if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH) vs = false; @@ -3022,12 +3129,12 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, FLD_VAL(vs, 12, 12); /* always set ALIGN bit when available */ - if (dispc.feat->supports_sync_align) + if (dispc->feat->supports_sync_align) l |= (1 << 18); - dispc_write_reg(DISPC_POL_FREQ(channel), l); + dispc_write_reg(dispc, DISPC_POL_FREQ(channel), l); - if (dispc.syscon_pol) { + if (dispc->syscon_pol) { const int shifts[] = { [OMAP_DSS_CHANNEL_LCD] = 0, [OMAP_DSS_CHANNEL_LCD2] = 1, @@ -3042,8 +3149,8 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, mask <<= 16 + shifts[channel]; val <<= 16 + shifts[channel]; - regmap_update_bits(dispc.syscon_pol, dispc.syscon_pol_offset, - mask, val); + regmap_update_bits(dispc->syscon_pol, dispc->syscon_pol_offset, + mask, val); } } @@ -3074,7 +3181,7 @@ static void dispc_mgr_set_timings(struct dispc_device *dispc, } if (dss_mgr_is_lcd(channel)) { - _dispc_mgr_set_lcd_timings(channel, &t); + _dispc_mgr_set_lcd_timings(dispc, channel, &t); xtot = t.hactive + t.hfront_porch + t.hsync_len + t.hback_porch; ytot = t.vactive + t.vfront_porch + t.vsync_len + t.vback_porch; @@ -3099,51 +3206,53 @@ static void dispc_mgr_set_timings(struct dispc_device *dispc, t.vactive /= 2; if (dispc->feat->supports_double_pixel) - REG_FLD_MOD(DISPC_CONTROL, + REG_FLD_MOD(dispc, DISPC_CONTROL, !!(t.flags & DISPLAY_FLAGS_DOUBLECLK), 19, 17); } - dispc_mgr_set_size(channel, t.hactive, t.vactive); + dispc_mgr_set_size(dispc, channel, t.hactive, t.vactive); } -static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, - u16 pck_div) +static void dispc_mgr_set_lcd_divisor(struct dispc_device *dispc, + enum omap_channel channel, u16 lck_div, + u16 pck_div) { BUG_ON(lck_div < 1); BUG_ON(pck_div < 1); - dispc_write_reg(DISPC_DIVISORo(channel), + dispc_write_reg(dispc, DISPC_DIVISORo(channel), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); - if (!dispc_has_feature(FEAT_CORE_CLK_DIV) && + if (!dispc_has_feature(dispc, FEAT_CORE_CLK_DIV) && channel == OMAP_DSS_CHANNEL_LCD) - dispc.core_clk_rate = dispc_fclk_rate() / lck_div; + dispc->core_clk_rate = dispc_fclk_rate(dispc) / lck_div; } -static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div, - int *pck_div) +static void dispc_mgr_get_lcd_divisor(struct dispc_device *dispc, + enum omap_channel channel, int *lck_div, + int *pck_div) { u32 l; - l = dispc_read_reg(DISPC_DIVISORo(channel)); + l = dispc_read_reg(dispc, DISPC_DIVISORo(channel)); *lck_div = FLD_GET(l, 23, 16); *pck_div = FLD_GET(l, 7, 0); } -static unsigned long dispc_fclk_rate(void) +static unsigned long dispc_fclk_rate(struct dispc_device *dispc) { unsigned long r; enum dss_clk_source src; - src = dss_get_dispc_clk_source(dispc.dss); + src = dss_get_dispc_clk_source(dispc->dss); if (src == DSS_CLK_SRC_FCK) { - r = dss_get_dispc_clk_rate(dispc.dss); + r = dss_get_dispc_clk_rate(dispc->dss); } else { struct dss_pll *pll; unsigned int clkout_idx; - pll = dss_pll_find_by_src(dispc.dss, src); + pll = dss_pll_find_by_src(dispc->dss, src); clkout_idx = dss_pll_get_clkout_idx_for_src(src); r = pll->cinfo.clkout[clkout_idx]; @@ -3152,7 +3261,8 @@ static unsigned long dispc_fclk_rate(void) return r; } -static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) +static unsigned long dispc_mgr_lclk_rate(struct dispc_device *dispc, + enum omap_channel channel) { int lcd; unsigned long r; @@ -3160,28 +3270,29 @@ static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) /* for TV, LCLK rate is the FCLK rate */ if (!dss_mgr_is_lcd(channel)) - return dispc_fclk_rate(); + return dispc_fclk_rate(dispc); - src = dss_get_lcd_clk_source(dispc.dss, channel); + src = dss_get_lcd_clk_source(dispc->dss, channel); if (src == DSS_CLK_SRC_FCK) { - r = dss_get_dispc_clk_rate(dispc.dss); + r = dss_get_dispc_clk_rate(dispc->dss); } else { struct dss_pll *pll; unsigned int clkout_idx; - pll = dss_pll_find_by_src(dispc.dss, src); + pll = dss_pll_find_by_src(dispc->dss, src); clkout_idx = dss_pll_get_clkout_idx_for_src(src); r = pll->cinfo.clkout[clkout_idx]; } - lcd = REG_GET(DISPC_DIVISORo(channel), 23, 16); + lcd = REG_GET(dispc, DISPC_DIVISORo(channel), 23, 16); return r / lcd; } -static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) +static unsigned long dispc_mgr_pclk_rate(struct dispc_device *dispc, + enum omap_channel channel) { unsigned long r; @@ -3189,15 +3300,15 @@ static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) int pcd; u32 l; - l = dispc_read_reg(DISPC_DIVISORo(channel)); + l = dispc_read_reg(dispc, DISPC_DIVISORo(channel)); pcd = FLD_GET(l, 7, 0); - r = dispc_mgr_lclk_rate(channel); + r = dispc_mgr_lclk_rate(dispc, channel); return r / pcd; } else { - return dispc.tv_pclk_rate; + return dispc->tv_pclk_rate; } } @@ -3206,53 +3317,57 @@ void dispc_set_tv_pclk(struct dispc_device *dispc, unsigned long pclk) dispc->tv_pclk_rate = pclk; } -static unsigned long dispc_core_clk_rate(void) +static unsigned long dispc_core_clk_rate(struct dispc_device *dispc) { - return dispc.core_clk_rate; + return dispc->core_clk_rate; } -static unsigned long dispc_plane_pclk_rate(enum omap_plane_id plane) +static unsigned long dispc_plane_pclk_rate(struct dispc_device *dispc, + enum omap_plane_id plane) { enum omap_channel channel; if (plane == OMAP_DSS_WB) return 0; - channel = dispc_ovl_get_channel_out(plane); + channel = dispc_ovl_get_channel_out(dispc, plane); - return dispc_mgr_pclk_rate(channel); + return dispc_mgr_pclk_rate(dispc, channel); } -static unsigned long dispc_plane_lclk_rate(enum omap_plane_id plane) +static unsigned long dispc_plane_lclk_rate(struct dispc_device *dispc, + enum omap_plane_id plane) { enum omap_channel channel; if (plane == OMAP_DSS_WB) return 0; - channel = dispc_ovl_get_channel_out(plane); + channel = dispc_ovl_get_channel_out(dispc, plane); - return dispc_mgr_lclk_rate(channel); + return dispc_mgr_lclk_rate(dispc, channel); } -static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) +static void dispc_dump_clocks_channel(struct dispc_device *dispc, + struct seq_file *s, + enum omap_channel channel) { int lcd, pcd; enum dss_clk_source lcd_clk_src; seq_printf(s, "- %s -\n", mgr_desc[channel].name); - lcd_clk_src = dss_get_lcd_clk_source(dispc.dss, channel); + lcd_clk_src = dss_get_lcd_clk_source(dispc->dss, channel); seq_printf(s, "%s clk source = %s\n", mgr_desc[channel].name, dss_get_clk_source_name(lcd_clk_src)); - dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd); + dispc_mgr_get_lcd_divisor(dispc, channel, &lcd, &pcd); seq_printf(s, "lck\t\t%-16lulck div\t%u\n", - dispc_mgr_lclk_rate(channel), lcd); + dispc_mgr_lclk_rate(dispc, channel), lcd); seq_printf(s, "pck\t\t%-16lupck div\t%u\n", - dispc_mgr_pclk_rate(channel), pcd); + dispc_mgr_pclk_rate(dispc, channel), pcd); } void dispc_dump_clocks(struct dispc_device *dispc, struct seq_file *s) @@ -3270,29 +3385,30 @@ void dispc_dump_clocks(struct dispc_device *dispc, struct seq_file *s) seq_printf(s, "dispc fclk source = %s\n", dss_get_clk_source_name(dispc_clk_src)); - seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); + seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate(dispc)); - if (dispc_has_feature(FEAT_CORE_CLK_DIV)) { + if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) { seq_printf(s, "- DISPC-CORE-CLK -\n"); - l = dispc_read_reg(DISPC_DIVISOR); + l = dispc_read_reg(dispc, DISPC_DIVISOR); lcd = FLD_GET(l, 23, 16); seq_printf(s, "lck\t\t%-16lulck div\t%u\n", - (dispc_fclk_rate()/lcd), lcd); + (dispc_fclk_rate(dispc)/lcd), lcd); } - dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD); + dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD); - if (dispc_has_feature(FEAT_MGR_LCD2)) - dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD2); - if (dispc_has_feature(FEAT_MGR_LCD3)) - dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) + dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD2); + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) + dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD3); dispc_runtime_put(dispc); } static int dispc_dump_regs(struct seq_file *s, void *p) { + struct dispc_device *dispc = s->private; int i, j; const char *mgr_names[] = { [OMAP_DSS_CHANNEL_LCD] = "LCD", @@ -3309,178 +3425,179 @@ static int dispc_dump_regs(struct seq_file *s, void *p) }; const char **p_names; -#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r)) +#define DUMPREG(dispc, r) \ + seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(dispc, r)) - if (dispc_runtime_get(&dispc)) + if (dispc_runtime_get(dispc)) return 0; /* DISPC common registers */ - DUMPREG(DISPC_REVISION); - DUMPREG(DISPC_SYSCONFIG); - DUMPREG(DISPC_SYSSTATUS); - DUMPREG(DISPC_IRQSTATUS); - DUMPREG(DISPC_IRQENABLE); - DUMPREG(DISPC_CONTROL); - DUMPREG(DISPC_CONFIG); - DUMPREG(DISPC_CAPABLE); - DUMPREG(DISPC_LINE_STATUS); - DUMPREG(DISPC_LINE_NUMBER); - if (dispc_has_feature(FEAT_ALPHA_FIXED_ZORDER) || - dispc_has_feature(FEAT_ALPHA_FREE_ZORDER)) - DUMPREG(DISPC_GLOBAL_ALPHA); - if (dispc_has_feature(FEAT_MGR_LCD2)) { - DUMPREG(DISPC_CONTROL2); - DUMPREG(DISPC_CONFIG2); + DUMPREG(dispc, DISPC_REVISION); + DUMPREG(dispc, DISPC_SYSCONFIG); + DUMPREG(dispc, DISPC_SYSSTATUS); + DUMPREG(dispc, DISPC_IRQSTATUS); + DUMPREG(dispc, DISPC_IRQENABLE); + DUMPREG(dispc, DISPC_CONTROL); + DUMPREG(dispc, DISPC_CONFIG); + DUMPREG(dispc, DISPC_CAPABLE); + DUMPREG(dispc, DISPC_LINE_STATUS); + DUMPREG(dispc, DISPC_LINE_NUMBER); + if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) || + dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER)) + DUMPREG(dispc, DISPC_GLOBAL_ALPHA); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) { + DUMPREG(dispc, DISPC_CONTROL2); + DUMPREG(dispc, DISPC_CONFIG2); } - if (dispc_has_feature(FEAT_MGR_LCD3)) { - DUMPREG(DISPC_CONTROL3); - DUMPREG(DISPC_CONFIG3); + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) { + DUMPREG(dispc, DISPC_CONTROL3); + DUMPREG(dispc, DISPC_CONFIG3); } - if (dispc_has_feature(FEAT_MFLAG)) - DUMPREG(DISPC_GLOBAL_MFLAG_ATTRIBUTE); + if (dispc_has_feature(dispc, FEAT_MFLAG)) + DUMPREG(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE); #undef DUMPREG #define DISPC_REG(i, name) name(i) -#define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \ +#define DUMPREG(dispc, i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \ (int)(48 - strlen(#r) - strlen(p_names[i])), " ", \ - dispc_read_reg(DISPC_REG(i, r))) + dispc_read_reg(dispc, DISPC_REG(i, r))) p_names = mgr_names; /* DISPC channel specific registers */ - for (i = 0; i < dispc_get_num_mgrs(&dispc); i++) { - DUMPREG(i, DISPC_DEFAULT_COLOR); - DUMPREG(i, DISPC_TRANS_COLOR); - DUMPREG(i, DISPC_SIZE_MGR); + for (i = 0; i < dispc_get_num_mgrs(dispc); i++) { + DUMPREG(dispc, i, DISPC_DEFAULT_COLOR); + DUMPREG(dispc, i, DISPC_TRANS_COLOR); + DUMPREG(dispc, i, DISPC_SIZE_MGR); if (i == OMAP_DSS_CHANNEL_DIGIT) continue; - DUMPREG(i, DISPC_TIMING_H); - DUMPREG(i, DISPC_TIMING_V); - DUMPREG(i, DISPC_POL_FREQ); - DUMPREG(i, DISPC_DIVISORo); + DUMPREG(dispc, i, DISPC_TIMING_H); + DUMPREG(dispc, i, DISPC_TIMING_V); + DUMPREG(dispc, i, DISPC_POL_FREQ); + DUMPREG(dispc, i, DISPC_DIVISORo); - DUMPREG(i, DISPC_DATA_CYCLE1); - DUMPREG(i, DISPC_DATA_CYCLE2); - DUMPREG(i, DISPC_DATA_CYCLE3); + DUMPREG(dispc, i, DISPC_DATA_CYCLE1); + DUMPREG(dispc, i, DISPC_DATA_CYCLE2); + DUMPREG(dispc, i, DISPC_DATA_CYCLE3); - if (dispc_has_feature(FEAT_CPR)) { - DUMPREG(i, DISPC_CPR_COEF_R); - DUMPREG(i, DISPC_CPR_COEF_G); - DUMPREG(i, DISPC_CPR_COEF_B); + if (dispc_has_feature(dispc, FEAT_CPR)) { + DUMPREG(dispc, i, DISPC_CPR_COEF_R); + DUMPREG(dispc, i, DISPC_CPR_COEF_G); + DUMPREG(dispc, i, DISPC_CPR_COEF_B); } } p_names = ovl_names; - for (i = 0; i < dispc_get_num_ovls(&dispc); i++) { - DUMPREG(i, DISPC_OVL_BA0); - DUMPREG(i, DISPC_OVL_BA1); - DUMPREG(i, DISPC_OVL_POSITION); - DUMPREG(i, DISPC_OVL_SIZE); - DUMPREG(i, DISPC_OVL_ATTRIBUTES); - DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD); - DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS); - DUMPREG(i, DISPC_OVL_ROW_INC); - DUMPREG(i, DISPC_OVL_PIXEL_INC); - - if (dispc_has_feature(FEAT_PRELOAD)) - DUMPREG(i, DISPC_OVL_PRELOAD); - if (dispc_has_feature(FEAT_MFLAG)) - DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD); + for (i = 0; i < dispc_get_num_ovls(dispc); i++) { + DUMPREG(dispc, i, DISPC_OVL_BA0); + DUMPREG(dispc, i, DISPC_OVL_BA1); + DUMPREG(dispc, i, DISPC_OVL_POSITION); + DUMPREG(dispc, i, DISPC_OVL_SIZE); + DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES); + DUMPREG(dispc, i, DISPC_OVL_FIFO_THRESHOLD); + DUMPREG(dispc, i, DISPC_OVL_FIFO_SIZE_STATUS); + DUMPREG(dispc, i, DISPC_OVL_ROW_INC); + DUMPREG(dispc, i, DISPC_OVL_PIXEL_INC); + + if (dispc_has_feature(dispc, FEAT_PRELOAD)) + DUMPREG(dispc, i, DISPC_OVL_PRELOAD); + if (dispc_has_feature(dispc, FEAT_MFLAG)) + DUMPREG(dispc, i, DISPC_OVL_MFLAG_THRESHOLD); if (i == OMAP_DSS_GFX) { - DUMPREG(i, DISPC_OVL_WINDOW_SKIP); - DUMPREG(i, DISPC_OVL_TABLE_BA); + DUMPREG(dispc, i, DISPC_OVL_WINDOW_SKIP); + DUMPREG(dispc, i, DISPC_OVL_TABLE_BA); continue; } - DUMPREG(i, DISPC_OVL_FIR); - DUMPREG(i, DISPC_OVL_PICTURE_SIZE); - DUMPREG(i, DISPC_OVL_ACCU0); - DUMPREG(i, DISPC_OVL_ACCU1); - if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - DUMPREG(i, DISPC_OVL_BA0_UV); - DUMPREG(i, DISPC_OVL_BA1_UV); - DUMPREG(i, DISPC_OVL_FIR2); - DUMPREG(i, DISPC_OVL_ACCU2_0); - DUMPREG(i, DISPC_OVL_ACCU2_1); + DUMPREG(dispc, i, DISPC_OVL_FIR); + DUMPREG(dispc, i, DISPC_OVL_PICTURE_SIZE); + DUMPREG(dispc, i, DISPC_OVL_ACCU0); + DUMPREG(dispc, i, DISPC_OVL_ACCU1); + if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { + DUMPREG(dispc, i, DISPC_OVL_BA0_UV); + DUMPREG(dispc, i, DISPC_OVL_BA1_UV); + DUMPREG(dispc, i, DISPC_OVL_FIR2); + DUMPREG(dispc, i, DISPC_OVL_ACCU2_0); + DUMPREG(dispc, i, DISPC_OVL_ACCU2_1); } - if (dispc_has_feature(FEAT_ATTR2)) - DUMPREG(i, DISPC_OVL_ATTRIBUTES2); + if (dispc_has_feature(dispc, FEAT_ATTR2)) + DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES2); } - if (dispc.feat->has_writeback) { + if (dispc->feat->has_writeback) { i = OMAP_DSS_WB; - DUMPREG(i, DISPC_OVL_BA0); - DUMPREG(i, DISPC_OVL_BA1); - DUMPREG(i, DISPC_OVL_SIZE); - DUMPREG(i, DISPC_OVL_ATTRIBUTES); - DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD); - DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS); - DUMPREG(i, DISPC_OVL_ROW_INC); - DUMPREG(i, DISPC_OVL_PIXEL_INC); - - if (dispc_has_feature(FEAT_MFLAG)) - DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD); - - DUMPREG(i, DISPC_OVL_FIR); - DUMPREG(i, DISPC_OVL_PICTURE_SIZE); - DUMPREG(i, DISPC_OVL_ACCU0); - DUMPREG(i, DISPC_OVL_ACCU1); - if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - DUMPREG(i, DISPC_OVL_BA0_UV); - DUMPREG(i, DISPC_OVL_BA1_UV); - DUMPREG(i, DISPC_OVL_FIR2); - DUMPREG(i, DISPC_OVL_ACCU2_0); - DUMPREG(i, DISPC_OVL_ACCU2_1); + DUMPREG(dispc, i, DISPC_OVL_BA0); + DUMPREG(dispc, i, DISPC_OVL_BA1); + DUMPREG(dispc, i, DISPC_OVL_SIZE); + DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES); + DUMPREG(dispc, i, DISPC_OVL_FIFO_THRESHOLD); + DUMPREG(dispc, i, DISPC_OVL_FIFO_SIZE_STATUS); + DUMPREG(dispc, i, DISPC_OVL_ROW_INC); + DUMPREG(dispc, i, DISPC_OVL_PIXEL_INC); + + if (dispc_has_feature(dispc, FEAT_MFLAG)) + DUMPREG(dispc, i, DISPC_OVL_MFLAG_THRESHOLD); + + DUMPREG(dispc, i, DISPC_OVL_FIR); + DUMPREG(dispc, i, DISPC_OVL_PICTURE_SIZE); + DUMPREG(dispc, i, DISPC_OVL_ACCU0); + DUMPREG(dispc, i, DISPC_OVL_ACCU1); + if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { + DUMPREG(dispc, i, DISPC_OVL_BA0_UV); + DUMPREG(dispc, i, DISPC_OVL_BA1_UV); + DUMPREG(dispc, i, DISPC_OVL_FIR2); + DUMPREG(dispc, i, DISPC_OVL_ACCU2_0); + DUMPREG(dispc, i, DISPC_OVL_ACCU2_1); } - if (dispc_has_feature(FEAT_ATTR2)) - DUMPREG(i, DISPC_OVL_ATTRIBUTES2); + if (dispc_has_feature(dispc, FEAT_ATTR2)) + DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES2); } #undef DISPC_REG #undef DUMPREG #define DISPC_REG(plane, name, i) name(plane, i) -#define DUMPREG(plane, name, i) \ +#define DUMPREG(dispc, plane, name, i) \ seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \ (int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \ - dispc_read_reg(DISPC_REG(plane, name, i))) + dispc_read_reg(dispc, DISPC_REG(plane, name, i))) /* Video pipeline coefficient registers */ /* start from OMAP_DSS_VIDEO1 */ - for (i = 1; i < dispc_get_num_ovls(&dispc); i++) { + for (i = 1; i < dispc_get_num_ovls(dispc); i++) { for (j = 0; j < 8; j++) - DUMPREG(i, DISPC_OVL_FIR_COEF_H, j); + DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_H, j); for (j = 0; j < 8; j++) - DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j); + DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_HV, j); for (j = 0; j < 5; j++) - DUMPREG(i, DISPC_OVL_CONV_COEF, j); + DUMPREG(dispc, i, DISPC_OVL_CONV_COEF, j); - if (dispc_has_feature(FEAT_FIR_COEF_V)) { + if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) { for (j = 0; j < 8; j++) - DUMPREG(i, DISPC_OVL_FIR_COEF_V, j); + DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_V, j); } - if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) { + if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { for (j = 0; j < 8; j++) - DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j); + DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_H2, j); for (j = 0; j < 8; j++) - DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j); + DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_HV2, j); for (j = 0; j < 8; j++) - DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j); + DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_V2, j); } } - dispc_runtime_put(&dispc); + dispc_runtime_put(dispc); #undef DISPC_REG #undef DUMPREG @@ -3548,8 +3665,8 @@ bool dispc_div_calc(struct dispc_device *dispc, unsigned long dispc_freq, * also. Thus we need to use the calculated lck. For * OMAP4+ the DISPC fclk is a separate clock. */ - if (dispc_has_feature(FEAT_CORE_CLK_DIV)) - fck = dispc_core_clk_rate(); + if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) + fck = dispc_core_clk_rate(dispc); else fck = lck; @@ -3571,7 +3688,8 @@ void dispc_mgr_set_clock_div(struct dispc_device *dispc, DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); - dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div); + dispc_mgr_set_lcd_divisor(dispc, channel, cinfo->lck_div, + cinfo->pck_div); } int dispc_mgr_get_clock_div(struct dispc_device *dispc, @@ -3580,10 +3698,10 @@ int dispc_mgr_get_clock_div(struct dispc_device *dispc, { unsigned long fck; - fck = dispc_fclk_rate(); + fck = dispc_fclk_rate(dispc); - cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16); - cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0); + cinfo->lck_div = REG_GET(dispc, DISPC_DIVISORo(channel), 23, 16); + cinfo->pck_div = REG_GET(dispc, DISPC_DIVISORo(channel), 7, 0); cinfo->lck = fck / cinfo->lck_div; cinfo->pck = cinfo->lck / cinfo->pck_div; @@ -3593,35 +3711,36 @@ int dispc_mgr_get_clock_div(struct dispc_device *dispc, static u32 dispc_read_irqstatus(struct dispc_device *dispc) { - return dispc_read_reg(DISPC_IRQSTATUS); + return dispc_read_reg(dispc, DISPC_IRQSTATUS); } static void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask) { - dispc_write_reg(DISPC_IRQSTATUS, mask); + dispc_write_reg(dispc, DISPC_IRQSTATUS, mask); } static void dispc_write_irqenable(struct dispc_device *dispc, u32 mask) { - u32 old_mask = dispc_read_reg(DISPC_IRQENABLE); + u32 old_mask = dispc_read_reg(dispc, DISPC_IRQENABLE); /* clear the irqstatus for newly enabled irqs */ dispc_clear_irqstatus(dispc, (mask ^ old_mask) & mask); - dispc_write_reg(DISPC_IRQENABLE, mask); + dispc_write_reg(dispc, DISPC_IRQENABLE, mask); /* flush posted write */ - dispc_read_reg(DISPC_IRQENABLE); + dispc_read_reg(dispc, DISPC_IRQENABLE); } void dispc_enable_sidle(struct dispc_device *dispc) { - REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */ + /* SIDLEMODE: smart idle */ + REG_FLD_MOD(dispc, DISPC_SYSCONFIG, 2, 4, 3); } void dispc_disable_sidle(struct dispc_device *dispc) { - REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ + REG_FLD_MOD(dispc, DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ } static u32 dispc_mgr_gamma_size(struct dispc_device *dispc, @@ -3635,10 +3754,11 @@ static u32 dispc_mgr_gamma_size(struct dispc_device *dispc, return gdesc->len; } -static void dispc_mgr_write_gamma_table(enum omap_channel channel) +static void dispc_mgr_write_gamma_table(struct dispc_device *dispc, + enum omap_channel channel) { const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; - u32 *table = dispc.gamma_table[channel]; + u32 *table = dispc->gamma_table[channel]; unsigned int i; DSSDBG("%s: channel %d\n", __func__, channel); @@ -3651,26 +3771,26 @@ static void dispc_mgr_write_gamma_table(enum omap_channel channel) else if (i == 0) v |= 1 << 31; - dispc_write_reg(gdesc->reg, v); + dispc_write_reg(dispc, gdesc->reg, v); } } -static void dispc_restore_gamma_tables(void) +static void dispc_restore_gamma_tables(struct dispc_device *dispc) { DSSDBG("%s()\n", __func__); - if (!dispc.feat->has_gamma_table) + if (!dispc->feat->has_gamma_table) return; - dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD); + dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD); - dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_DIGIT); + dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_DIGIT); - if (dispc_has_feature(FEAT_MGR_LCD2)) - dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD2); + if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) + dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD2); - if (dispc_has_feature(FEAT_MGR_LCD3)) - dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD3); + if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) + dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD3); } static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = { @@ -3723,81 +3843,82 @@ static void dispc_mgr_set_gamma(struct dispc_device *dispc, } if (dispc->is_enabled) - dispc_mgr_write_gamma_table(channel); + dispc_mgr_write_gamma_table(dispc, channel); } -static int dispc_init_gamma_tables(void) +static int dispc_init_gamma_tables(struct dispc_device *dispc) { int channel; - if (!dispc.feat->has_gamma_table) + if (!dispc->feat->has_gamma_table) return 0; - for (channel = 0; channel < ARRAY_SIZE(dispc.gamma_table); channel++) { + for (channel = 0; channel < ARRAY_SIZE(dispc->gamma_table); channel++) { const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; u32 *gt; if (channel == OMAP_DSS_CHANNEL_LCD2 && - !dispc_has_feature(FEAT_MGR_LCD2)) + !dispc_has_feature(dispc, FEAT_MGR_LCD2)) continue; if (channel == OMAP_DSS_CHANNEL_LCD3 && - !dispc_has_feature(FEAT_MGR_LCD3)) + !dispc_has_feature(dispc, FEAT_MGR_LCD3)) continue; - gt = devm_kmalloc_array(&dispc.pdev->dev, gdesc->len, - sizeof(u32), GFP_KERNEL); + gt = devm_kmalloc_array(&dispc->pdev->dev, gdesc->len, + sizeof(u32), GFP_KERNEL); if (!gt) return -ENOMEM; - dispc.gamma_table[channel] = gt; + dispc->gamma_table[channel] = gt; - dispc_mgr_set_gamma(&dispc, channel, NULL, 0); + dispc_mgr_set_gamma(dispc, channel, NULL, 0); } return 0; } -static void _omap_dispc_initial_config(void) +static void _omap_dispc_initial_config(struct dispc_device *dispc) { u32 l; /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */ - if (dispc_has_feature(FEAT_CORE_CLK_DIV)) { - l = dispc_read_reg(DISPC_DIVISOR); + if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) { + l = dispc_read_reg(dispc, DISPC_DIVISOR); /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */ l = FLD_MOD(l, 1, 0, 0); l = FLD_MOD(l, 1, 23, 16); - dispc_write_reg(DISPC_DIVISOR, l); + dispc_write_reg(dispc, DISPC_DIVISOR, l); - dispc.core_clk_rate = dispc_fclk_rate(); + dispc->core_clk_rate = dispc_fclk_rate(dispc); } /* Use gamma table mode, instead of palette mode */ - if (dispc.feat->has_gamma_table) - REG_FLD_MOD(DISPC_CONFIG, 1, 3, 3); + if (dispc->feat->has_gamma_table) + REG_FLD_MOD(dispc, DISPC_CONFIG, 1, 3, 3); /* For older DSS versions (FEAT_FUNCGATED) this enables * func-clock auto-gating. For newer versions - * (dispc.feat->has_gamma_table) this enables tv-out gamma tables. + * (dispc->feat->has_gamma_table) this enables tv-out gamma tables. */ - if (dispc_has_feature(FEAT_FUNCGATED) || dispc.feat->has_gamma_table) - REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); + if (dispc_has_feature(dispc, FEAT_FUNCGATED) || + dispc->feat->has_gamma_table) + REG_FLD_MOD(dispc, DISPC_CONFIG, 1, 9, 9); - dispc_setup_color_conv_coef(); + dispc_setup_color_conv_coef(dispc); - dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); + dispc_set_loadmode(dispc, OMAP_DSS_LOAD_FRAME_ONLY); - dispc_init_fifos(); + dispc_init_fifos(dispc); - dispc_configure_burst_sizes(); + dispc_configure_burst_sizes(dispc); - dispc_ovl_enable_zorder_planes(); + dispc_ovl_enable_zorder_planes(dispc); - if (dispc.feat->mstandby_workaround) - REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0); + if (dispc->feat->mstandby_workaround) + REG_FLD_MOD(dispc, DISPC_MSTANDBY_CTRL, 1, 0, 0); - if (dispc_has_feature(FEAT_MFLAG)) - dispc_init_mflag(); + if (dispc_has_feature(dispc, FEAT_MFLAG)) + dispc_init_mflag(dispc); } static const enum dispc_feature_id omap2_dispc_features_list[] = { @@ -4316,10 +4437,12 @@ static const struct dispc_features omap54xx_dispc_feats = { static irqreturn_t dispc_irq_handler(int irq, void *arg) { - if (!dispc.is_enabled) + struct dispc_device *dispc = arg; + + if (!dispc->is_enabled) return IRQ_NONE; - return dispc.user_handler(irq, dispc.user_data); + return dispc->user_handler(irq, dispc->user_data); } static int dispc_request_irq(struct dispc_device *dispc, irq_handler_t handler, @@ -4436,18 +4559,19 @@ static struct i734_buf { void *vaddr; } i734_buf; -static int dispc_errata_i734_wa_init(void) +static int dispc_errata_i734_wa_init(struct dispc_device *dispc) { - if (!dispc.feat->has_gamma_i734_bug) + if (!dispc->feat->has_gamma_i734_bug) return 0; i734_buf.size = i734.ovli.width * i734.ovli.height * color_mode_to_bpp(i734.ovli.fourcc) / 8; - i734_buf.vaddr = dma_alloc_writecombine(&dispc.pdev->dev, i734_buf.size, - &i734_buf.paddr, GFP_KERNEL); + i734_buf.vaddr = dma_alloc_writecombine(&dispc->pdev->dev, + i734_buf.size, &i734_buf.paddr, + GFP_KERNEL); if (!i734_buf.vaddr) { - dev_err(&dispc.pdev->dev, "%s: dma_alloc_writecombine failed", + dev_err(&dispc->pdev->dev, "%s: dma_alloc_writecombine failed", __func__); return -ENOMEM; } @@ -4455,73 +4579,73 @@ static int dispc_errata_i734_wa_init(void) return 0; } -static void dispc_errata_i734_wa_fini(void) +static void dispc_errata_i734_wa_fini(struct dispc_device *dispc) { - if (!dispc.feat->has_gamma_i734_bug) + if (!dispc->feat->has_gamma_i734_bug) return; - dma_free_writecombine(&dispc.pdev->dev, i734_buf.size, i734_buf.vaddr, + dma_free_writecombine(&dispc->pdev->dev, i734_buf.size, i734_buf.vaddr, i734_buf.paddr); } -static void dispc_errata_i734_wa(void) +static void dispc_errata_i734_wa(struct dispc_device *dispc) { - u32 framedone_irq = dispc_mgr_get_framedone_irq(&dispc, + u32 framedone_irq = dispc_mgr_get_framedone_irq(dispc, OMAP_DSS_CHANNEL_LCD); struct omap_overlay_info ovli; struct dss_lcd_mgr_config lcd_conf; u32 gatestate; unsigned int count; - if (!dispc.feat->has_gamma_i734_bug) + if (!dispc->feat->has_gamma_i734_bug) return; - gatestate = REG_GET(DISPC_CONFIG, 8, 4); + gatestate = REG_GET(dispc, DISPC_CONFIG, 8, 4); ovli = i734.ovli; ovli.paddr = i734_buf.paddr; lcd_conf = i734.lcd_conf; /* Gate all LCD1 outputs */ - REG_FLD_MOD(DISPC_CONFIG, 0x1f, 8, 4); + REG_FLD_MOD(dispc, DISPC_CONFIG, 0x1f, 8, 4); /* Setup and enable GFX plane */ - dispc_ovl_setup(&dispc, OMAP_DSS_GFX, &ovli, &i734.vm, false, + dispc_ovl_setup(dispc, OMAP_DSS_GFX, &ovli, &i734.vm, false, OMAP_DSS_CHANNEL_LCD); - dispc_ovl_enable(&dispc, OMAP_DSS_GFX, true); + dispc_ovl_enable(dispc, OMAP_DSS_GFX, true); /* Set up and enable display manager for LCD1 */ - dispc_mgr_setup(&dispc, OMAP_DSS_CHANNEL_LCD, &i734.mgri); - dispc_calc_clock_rates(&dispc, dss_get_dispc_clk_rate(dispc.dss), + dispc_mgr_setup(dispc, OMAP_DSS_CHANNEL_LCD, &i734.mgri); + dispc_calc_clock_rates(dispc, dss_get_dispc_clk_rate(dispc->dss), &lcd_conf.clock_info); - dispc_mgr_set_lcd_config(&dispc, OMAP_DSS_CHANNEL_LCD, &lcd_conf); - dispc_mgr_set_timings(&dispc, OMAP_DSS_CHANNEL_LCD, &i734.vm); + dispc_mgr_set_lcd_config(dispc, OMAP_DSS_CHANNEL_LCD, &lcd_conf); + dispc_mgr_set_timings(dispc, OMAP_DSS_CHANNEL_LCD, &i734.vm); - dispc_clear_irqstatus(&dispc, framedone_irq); + dispc_clear_irqstatus(dispc, framedone_irq); /* Enable and shut the channel to produce just one frame */ - dispc_mgr_enable(&dispc, OMAP_DSS_CHANNEL_LCD, true); - dispc_mgr_enable(&dispc, OMAP_DSS_CHANNEL_LCD, false); + dispc_mgr_enable(dispc, OMAP_DSS_CHANNEL_LCD, true); + dispc_mgr_enable(dispc, OMAP_DSS_CHANNEL_LCD, false); /* Busy wait for framedone. We can't fiddle with irq handlers * in PM resume. Typically the loop runs less than 5 times and * waits less than a micro second. */ count = 0; - while (!(dispc_read_irqstatus(&dispc) & framedone_irq)) { + while (!(dispc_read_irqstatus(dispc) & framedone_irq)) { if (count++ > 10000) { - dev_err(&dispc.pdev->dev, "%s: framedone timeout\n", + dev_err(&dispc->pdev->dev, "%s: framedone timeout\n", __func__); break; } } - dispc_ovl_enable(&dispc, OMAP_DSS_GFX, false); + dispc_ovl_enable(dispc, OMAP_DSS_GFX, false); /* Clear all irq bits before continuing */ - dispc_clear_irqstatus(&dispc, 0xffffffff); + dispc_clear_irqstatus(dispc, 0xffffffff); /* Restore the original state to LCD1 output gates */ - REG_FLD_MOD(DISPC_CONFIG, gatestate, 8, 4); + REG_FLD_MOD(dispc, DISPC_CONFIG, gatestate, 8, 4); } static const struct dispc_ops dispc_ops = { @@ -4583,15 +4707,21 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) struct platform_device *pdev = to_platform_device(dev); const struct soc_device_attribute *soc; struct dss_device *dss = dss_get_device(master); + struct dispc_device *dispc; u32 rev; int r = 0; struct resource *dispc_mem; struct device_node *np = pdev->dev.of_node; - dispc.pdev = pdev; - dispc.dss = dss; + dispc = kzalloc(sizeof(*dispc), GFP_KERNEL); + if (!dispc) + return -ENOMEM; + + dispc->pdev = pdev; + platform_set_drvdata(pdev, dispc); + dispc->dss = dss; - spin_lock_init(&dispc.control_lock); + spin_lock_init(&dispc->control_lock); /* * The OMAP3-based models can't be told apart using the compatible @@ -4599,82 +4729,92 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) */ soc = soc_device_match(dispc_soc_devices); if (soc) - dispc.feat = soc->data; + dispc->feat = soc->data; else - dispc.feat = of_match_device(dispc_of_match, &pdev->dev)->data; + dispc->feat = of_match_device(dispc_of_match, &pdev->dev)->data; - r = dispc_errata_i734_wa_init(); + r = dispc_errata_i734_wa_init(dispc); if (r) - return r; + goto err_free; - dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); - dispc.base = devm_ioremap_resource(&pdev->dev, dispc_mem); - if (IS_ERR(dispc.base)) - return PTR_ERR(dispc.base); + dispc_mem = platform_get_resource(dispc->pdev, IORESOURCE_MEM, 0); + dispc->base = devm_ioremap_resource(&pdev->dev, dispc_mem); + if (IS_ERR(dispc->base)) { + r = PTR_ERR(dispc->base); + goto err_free; + } - dispc.irq = platform_get_irq(dispc.pdev, 0); - if (dispc.irq < 0) { + dispc->irq = platform_get_irq(dispc->pdev, 0); + if (dispc->irq < 0) { DSSERR("platform_get_irq failed\n"); - return -ENODEV; + r = -ENODEV; + goto err_free; } if (np && of_property_read_bool(np, "syscon-pol")) { - dispc.syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol"); - if (IS_ERR(dispc.syscon_pol)) { + dispc->syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol"); + if (IS_ERR(dispc->syscon_pol)) { dev_err(&pdev->dev, "failed to get syscon-pol regmap\n"); - return PTR_ERR(dispc.syscon_pol); + r = PTR_ERR(dispc->syscon_pol); + goto err_free; } if (of_property_read_u32_index(np, "syscon-pol", 1, - &dispc.syscon_pol_offset)) { + &dispc->syscon_pol_offset)) { dev_err(&pdev->dev, "failed to get syscon-pol offset\n"); - return -EINVAL; + r = -EINVAL; + goto err_free; } } - r = dispc_init_gamma_tables(); + r = dispc_init_gamma_tables(dispc); if (r) - return r; + goto err_free; pm_runtime_enable(&pdev->dev); - r = dispc_runtime_get(&dispc); + r = dispc_runtime_get(dispc); if (r) goto err_runtime_get; - _omap_dispc_initial_config(); + _omap_dispc_initial_config(dispc); - rev = dispc_read_reg(DISPC_REVISION); + rev = dispc_read_reg(dispc, DISPC_REVISION); dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - dispc_runtime_put(&dispc); + dispc_runtime_put(dispc); - dss->dispc = &dispc; + dss->dispc = dispc; dss->dispc_ops = &dispc_ops; - dispc.debugfs = dss_debugfs_create_file(dss, "dispc", dispc_dump_regs, - &dispc); + dispc->debugfs = dss_debugfs_create_file(dss, "dispc", dispc_dump_regs, + dispc); return 0; err_runtime_get: pm_runtime_disable(&pdev->dev); +err_free: + kfree(dispc); return r; } static void dispc_unbind(struct device *dev, struct device *master, void *data) { - struct dss_device *dss = dispc.dss; + struct dispc_device *dispc = dev_get_drvdata(dev); + struct dss_device *dss = dispc->dss; - dss_debugfs_remove_file(dispc.debugfs); + dss_debugfs_remove_file(dispc->debugfs); dss->dispc = NULL; dss->dispc_ops = NULL; pm_runtime_disable(dev); - dispc_errata_i734_wa_fini(); + dispc_errata_i734_wa_fini(dispc); + + kfree(dispc); } static const struct component_ops dispc_component_ops = { @@ -4695,36 +4835,40 @@ static int dispc_remove(struct platform_device *pdev) static int dispc_runtime_suspend(struct device *dev) { - dispc.is_enabled = false; + struct dispc_device *dispc = dev_get_drvdata(dev); + + dispc->is_enabled = false; /* ensure the dispc_irq_handler sees the is_enabled value */ smp_wmb(); /* wait for current handler to finish before turning the DISPC off */ - synchronize_irq(dispc.irq); + synchronize_irq(dispc->irq); - dispc_save_context(); + dispc_save_context(dispc); return 0; } static int dispc_runtime_resume(struct device *dev) { + struct dispc_device *dispc = dev_get_drvdata(dev); + /* * The reset value for load mode is 0 (OMAP_DSS_LOAD_CLUT_AND_FRAME) * but we always initialize it to 2 (OMAP_DSS_LOAD_FRAME_ONLY) in * _omap_dispc_initial_config(). We can thus use it to detect if * we have lost register context. */ - if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) { - _omap_dispc_initial_config(); + if (REG_GET(dispc, DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) { + _omap_dispc_initial_config(dispc); - dispc_errata_i734_wa(); + dispc_errata_i734_wa(dispc); - dispc_restore_context(); + dispc_restore_context(dispc); - dispc_restore_gamma_tables(); + dispc_restore_gamma_tables(dispc); } - dispc.is_enabled = true; + dispc->is_enabled = true; /* ensure the dispc_irq_handler sees the is_enabled value */ smp_wmb(); -- cgit v1.2.3 From ac7674567c6204185d31aca828f9d1e6ad64f40b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:45 +0200 Subject: drm: omapdrm: hdmi4: Allocate the omap_hdmi data structure dynamically The omap_hdmi private data structure is currently stored as a global variable. While no platform with multiple HDMI4 encoders currently exists nor is planned, this doesn't comply with the kernel device model and should thus be fixed. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/hdmi.h | 2 + drivers/gpu/drm/omapdrm/dss/hdmi4.c | 356 +++++++++++++++++-------------- drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c | 4 +- drivers/gpu/drm/omapdrm/dss/hdmi4_core.h | 4 +- 4 files changed, 200 insertions(+), 166 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h index fa2fbdaa427c..3aeb4cabd59f 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h @@ -389,4 +389,6 @@ struct omap_hdmi { bool display_enabled; }; +#define dssdev_to_hdmi(dssdev) container_of(dssdev, struct omap_hdmi, output) + #endif diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 815865c09ac1..1f7897c58f2f 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -45,15 +45,13 @@ #include "dss.h" #include "hdmi.h" -static struct omap_hdmi hdmi; - -static int hdmi_runtime_get(void) +static int hdmi_runtime_get(struct omap_hdmi *hdmi) { int r; DSSDBG("hdmi_runtime_get\n"); - r = pm_runtime_get_sync(&hdmi.pdev->dev); + r = pm_runtime_get_sync(&hdmi->pdev->dev); WARN_ON(r < 0); if (r < 0) return r; @@ -61,13 +59,13 @@ static int hdmi_runtime_get(void) return 0; } -static void hdmi_runtime_put(void) +static void hdmi_runtime_put(struct omap_hdmi *hdmi) { int r; DSSDBG("hdmi_runtime_put\n"); - r = pm_runtime_put_sync(&hdmi.pdev->dev); + r = pm_runtime_put_sync(&hdmi->pdev->dev); WARN_ON(r < 0 && r != -ENOSYS); } @@ -110,14 +108,14 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static int hdmi_init_regulator(void) +static int hdmi_init_regulator(struct omap_hdmi *hdmi) { struct regulator *reg; - if (hdmi.vdda_reg != NULL) + if (hdmi->vdda_reg != NULL) return 0; - reg = devm_regulator_get(&hdmi.pdev->dev, "vdda"); + reg = devm_regulator_get(&hdmi->pdev->dev, "vdda"); if (IS_ERR(reg)) { if (PTR_ERR(reg) != -EPROBE_DEFER) @@ -125,63 +123,63 @@ static int hdmi_init_regulator(void) return PTR_ERR(reg); } - hdmi.vdda_reg = reg; + hdmi->vdda_reg = reg; return 0; } -static int hdmi_power_on_core(struct omap_dss_device *dssdev) +static int hdmi_power_on_core(struct omap_hdmi *hdmi) { int r; - if (hdmi.core.core_pwr_cnt++) + if (hdmi->core.core_pwr_cnt++) return 0; - r = regulator_enable(hdmi.vdda_reg); + r = regulator_enable(hdmi->vdda_reg); if (r) goto err_reg_enable; - r = hdmi_runtime_get(); + r = hdmi_runtime_get(hdmi); if (r) goto err_runtime_get; - hdmi4_core_powerdown_disable(&hdmi.core); + hdmi4_core_powerdown_disable(&hdmi->core); /* Make selection of HDMI in DSS */ - dss_select_hdmi_venc_clk_source(hdmi.dss, DSS_HDMI_M_PCLK); + dss_select_hdmi_venc_clk_source(hdmi->dss, DSS_HDMI_M_PCLK); - hdmi.core_enabled = true; + hdmi->core_enabled = true; return 0; err_runtime_get: - regulator_disable(hdmi.vdda_reg); + regulator_disable(hdmi->vdda_reg); err_reg_enable: - hdmi.core.core_pwr_cnt--; + hdmi->core.core_pwr_cnt--; return r; } -static void hdmi_power_off_core(struct omap_dss_device *dssdev) +static void hdmi_power_off_core(struct omap_hdmi *hdmi) { - if (--hdmi.core.core_pwr_cnt) + if (--hdmi->core.core_pwr_cnt) return; - hdmi.core_enabled = false; + hdmi->core_enabled = false; - hdmi_runtime_put(); - regulator_disable(hdmi.vdda_reg); + hdmi_runtime_put(hdmi); + regulator_disable(hdmi->vdda_reg); } -static int hdmi_power_on_full(struct omap_dss_device *dssdev) +static int hdmi_power_on_full(struct omap_hdmi *hdmi) { int r; struct videomode *vm; - struct hdmi_wp_data *wp = &hdmi.wp; + struct hdmi_wp_data *wp = &hdmi->wp; struct dss_pll_clock_info hdmi_cinfo = { 0 }; unsigned int pc; - r = hdmi_power_on_core(dssdev); + r = hdmi_power_on_core(hdmi); if (r) return r; @@ -189,7 +187,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) hdmi_wp_clear_irqenable(wp, ~HDMI_IRQ_CORE); hdmi_wp_set_irqstatus(wp, ~HDMI_IRQ_CORE); - vm = &hdmi.cfg.vm; + vm = &hdmi->cfg.vm; DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive, vm->vactive); @@ -201,22 +199,22 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) /* DSS_HDMI_TCLK is bitclk / 10 */ pc *= 10; - dss_pll_calc_b(&hdmi.pll.pll, clk_get_rate(hdmi.pll.pll.clkin), + dss_pll_calc_b(&hdmi->pll.pll, clk_get_rate(hdmi->pll.pll.clkin), pc, &hdmi_cinfo); - r = dss_pll_enable(&hdmi.pll.pll); + r = dss_pll_enable(&hdmi->pll.pll); if (r) { DSSERR("Failed to enable PLL\n"); goto err_pll_enable; } - r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo); + r = dss_pll_set_config(&hdmi->pll.pll, &hdmi_cinfo); if (r) { DSSERR("Failed to configure PLL\n"); goto err_pll_cfg; } - r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco, + r = hdmi_phy_configure(&hdmi->phy, hdmi_cinfo.clkdco, hdmi_cinfo.clkout[0]); if (r) { DSSDBG("Failed to configure PHY\n"); @@ -227,16 +225,16 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) if (r) goto err_phy_pwr; - hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); + hdmi4_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg); /* tv size */ - dss_mgr_set_timings(&hdmi.output, vm); + dss_mgr_set_timings(&hdmi->output, vm); - r = dss_mgr_enable(&hdmi.output); + r = dss_mgr_enable(&hdmi->output); if (r) goto err_mgr_enable; - r = hdmi_wp_video_start(&hdmi.wp); + r = hdmi_wp_video_start(&hdmi->wp); if (r) goto err_vid_enable; @@ -246,37 +244,39 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) return 0; err_vid_enable: - dss_mgr_disable(&hdmi.output); + dss_mgr_disable(&hdmi->output); err_mgr_enable: - hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); + hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF); err_phy_pwr: err_phy_cfg: err_pll_cfg: - dss_pll_disable(&hdmi.pll.pll); + dss_pll_disable(&hdmi->pll.pll); err_pll_enable: - hdmi_power_off_core(dssdev); + hdmi_power_off_core(hdmi); return -EIO; } -static void hdmi_power_off_full(struct omap_dss_device *dssdev) +static void hdmi_power_off_full(struct omap_hdmi *hdmi) { - hdmi_wp_clear_irqenable(&hdmi.wp, ~HDMI_IRQ_CORE); + hdmi_wp_clear_irqenable(&hdmi->wp, ~HDMI_IRQ_CORE); - hdmi_wp_video_stop(&hdmi.wp); + hdmi_wp_video_stop(&hdmi->wp); - dss_mgr_disable(&hdmi.output); + dss_mgr_disable(&hdmi->output); - hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); + hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF); - dss_pll_disable(&hdmi.pll.pll); + dss_pll_disable(&hdmi->pll.pll); - hdmi_power_off_core(dssdev); + hdmi_power_off_core(hdmi); } static int hdmi_display_check_timing(struct omap_dss_device *dssdev, struct videomode *vm) { - if (!dispc_mgr_timings_ok(hdmi.dss->dispc, dssdev->dispc_channel, vm)) + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + if (!dispc_mgr_timings_ok(hdmi->dss->dispc, dssdev->dispc_channel, vm)) return -EINVAL; return 0; @@ -285,53 +285,59 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev, static void hdmi_display_set_timing(struct omap_dss_device *dssdev, struct videomode *vm) { - mutex_lock(&hdmi.lock); + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + mutex_lock(&hdmi->lock); - hdmi.cfg.vm = *vm; + hdmi->cfg.vm = *vm; - dispc_set_tv_pclk(hdmi.dss->dispc, vm->pixelclock); + dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); } static void hdmi_display_get_timings(struct omap_dss_device *dssdev, struct videomode *vm) { - *vm = hdmi.cfg.vm; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + *vm = hdmi->cfg.vm; } static int hdmi_dump_regs(struct seq_file *s, void *p) { - mutex_lock(&hdmi.lock); + struct omap_hdmi *hdmi = s->private; + + mutex_lock(&hdmi->lock); - if (hdmi_runtime_get()) { - mutex_unlock(&hdmi.lock); + if (hdmi_runtime_get(hdmi)) { + mutex_unlock(&hdmi->lock); return 0; } - hdmi_wp_dump(&hdmi.wp, s); - hdmi_pll_dump(&hdmi.pll, s); - hdmi_phy_dump(&hdmi.phy, s); - hdmi4_core_dump(&hdmi.core, s); + hdmi_wp_dump(&hdmi->wp, s); + hdmi_pll_dump(&hdmi->pll, s); + hdmi_phy_dump(&hdmi->phy, s); + hdmi4_core_dump(&hdmi->core, s); - hdmi_runtime_put(); - mutex_unlock(&hdmi.lock); + hdmi_runtime_put(hdmi); + mutex_unlock(&hdmi->lock); return 0; } -static int read_edid(u8 *buf, int len) +static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len) { int r; - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - r = hdmi_runtime_get(); + r = hdmi_runtime_get(hdmi); BUG_ON(r); - r = hdmi4_read_edid(&hdmi.core, buf, len); + r = hdmi4_read_edid(&hdmi->core, buf, len); - hdmi_runtime_put(); - mutex_unlock(&hdmi.lock); + hdmi_runtime_put(hdmi); + mutex_unlock(&hdmi->lock); return r; } @@ -350,111 +356,117 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd) static int hdmi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_device *out = &hdmi.output; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); unsigned long flags; int r = 0; DSSDBG("ENTER hdmi_display_enable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - if (!out->dispc_channel_connected) { + if (!dssdev->dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err0; } - r = hdmi_power_on_full(dssdev); + r = hdmi_power_on_full(hdmi); if (r) { DSSERR("failed to power on device\n"); goto err0; } - if (hdmi.audio_configured) { - r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config, - hdmi.cfg.vm.pixelclock); + if (hdmi->audio_configured) { + r = hdmi4_audio_config(&hdmi->core, &hdmi->wp, + &hdmi->audio_config, + hdmi->cfg.vm.pixelclock); if (r) { DSSERR("Error restoring audio configuration: %d", r); - hdmi.audio_abort_cb(&hdmi.pdev->dev); - hdmi.audio_configured = false; + hdmi->audio_abort_cb(&hdmi->pdev->dev); + hdmi->audio_configured = false; } } - spin_lock_irqsave(&hdmi.audio_playing_lock, flags); - if (hdmi.audio_configured && hdmi.audio_playing) - hdmi_start_audio_stream(&hdmi); - hdmi.display_enabled = true; - spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags); + spin_lock_irqsave(&hdmi->audio_playing_lock, flags); + if (hdmi->audio_configured && hdmi->audio_playing) + hdmi_start_audio_stream(hdmi); + hdmi->display_enabled = true; + spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return 0; err0: - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return r; } static void hdmi_display_disable(struct omap_dss_device *dssdev) { + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); unsigned long flags; DSSDBG("Enter hdmi_display_disable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - spin_lock_irqsave(&hdmi.audio_playing_lock, flags); - hdmi_stop_audio_stream(&hdmi); - hdmi.display_enabled = false; - spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags); + spin_lock_irqsave(&hdmi->audio_playing_lock, flags); + hdmi_stop_audio_stream(hdmi); + hdmi->display_enabled = false; + spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); - hdmi_power_off_full(dssdev); + hdmi_power_off_full(hdmi); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); } -int hdmi4_core_enable(struct omap_dss_device *dssdev) +int hdmi4_core_enable(struct hdmi_core_data *core) { + struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); int r = 0; DSSDBG("ENTER omapdss_hdmi4_core_enable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - r = hdmi_power_on_core(dssdev); + r = hdmi_power_on_core(hdmi); if (r) { DSSERR("failed to power on device\n"); goto err0; } - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return 0; err0: - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return r; } -void hdmi4_core_disable(struct omap_dss_device *dssdev) +void hdmi4_core_disable(struct hdmi_core_data *core) { + struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core); + DSSDBG("Enter omapdss_hdmi4_core_disable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - hdmi_power_off_core(dssdev); + hdmi_power_off_core(hdmi); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); } static int hdmi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); int r; - r = hdmi_init_regulator(); + r = hdmi_init_regulator(hdmi); if (r) return r; - r = dss_mgr_connect(&hdmi.output, dssdev); + r = dss_mgr_connect(&hdmi->output, dssdev); if (r) return r; @@ -462,7 +474,7 @@ static int hdmi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(&hdmi.output, dssdev); + dss_mgr_disconnect(&hdmi->output, dssdev); return r; } @@ -472,6 +484,8 @@ static int hdmi_connect(struct omap_dss_device *dssdev, static void hdmi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -479,51 +493,58 @@ static void hdmi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(&hdmi.output, dssdev); + dss_mgr_disconnect(&hdmi->output, dssdev); } static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *edid, int len) { + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); bool need_enable; int r; - need_enable = hdmi.core_enabled == false; + need_enable = hdmi->core_enabled == false; if (need_enable) { - r = hdmi4_core_enable(dssdev); + r = hdmi4_core_enable(&hdmi->core); if (r) return r; } - r = read_edid(edid, len); + r = read_edid(hdmi, edid, len); if (r >= 256) - hdmi4_cec_set_phys_addr(&hdmi.core, + hdmi4_cec_set_phys_addr(&hdmi->core, cec_get_edid_phys_addr(edid, r, NULL)); else - hdmi4_cec_set_phys_addr(&hdmi.core, CEC_PHYS_ADDR_INVALID); + hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID); if (need_enable) - hdmi4_core_disable(dssdev); + hdmi4_core_disable(&hdmi->core); return r; } static void hdmi_lost_hotplug(struct omap_dss_device *dssdev) { - hdmi4_cec_set_phys_addr(&hdmi.core, CEC_PHYS_ADDR_INVALID); + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID); } static int hdmi_set_infoframe(struct omap_dss_device *dssdev, const struct hdmi_avi_infoframe *avi) { - hdmi.cfg.infoframe = *avi; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + hdmi->cfg.infoframe = *avi; return 0; } static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode) { - hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; return 0; } @@ -544,11 +565,11 @@ static const struct omapdss_hdmi_ops hdmi_ops = { .set_hdmi_mode = hdmi_set_hdmi_mode, }; -static void hdmi_init_output(struct platform_device *pdev) +static void hdmi_init_output(struct omap_hdmi *hdmi) { - struct omap_dss_device *out = &hdmi.output; + struct omap_dss_device *out = &hdmi->output; - out->dev = &pdev->dev; + out->dev = &hdmi->pdev->dev; out->id = OMAP_DSS_OUTPUT_HDMI; out->output_type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; @@ -559,15 +580,16 @@ static void hdmi_init_output(struct platform_device *pdev) omapdss_register_output(out); } -static void hdmi_uninit_output(struct platform_device *pdev) +static void hdmi_uninit_output(struct omap_hdmi *hdmi) { - struct omap_dss_device *out = &hdmi.output; + struct omap_dss_device *out = &hdmi->output; omapdss_unregister_output(out); } -static int hdmi_probe_of(struct platform_device *pdev) +static int hdmi_probe_of(struct omap_hdmi *hdmi) { + struct platform_device *pdev = hdmi->pdev; struct device_node *node = pdev->dev.of_node; struct device_node *ep; int r; @@ -576,7 +598,7 @@ static int hdmi_probe_of(struct platform_device *pdev) if (!ep) return 0; - r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy); + r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy); if (r) goto err; @@ -689,21 +711,21 @@ static const struct omap_hdmi_audio_ops hdmi_audio_ops = { .audio_config = hdmi_audio_config, }; -static int hdmi_audio_register(struct device *dev) +static int hdmi_audio_register(struct omap_hdmi *hdmi) { struct omap_hdmi_audio_pdata pdata = { - .dev = dev, + .dev = &hdmi->pdev->dev, .version = 4, - .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp), + .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp), .ops = &hdmi_audio_ops, }; - hdmi.audio_pdev = platform_device_register_data( - dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, + hdmi->audio_pdev = platform_device_register_data( + &hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, &pdata, sizeof(pdata)); - if (IS_ERR(hdmi.audio_pdev)) - return PTR_ERR(hdmi.audio_pdev); + if (IS_ERR(hdmi->audio_pdev)) + return PTR_ERR(hdmi->audio_pdev); return 0; } @@ -713,92 +735,102 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct dss_device *dss = dss_get_device(master); + struct omap_hdmi *hdmi; int r; int irq; - hdmi.pdev = pdev; - hdmi.dss = dss; - dev_set_drvdata(&pdev->dev, &hdmi); + hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + hdmi->pdev = pdev; + hdmi->dss = dss; + dev_set_drvdata(&pdev->dev, hdmi); - mutex_init(&hdmi.lock); - spin_lock_init(&hdmi.audio_playing_lock); + mutex_init(&hdmi->lock); + spin_lock_init(&hdmi->audio_playing_lock); - r = hdmi_probe_of(pdev); + r = hdmi_probe_of(hdmi); if (r) - return r; + goto err_free; - r = hdmi_wp_init(pdev, &hdmi.wp, 4); + r = hdmi_wp_init(pdev, &hdmi->wp, 4); if (r) - return r; + goto err_free; - r = hdmi_pll_init(dss, pdev, &hdmi.pll, &hdmi.wp); + r = hdmi_pll_init(dss, pdev, &hdmi->pll, &hdmi->wp); if (r) - return r; + goto err_free; - r = hdmi_phy_init(pdev, &hdmi.phy, 4); + r = hdmi_phy_init(pdev, &hdmi->phy, 4); if (r) - goto err; + goto err_pll; - r = hdmi4_core_init(pdev, &hdmi.core); + r = hdmi4_core_init(pdev, &hdmi->core); if (r) - goto err; + goto err_pll; - r = hdmi4_cec_init(pdev, &hdmi.core, &hdmi.wp); + r = hdmi4_cec_init(pdev, &hdmi->core, &hdmi->wp); if (r) - goto err; + goto err_pll; irq = platform_get_irq(pdev, 0); if (irq < 0) { DSSERR("platform_get_irq failed\n"); r = -ENODEV; - goto err; + goto err_pll; } r = devm_request_threaded_irq(&pdev->dev, irq, NULL, hdmi_irq_handler, - IRQF_ONESHOT, "OMAP HDMI", &hdmi); + IRQF_ONESHOT, "OMAP HDMI", hdmi); if (r) { DSSERR("HDMI IRQ request failed\n"); - goto err; + goto err_pll; } pm_runtime_enable(&pdev->dev); - hdmi_init_output(pdev); + hdmi_init_output(hdmi); - r = hdmi_audio_register(&pdev->dev); + r = hdmi_audio_register(hdmi); if (r) { DSSERR("Registering HDMI audio failed\n"); - hdmi_uninit_output(pdev); + hdmi_uninit_output(hdmi); pm_runtime_disable(&pdev->dev); return r; } - hdmi.debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs, - &hdmi); + hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs, + hdmi); return 0; -err: - hdmi_pll_uninit(&hdmi.pll); + +err_pll: + hdmi_pll_uninit(&hdmi->pll); +err_free: + kfree(hdmi); return r; } static void hdmi4_unbind(struct device *dev, struct device *master, void *data) { - struct platform_device *pdev = to_platform_device(dev); + struct omap_hdmi *hdmi = dev_get_drvdata(dev); + + dss_debugfs_remove_file(hdmi->debugfs); - dss_debugfs_remove_file(hdmi.debugfs); + if (hdmi->audio_pdev) + platform_device_unregister(hdmi->audio_pdev); - if (hdmi.audio_pdev) - platform_device_unregister(hdmi.audio_pdev); + hdmi_uninit_output(hdmi); - hdmi_uninit_output(pdev); + hdmi4_cec_uninit(&hdmi->core); - hdmi4_cec_uninit(&hdmi.core); + hdmi_pll_uninit(&hdmi->pll); - hdmi_pll_uninit(&hdmi.pll); + pm_runtime_disable(dev); - pm_runtime_disable(&pdev->dev); + kfree(hdmi); } static const struct component_ops hdmi4_component_ops = { diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c index 23db74ae1826..340383150fb9 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c @@ -175,10 +175,10 @@ static int hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) REG_FLD_MOD(core->base, HDMI_CORE_SYS_INTR_UNMASK4, 0, 3, 3); hdmi_wp_clear_irqenable(core->wp, HDMI_IRQ_CORE); hdmi_wp_set_irqstatus(core->wp, HDMI_IRQ_CORE); - hdmi4_core_disable(NULL); + hdmi4_core_disable(core); return 0; } - err = hdmi4_core_enable(NULL); + err = hdmi4_core_enable(core); if (err) return err; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h index b6ab579e44d2..337a317c1a27 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h @@ -266,8 +266,8 @@ void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s); int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core); -int hdmi4_core_enable(struct omap_dss_device *dssdev); -void hdmi4_core_disable(struct omap_dss_device *dssdev); +int hdmi4_core_enable(struct hdmi_core_data *core); +void hdmi4_core_disable(struct hdmi_core_data *core); void hdmi4_core_powerdown_disable(struct hdmi_core_data *core); int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp); -- cgit v1.2.3 From c44991ce21bef5831b28b36f1da87dceb85bef75 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:46 +0200 Subject: drm: omapdrm: hdmi5: Allocate the omap_hdmi data structure dynamically The omap_hdmi private data structure is currently stored as a global variable. While no platform with multiple HDMI5 encoders currently exists nor is planned, this doesn't comply with the kernel device model and should thus be fixed. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 364 +++++++++++++++++++----------------- 1 file changed, 196 insertions(+), 168 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index a83d70144f85..4a0178ab8016 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -46,15 +46,13 @@ #include "hdmi5_core.h" #include "dss.h" -static struct omap_hdmi hdmi; - -static int hdmi_runtime_get(void) +static int hdmi_runtime_get(struct omap_hdmi *hdmi) { int r; DSSDBG("hdmi_runtime_get\n"); - r = pm_runtime_get_sync(&hdmi.pdev->dev); + r = pm_runtime_get_sync(&hdmi->pdev->dev); WARN_ON(r < 0); if (r < 0) return r; @@ -62,19 +60,20 @@ static int hdmi_runtime_get(void) return 0; } -static void hdmi_runtime_put(void) +static void hdmi_runtime_put(struct omap_hdmi *hdmi) { int r; DSSDBG("hdmi_runtime_put\n"); - r = pm_runtime_put_sync(&hdmi.pdev->dev); + r = pm_runtime_put_sync(&hdmi->pdev->dev); WARN_ON(r < 0 && r != -ENOSYS); } static irqreturn_t hdmi_irq_handler(int irq, void *data) { - struct hdmi_wp_data *wp = data; + struct omap_hdmi *hdmi = data; + struct hdmi_wp_data *wp = &hdmi->wp; u32 irqstatus; irqstatus = hdmi_wp_get_irqstatus(wp); @@ -97,17 +96,17 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data) * setting the PHY to LDOON. To ignore those, we force the RXDET * line to 0 until the PHY power state has been changed. */ - v = hdmi_read_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL); + v = hdmi_read_reg(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL); v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */ v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */ - hdmi_write_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v); + hdmi_write_reg(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v); hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON); - REG_FLD_MOD(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15); + REG_FLD_MOD(hdmi->phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15); } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) { hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON); @@ -118,69 +117,69 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static int hdmi_init_regulator(void) +static int hdmi_init_regulator(struct omap_hdmi *hdmi) { struct regulator *reg; - if (hdmi.vdda_reg != NULL) + if (hdmi->vdda_reg != NULL) return 0; - reg = devm_regulator_get(&hdmi.pdev->dev, "vdda"); + reg = devm_regulator_get(&hdmi->pdev->dev, "vdda"); if (IS_ERR(reg)) { DSSERR("can't get VDDA regulator\n"); return PTR_ERR(reg); } - hdmi.vdda_reg = reg; + hdmi->vdda_reg = reg; return 0; } -static int hdmi_power_on_core(struct omap_dss_device *dssdev) +static int hdmi_power_on_core(struct omap_hdmi *hdmi) { int r; - r = regulator_enable(hdmi.vdda_reg); + r = regulator_enable(hdmi->vdda_reg); if (r) return r; - r = hdmi_runtime_get(); + r = hdmi_runtime_get(hdmi); if (r) goto err_runtime_get; /* Make selection of HDMI in DSS */ - dss_select_hdmi_venc_clk_source(hdmi.dss, DSS_HDMI_M_PCLK); + dss_select_hdmi_venc_clk_source(hdmi->dss, DSS_HDMI_M_PCLK); - hdmi.core_enabled = true; + hdmi->core_enabled = true; return 0; err_runtime_get: - regulator_disable(hdmi.vdda_reg); + regulator_disable(hdmi->vdda_reg); return r; } -static void hdmi_power_off_core(struct omap_dss_device *dssdev) +static void hdmi_power_off_core(struct omap_hdmi *hdmi) { - hdmi.core_enabled = false; + hdmi->core_enabled = false; - hdmi_runtime_put(); - regulator_disable(hdmi.vdda_reg); + hdmi_runtime_put(hdmi); + regulator_disable(hdmi->vdda_reg); } -static int hdmi_power_on_full(struct omap_dss_device *dssdev) +static int hdmi_power_on_full(struct omap_hdmi *hdmi) { int r; struct videomode *vm; struct dss_pll_clock_info hdmi_cinfo = { 0 }; unsigned int pc; - r = hdmi_power_on_core(dssdev); + r = hdmi_power_on_core(hdmi); if (r) return r; - vm = &hdmi.cfg.vm; + vm = &hdmi->cfg.vm; DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive, vm->vactive); @@ -192,87 +191,89 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) /* DSS_HDMI_TCLK is bitclk / 10 */ pc *= 10; - dss_pll_calc_b(&hdmi.pll.pll, clk_get_rate(hdmi.pll.pll.clkin), + dss_pll_calc_b(&hdmi->pll.pll, clk_get_rate(hdmi->pll.pll.clkin), pc, &hdmi_cinfo); /* disable and clear irqs */ - hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); - hdmi_wp_set_irqstatus(&hdmi.wp, - hdmi_wp_get_irqstatus(&hdmi.wp)); + hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff); + hdmi_wp_set_irqstatus(&hdmi->wp, + hdmi_wp_get_irqstatus(&hdmi->wp)); - r = dss_pll_enable(&hdmi.pll.pll); + r = dss_pll_enable(&hdmi->pll.pll); if (r) { DSSERR("Failed to enable PLL\n"); goto err_pll_enable; } - r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo); + r = dss_pll_set_config(&hdmi->pll.pll, &hdmi_cinfo); if (r) { DSSERR("Failed to configure PLL\n"); goto err_pll_cfg; } - r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco, + r = hdmi_phy_configure(&hdmi->phy, hdmi_cinfo.clkdco, hdmi_cinfo.clkout[0]); if (r) { DSSDBG("Failed to start PHY\n"); goto err_phy_cfg; } - r = hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_LDOON); + r = hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_LDOON); if (r) goto err_phy_pwr; - hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); + hdmi5_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg); /* tv size */ - dss_mgr_set_timings(&hdmi.output, vm); + dss_mgr_set_timings(&hdmi->output, vm); - r = dss_mgr_enable(&hdmi.output); + r = dss_mgr_enable(&hdmi->output); if (r) goto err_mgr_enable; - r = hdmi_wp_video_start(&hdmi.wp); + r = hdmi_wp_video_start(&hdmi->wp); if (r) goto err_vid_enable; - hdmi_wp_set_irqenable(&hdmi.wp, + hdmi_wp_set_irqenable(&hdmi->wp, HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT); return 0; err_vid_enable: - dss_mgr_disable(&hdmi.output); + dss_mgr_disable(&hdmi->output); err_mgr_enable: - hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); + hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF); err_phy_pwr: err_phy_cfg: err_pll_cfg: - dss_pll_disable(&hdmi.pll.pll); + dss_pll_disable(&hdmi->pll.pll); err_pll_enable: - hdmi_power_off_core(dssdev); + hdmi_power_off_core(hdmi); return -EIO; } -static void hdmi_power_off_full(struct omap_dss_device *dssdev) +static void hdmi_power_off_full(struct omap_hdmi *hdmi) { - hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); + hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff); - hdmi_wp_video_stop(&hdmi.wp); + hdmi_wp_video_stop(&hdmi->wp); - dss_mgr_disable(&hdmi.output); + dss_mgr_disable(&hdmi->output); - hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); + hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF); - dss_pll_disable(&hdmi.pll.pll); + dss_pll_disable(&hdmi->pll.pll); - hdmi_power_off_core(dssdev); + hdmi_power_off_core(hdmi); } static int hdmi_display_check_timing(struct omap_dss_device *dssdev, struct videomode *vm) { - if (!dispc_mgr_timings_ok(hdmi.dss->dispc, dssdev->dispc_channel, vm)) + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + if (!dispc_mgr_timings_ok(hdmi->dss->dispc, dssdev->dispc_channel, vm)) return -EINVAL; return 0; @@ -281,67 +282,73 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev, static void hdmi_display_set_timing(struct omap_dss_device *dssdev, struct videomode *vm) { - mutex_lock(&hdmi.lock); + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + mutex_lock(&hdmi->lock); - hdmi.cfg.vm = *vm; + hdmi->cfg.vm = *vm; - dispc_set_tv_pclk(hdmi.dss->dispc, vm->pixelclock); + dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); } static void hdmi_display_get_timings(struct omap_dss_device *dssdev, struct videomode *vm) { - *vm = hdmi.cfg.vm; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + *vm = hdmi->cfg.vm; } static int hdmi_dump_regs(struct seq_file *s, void *p) { - mutex_lock(&hdmi.lock); + struct omap_hdmi *hdmi = s->private; + + mutex_lock(&hdmi->lock); - if (hdmi_runtime_get()) { - mutex_unlock(&hdmi.lock); + if (hdmi_runtime_get(hdmi)) { + mutex_unlock(&hdmi->lock); return 0; } - hdmi_wp_dump(&hdmi.wp, s); - hdmi_pll_dump(&hdmi.pll, s); - hdmi_phy_dump(&hdmi.phy, s); - hdmi5_core_dump(&hdmi.core, s); + hdmi_wp_dump(&hdmi->wp, s); + hdmi_pll_dump(&hdmi->pll, s); + hdmi_phy_dump(&hdmi->phy, s); + hdmi5_core_dump(&hdmi->core, s); - hdmi_runtime_put(); - mutex_unlock(&hdmi.lock); + hdmi_runtime_put(hdmi); + mutex_unlock(&hdmi->lock); return 0; } -static int read_edid(u8 *buf, int len) +static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len) { int r; int idlemode; - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - r = hdmi_runtime_get(); + r = hdmi_runtime_get(hdmi); BUG_ON(r); - idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2); + idlemode = REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); /* No-idle mode */ - REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); + REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); - r = hdmi5_read_edid(&hdmi.core, buf, len); + r = hdmi5_read_edid(&hdmi->core, buf, len); - REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); + REG_FLD_MOD(hdmi->wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); - hdmi_runtime_put(); - mutex_unlock(&hdmi.lock); + hdmi_runtime_put(hdmi); + mutex_unlock(&hdmi->lock); return r; } static void hdmi_start_audio_stream(struct omap_hdmi *hd) { - REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); + REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); hdmi_wp_audio_enable(&hd->wp, true); hdmi_wp_audio_core_req_enable(&hd->wp, true); } @@ -355,111 +362,114 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd) static int hdmi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_device *out = &hdmi.output; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); unsigned long flags; int r = 0; DSSDBG("ENTER hdmi_display_enable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - if (!out->dispc_channel_connected) { + if (!dssdev->dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err0; } - r = hdmi_power_on_full(dssdev); + r = hdmi_power_on_full(hdmi); if (r) { DSSERR("failed to power on device\n"); goto err0; } - if (hdmi.audio_configured) { - r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config, - hdmi.cfg.vm.pixelclock); + if (hdmi->audio_configured) { + r = hdmi5_audio_config(&hdmi->core, &hdmi->wp, + &hdmi->audio_config, + hdmi->cfg.vm.pixelclock); if (r) { DSSERR("Error restoring audio configuration: %d", r); - hdmi.audio_abort_cb(&hdmi.pdev->dev); - hdmi.audio_configured = false; + hdmi->audio_abort_cb(&hdmi->pdev->dev); + hdmi->audio_configured = false; } } - spin_lock_irqsave(&hdmi.audio_playing_lock, flags); - if (hdmi.audio_configured && hdmi.audio_playing) - hdmi_start_audio_stream(&hdmi); - hdmi.display_enabled = true; - spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags); + spin_lock_irqsave(&hdmi->audio_playing_lock, flags); + if (hdmi->audio_configured && hdmi->audio_playing) + hdmi_start_audio_stream(hdmi); + hdmi->display_enabled = true; + spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return 0; err0: - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return r; } static void hdmi_display_disable(struct omap_dss_device *dssdev) { + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); unsigned long flags; DSSDBG("Enter hdmi_display_disable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - spin_lock_irqsave(&hdmi.audio_playing_lock, flags); - hdmi_stop_audio_stream(&hdmi); - hdmi.display_enabled = false; - spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags); + spin_lock_irqsave(&hdmi->audio_playing_lock, flags); + hdmi_stop_audio_stream(hdmi); + hdmi->display_enabled = false; + spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); - hdmi_power_off_full(dssdev); + hdmi_power_off_full(hdmi); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); } -static int hdmi_core_enable(struct omap_dss_device *dssdev) +static int hdmi_core_enable(struct omap_hdmi *hdmi) { int r = 0; DSSDBG("ENTER omapdss_hdmi_core_enable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - r = hdmi_power_on_core(dssdev); + r = hdmi_power_on_core(hdmi); if (r) { DSSERR("failed to power on device\n"); goto err0; } - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return 0; err0: - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); return r; } -static void hdmi_core_disable(struct omap_dss_device *dssdev) +static void hdmi_core_disable(struct omap_hdmi *hdmi) { DSSDBG("Enter omapdss_hdmi_core_disable\n"); - mutex_lock(&hdmi.lock); + mutex_lock(&hdmi->lock); - hdmi_power_off_core(dssdev); + hdmi_power_off_core(hdmi); - mutex_unlock(&hdmi.lock); + mutex_unlock(&hdmi->lock); } static int hdmi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); int r; - r = hdmi_init_regulator(); + r = hdmi_init_regulator(hdmi); if (r) return r; - r = dss_mgr_connect(&hdmi.output, dssdev); + r = dss_mgr_connect(&hdmi->output, dssdev); if (r) return r; @@ -467,7 +477,7 @@ static int hdmi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(&hdmi.output, dssdev); + dss_mgr_disconnect(&hdmi->output, dssdev); return r; } @@ -477,6 +487,8 @@ static int hdmi_connect(struct omap_dss_device *dssdev, static void hdmi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -484,27 +496,28 @@ static void hdmi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(&hdmi.output, dssdev); + dss_mgr_disconnect(&hdmi->output, dssdev); } static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *edid, int len) { + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); bool need_enable; int r; - need_enable = hdmi.core_enabled == false; + need_enable = hdmi->core_enabled == false; if (need_enable) { - r = hdmi_core_enable(dssdev); + r = hdmi_core_enable(hdmi); if (r) return r; } - r = read_edid(edid, len); + r = read_edid(hdmi, edid, len); if (need_enable) - hdmi_core_disable(dssdev); + hdmi_core_disable(hdmi); return r; } @@ -512,14 +525,18 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, static int hdmi_set_infoframe(struct omap_dss_device *dssdev, const struct hdmi_avi_infoframe *avi) { - hdmi.cfg.infoframe = *avi; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + hdmi->cfg.infoframe = *avi; return 0; } static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode) { - hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; + struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); + + hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; return 0; } @@ -539,11 +556,11 @@ static const struct omapdss_hdmi_ops hdmi_ops = { .set_hdmi_mode = hdmi_set_hdmi_mode, }; -static void hdmi_init_output(struct platform_device *pdev) +static void hdmi_init_output(struct omap_hdmi *hdmi) { - struct omap_dss_device *out = &hdmi.output; + struct omap_dss_device *out = &hdmi->output; - out->dev = &pdev->dev; + out->dev = &hdmi->pdev->dev; out->id = OMAP_DSS_OUTPUT_HDMI; out->output_type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; @@ -554,15 +571,16 @@ static void hdmi_init_output(struct platform_device *pdev) omapdss_register_output(out); } -static void hdmi_uninit_output(struct platform_device *pdev) +static void hdmi_uninit_output(struct omap_hdmi *hdmi) { - struct omap_dss_device *out = &hdmi.output; + struct omap_dss_device *out = &hdmi->output; omapdss_unregister_output(out); } -static int hdmi_probe_of(struct platform_device *pdev) +static int hdmi_probe_of(struct omap_hdmi *hdmi) { + struct platform_device *pdev = hdmi->pdev; struct device_node *node = pdev->dev.of_node; struct device_node *ep; int r; @@ -571,7 +589,7 @@ static int hdmi_probe_of(struct platform_device *pdev) if (!ep) return 0; - r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy); + r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy); if (r) goto err; @@ -685,26 +703,26 @@ static const struct omap_hdmi_audio_ops hdmi_audio_ops = { .audio_config = hdmi_audio_config, }; -static int hdmi_audio_register(struct device *dev) +static int hdmi_audio_register(struct omap_hdmi *hdmi) { struct omap_hdmi_audio_pdata pdata = { - .dev = dev, + .dev = &hdmi->pdev->dev, .version = 5, - .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp), + .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp), .ops = &hdmi_audio_ops, }; - hdmi.audio_pdev = platform_device_register_data( - dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, + hdmi->audio_pdev = platform_device_register_data( + &hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, &pdata, sizeof(pdata)); - if (IS_ERR(hdmi.audio_pdev)) - return PTR_ERR(hdmi.audio_pdev); + if (IS_ERR(hdmi->audio_pdev)) + return PTR_ERR(hdmi->audio_pdev); - hdmi_runtime_get(); - hdmi.wp_idlemode = - REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2); - hdmi_runtime_put(); + hdmi_runtime_get(hdmi); + hdmi->wp_idlemode = + REG_GET(hdmi->wp.base, HDMI_WP_SYSCONFIG, 3, 2); + hdmi_runtime_put(hdmi); return 0; } @@ -714,86 +732,96 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct dss_device *dss = dss_get_device(master); + struct omap_hdmi *hdmi; int r; int irq; - hdmi.pdev = pdev; - hdmi.dss = dss; - dev_set_drvdata(&pdev->dev, &hdmi); + hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + hdmi->pdev = pdev; + hdmi->dss = dss; + dev_set_drvdata(&pdev->dev, hdmi); - mutex_init(&hdmi.lock); - spin_lock_init(&hdmi.audio_playing_lock); + mutex_init(&hdmi->lock); + spin_lock_init(&hdmi->audio_playing_lock); - r = hdmi_probe_of(pdev); + r = hdmi_probe_of(hdmi); if (r) - return r; + goto err_free; - r = hdmi_wp_init(pdev, &hdmi.wp, 5); + r = hdmi_wp_init(pdev, &hdmi->wp, 5); if (r) - return r; + goto err_free; - r = hdmi_pll_init(dss, pdev, &hdmi.pll, &hdmi.wp); + r = hdmi_pll_init(dss, pdev, &hdmi->pll, &hdmi->wp); if (r) - return r; + goto err_free; - r = hdmi_phy_init(pdev, &hdmi.phy, 5); + r = hdmi_phy_init(pdev, &hdmi->phy, 5); if (r) - goto err; + goto err_pll; - r = hdmi5_core_init(pdev, &hdmi.core); + r = hdmi5_core_init(pdev, &hdmi->core); if (r) - goto err; + goto err_pll; irq = platform_get_irq(pdev, 0); if (irq < 0) { DSSERR("platform_get_irq failed\n"); r = -ENODEV; - goto err; + goto err_pll; } r = devm_request_threaded_irq(&pdev->dev, irq, NULL, hdmi_irq_handler, - IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); + IRQF_ONESHOT, "OMAP HDMI", hdmi); if (r) { DSSERR("HDMI IRQ request failed\n"); - goto err; + goto err_pll; } pm_runtime_enable(&pdev->dev); - hdmi_init_output(pdev); + hdmi_init_output(hdmi); - r = hdmi_audio_register(&pdev->dev); + r = hdmi_audio_register(hdmi); if (r) { DSSERR("Registering HDMI audio failed %d\n", r); - hdmi_uninit_output(pdev); + hdmi_uninit_output(hdmi); pm_runtime_disable(&pdev->dev); return r; } - hdmi.debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs, - &hdmi); + hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs, + hdmi); return 0; -err: - hdmi_pll_uninit(&hdmi.pll); + +err_pll: + hdmi_pll_uninit(&hdmi->pll); +err_free: + kfree(hdmi); return r; } static void hdmi5_unbind(struct device *dev, struct device *master, void *data) { - struct platform_device *pdev = to_platform_device(dev); + struct omap_hdmi *hdmi = dev_get_drvdata(dev); + + dss_debugfs_remove_file(hdmi->debugfs); - dss_debugfs_remove_file(hdmi.debugfs); + if (hdmi->audio_pdev) + platform_device_unregister(hdmi->audio_pdev); - if (hdmi.audio_pdev) - platform_device_unregister(hdmi.audio_pdev); + hdmi_uninit_output(hdmi); - hdmi_uninit_output(pdev); + hdmi_pll_uninit(&hdmi->pll); - hdmi_pll_uninit(&hdmi.pll); + pm_runtime_disable(dev); - pm_runtime_disable(&pdev->dev); + kfree(hdmi); } static const struct component_ops hdmi5_component_ops = { -- cgit v1.2.3 From 24aac6011f704d69b5f34514923413f85669f282 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:47 +0200 Subject: drm: omapdrm: sdi: Allocate the sdi private data structure dynamically The sdi private data structure is currently stored as a global variable. While no platform with multiple SDI encoders currently exists nor is planned, this doesn't comply with the kernel device model and should thus be fixed. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/sdi.c | 151 ++++++++++++++++++++++---------------- 1 file changed, 86 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index 9c2ed56a70c1..68a40ae26f5b 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -29,7 +29,7 @@ #include "omapdss.h" #include "dss.h" -static struct { +struct sdi_device { struct platform_device *pdev; struct dss_device *dss; @@ -41,11 +41,12 @@ static struct { int datapairs; struct omap_dss_device output; +}; - bool port_initialized; -} sdi; +#define dssdev_to_sdi(dssdev) container_of(dssdev, struct sdi_device, output) struct sdi_clk_calc_ctx { + struct sdi_device *sdi; unsigned long pck_min, pck_max; unsigned long fck; @@ -71,17 +72,17 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data) ctx->fck = fck; - return dispc_div_calc(sdi.dss->dispc, fck, + return dispc_div_calc(ctx->sdi->dss->dispc, fck, ctx->pck_min, ctx->pck_max, dpi_calc_dispc_cb, ctx); } -static int sdi_calc_clock_div(unsigned long pclk, - unsigned long *fck, - struct dispc_clock_info *dispc_cinfo) +static int sdi_calc_clock_div(struct sdi_device *sdi, unsigned long pclk, + unsigned long *fck, + struct dispc_clock_info *dispc_cinfo) { int i; - struct sdi_clk_calc_ctx ctx; + struct sdi_clk_calc_ctx ctx = { .sdi = sdi }; /* * DSS fclk gives us very few possibilities, so finding a good pixel @@ -100,7 +101,7 @@ static int sdi_calc_clock_div(unsigned long pclk, ctx.pck_min = 0; ctx.pck_max = pclk + 1000 * i * i * i; - ok = dss_div_calc(sdi.dss, pclk, ctx.pck_min, + ok = dss_div_calc(sdi->dss, pclk, ctx.pck_min, dpi_calc_dss_cb, &ctx); if (ok) { *fck = ctx.fck; @@ -112,48 +113,49 @@ static int sdi_calc_clock_div(unsigned long pclk, return -EINVAL; } -static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) +static void sdi_config_lcd_manager(struct sdi_device *sdi) { - sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; + sdi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; - sdi.mgr_config.stallmode = false; - sdi.mgr_config.fifohandcheck = false; + sdi->mgr_config.stallmode = false; + sdi->mgr_config.fifohandcheck = false; - sdi.mgr_config.video_port_width = 24; - sdi.mgr_config.lcden_sig_polarity = 1; + sdi->mgr_config.video_port_width = 24; + sdi->mgr_config.lcden_sig_polarity = 1; - dss_mgr_set_lcd_config(&sdi.output, &sdi.mgr_config); + dss_mgr_set_lcd_config(&sdi->output, &sdi->mgr_config); } static int sdi_display_enable(struct omap_dss_device *dssdev) { - struct videomode *vm = &sdi.vm; + struct sdi_device *sdi = dssdev_to_sdi(dssdev); + struct videomode *vm = &sdi->vm; unsigned long fck; struct dispc_clock_info dispc_cinfo; unsigned long pck; int r; - if (!sdi.output.dispc_channel_connected) { + if (!sdi->output.dispc_channel_connected) { DSSERR("failed to enable display: no output/manager\n"); return -ENODEV; } - r = regulator_enable(sdi.vdds_sdi_reg); + r = regulator_enable(sdi->vdds_sdi_reg); if (r) goto err_reg_enable; - r = dispc_runtime_get(sdi.dss->dispc); + r = dispc_runtime_get(sdi->dss->dispc); if (r) goto err_get_dispc; /* 15.5.9.1.2 */ vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE | DISPLAY_FLAGS_SYNC_POSEDGE; - r = sdi_calc_clock_div(vm->pixelclock, &fck, &dispc_cinfo); + r = sdi_calc_clock_div(sdi, vm->pixelclock, &fck, &dispc_cinfo); if (r) goto err_calc_clock_div; - sdi.mgr_config.clock_info = dispc_cinfo; + sdi->mgr_config.clock_info = dispc_cinfo; pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div; @@ -165,13 +167,13 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) } - dss_mgr_set_timings(&sdi.output, vm); + dss_mgr_set_timings(&sdi->output, vm); - r = dss_set_fck_rate(sdi.dss, fck); + r = dss_set_fck_rate(sdi->dss, fck); if (r) goto err_set_dss_clock_div; - sdi_config_lcd_manager(dssdev); + sdi_config_lcd_manager(sdi); /* * LCLK and PCLK divisors are located in shadow registers, and we @@ -184,62 +186,69 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) * need to care about the shadow register mechanism for pck-free. The * exact reason for this is unknown. */ - dispc_mgr_set_clock_div(sdi.dss->dispc, sdi.output.dispc_channel, - &sdi.mgr_config.clock_info); + dispc_mgr_set_clock_div(sdi->dss->dispc, sdi->output.dispc_channel, + &sdi->mgr_config.clock_info); - dss_sdi_init(sdi.dss, sdi.datapairs); - r = dss_sdi_enable(sdi.dss); + dss_sdi_init(sdi->dss, sdi->datapairs); + r = dss_sdi_enable(sdi->dss); if (r) goto err_sdi_enable; mdelay(2); - r = dss_mgr_enable(&sdi.output); + r = dss_mgr_enable(&sdi->output); if (r) goto err_mgr_enable; return 0; err_mgr_enable: - dss_sdi_disable(sdi.dss); + dss_sdi_disable(sdi->dss); err_sdi_enable: err_set_dss_clock_div: err_calc_clock_div: - dispc_runtime_put(sdi.dss->dispc); + dispc_runtime_put(sdi->dss->dispc); err_get_dispc: - regulator_disable(sdi.vdds_sdi_reg); + regulator_disable(sdi->vdds_sdi_reg); err_reg_enable: return r; } static void sdi_display_disable(struct omap_dss_device *dssdev) { - dss_mgr_disable(&sdi.output); + struct sdi_device *sdi = dssdev_to_sdi(dssdev); + + dss_mgr_disable(&sdi->output); - dss_sdi_disable(sdi.dss); + dss_sdi_disable(sdi->dss); - dispc_runtime_put(sdi.dss->dispc); + dispc_runtime_put(sdi->dss->dispc); - regulator_disable(sdi.vdds_sdi_reg); + regulator_disable(sdi->vdds_sdi_reg); } static void sdi_set_timings(struct omap_dss_device *dssdev, struct videomode *vm) { - sdi.vm = *vm; + struct sdi_device *sdi = dssdev_to_sdi(dssdev); + + sdi->vm = *vm; } static void sdi_get_timings(struct omap_dss_device *dssdev, struct videomode *vm) { - *vm = sdi.vm; + struct sdi_device *sdi = dssdev_to_sdi(dssdev); + + *vm = sdi->vm; } static int sdi_check_timings(struct omap_dss_device *dssdev, struct videomode *vm) { + struct sdi_device *sdi = dssdev_to_sdi(dssdev); enum omap_channel channel = dssdev->dispc_channel; - if (!dispc_mgr_timings_ok(sdi.dss->dispc, channel, vm)) + if (!dispc_mgr_timings_ok(sdi->dss->dispc, channel, vm)) return -EINVAL; if (vm->pixelclock == 0) @@ -248,21 +257,21 @@ static int sdi_check_timings(struct omap_dss_device *dssdev, return 0; } -static int sdi_init_regulator(void) +static int sdi_init_regulator(struct sdi_device *sdi) { struct regulator *vdds_sdi; - if (sdi.vdds_sdi_reg) + if (sdi->vdds_sdi_reg) return 0; - vdds_sdi = devm_regulator_get(&sdi.pdev->dev, "vdds_sdi"); + vdds_sdi = devm_regulator_get(&sdi->pdev->dev, "vdds_sdi"); if (IS_ERR(vdds_sdi)) { if (PTR_ERR(vdds_sdi) != -EPROBE_DEFER) DSSERR("can't get VDDS_SDI regulator\n"); return PTR_ERR(vdds_sdi); } - sdi.vdds_sdi_reg = vdds_sdi; + sdi->vdds_sdi_reg = vdds_sdi; return 0; } @@ -270,13 +279,14 @@ static int sdi_init_regulator(void) static int sdi_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + struct sdi_device *sdi = dssdev_to_sdi(dssdev); int r; - r = sdi_init_regulator(); + r = sdi_init_regulator(sdi); if (r) return r; - r = dss_mgr_connect(&sdi.output, dssdev); + r = dss_mgr_connect(&sdi->output, dssdev); if (r) return r; @@ -284,7 +294,7 @@ static int sdi_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(&sdi.output, dssdev); + dss_mgr_disconnect(&sdi->output, dssdev); return r; } @@ -294,6 +304,8 @@ static int sdi_connect(struct omap_dss_device *dssdev, static void sdi_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + struct sdi_device *sdi = dssdev_to_sdi(dssdev); + WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -301,7 +313,7 @@ static void sdi_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(&sdi.output, dssdev); + dss_mgr_disconnect(&sdi->output, dssdev); } static const struct omapdss_sdi_ops sdi_ops = { @@ -316,11 +328,11 @@ static const struct omapdss_sdi_ops sdi_ops = { .get_timings = sdi_get_timings, }; -static void sdi_init_output(struct platform_device *pdev) +static void sdi_init_output(struct sdi_device *sdi) { - struct omap_dss_device *out = &sdi.output; + struct omap_dss_device *out = &sdi->output; - out->dev = &pdev->dev; + out->dev = &sdi->pdev->dev; out->id = OMAP_DSS_OUTPUT_SDI; out->output_type = OMAP_DISPLAY_TYPE_SDI; out->name = "sdi.0"; @@ -333,23 +345,28 @@ static void sdi_init_output(struct platform_device *pdev) omapdss_register_output(out); } -static void sdi_uninit_output(struct platform_device *pdev) +static void sdi_uninit_output(struct sdi_device *sdi) { - struct omap_dss_device *out = &sdi.output; - - omapdss_unregister_output(out); + omapdss_unregister_output(&sdi->output); } int sdi_init_port(struct dss_device *dss, struct platform_device *pdev, struct device_node *port) { + struct sdi_device *sdi; struct device_node *ep; u32 datapairs; int r; + sdi = kzalloc(sizeof(*sdi), GFP_KERNEL); + if (!sdi) + return -ENOMEM; + ep = of_get_next_child(port, NULL); - if (!ep) - return 0; + if (!ep) { + r = 0; + goto err_free; + } r = of_property_read_u32(ep, "datapairs", &datapairs); if (r) { @@ -357,29 +374,33 @@ int sdi_init_port(struct dss_device *dss, struct platform_device *pdev, goto err_datapairs; } - sdi.datapairs = datapairs; - sdi.dss = dss; + sdi->datapairs = datapairs; + sdi->dss = dss; of_node_put(ep); - sdi.pdev = pdev; + sdi->pdev = pdev; + port->data = sdi; - sdi_init_output(pdev); - - sdi.port_initialized = true; + sdi_init_output(sdi); return 0; err_datapairs: of_node_put(ep); +err_free: + kfree(sdi); return r; } void sdi_uninit_port(struct device_node *port) { - if (!sdi.port_initialized) + struct sdi_device *sdi = port->data; + + if (!sdi) return; - sdi_uninit_output(sdi.pdev); + sdi_uninit_output(sdi); + kfree(sdi); } -- cgit v1.2.3 From 663ac57b285d0176cacb85899b7f79d83f825353 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Feb 2018 14:00:48 +0200 Subject: drm: omapdrm: venc: Allocate the venc private data structure dynamically The venc private data structure is currently stored as a global variable. While no platform with multiple VENC encoders currently exists nor is planned, this doesn't comply with the kernel device model and should thus be fixed. Signed-off-by: Laurent Pinchart Reviewed-by: Sebastian Reichel --- drivers/gpu/drm/omapdrm/dss/venc.c | 442 ++++++++++++++++++++----------------- 1 file changed, 238 insertions(+), 204 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 12a0ac4e1eb1..24d1ced210bd 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -319,7 +319,7 @@ static enum venc_videomode venc_get_videomode(const struct videomode *vm) return VENC_MODE_UNKNOWN; } -static struct { +struct venc_device { struct platform_device *pdev; void __iomem *base; struct mutex venc_lock; @@ -337,81 +337,87 @@ static struct { bool requires_tv_dac_clk; struct omap_dss_device output; -} venc; +}; + +#define dssdev_to_venc(dssdev) container_of(dssdev, struct venc_device, output) -static inline void venc_write_reg(int idx, u32 val) +static inline void venc_write_reg(struct venc_device *venc, int idx, u32 val) { - __raw_writel(val, venc.base + idx); + __raw_writel(val, venc->base + idx); } -static inline u32 venc_read_reg(int idx) +static inline u32 venc_read_reg(struct venc_device *venc, int idx) { - u32 l = __raw_readl(venc.base + idx); + u32 l = __raw_readl(venc->base + idx); return l; } -static void venc_write_config(const struct venc_config *config) +static void venc_write_config(struct venc_device *venc, + const struct venc_config *config) { DSSDBG("write venc conf\n"); - venc_write_reg(VENC_LLEN, config->llen); - venc_write_reg(VENC_FLENS, config->flens); - venc_write_reg(VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr); - venc_write_reg(VENC_C_PHASE, config->c_phase); - venc_write_reg(VENC_GAIN_U, config->gain_u); - venc_write_reg(VENC_GAIN_V, config->gain_v); - venc_write_reg(VENC_GAIN_Y, config->gain_y); - venc_write_reg(VENC_BLACK_LEVEL, config->black_level); - venc_write_reg(VENC_BLANK_LEVEL, config->blank_level); - venc_write_reg(VENC_M_CONTROL, config->m_control); - venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | - venc.wss_data); - venc_write_reg(VENC_S_CARR, config->s_carr); - venc_write_reg(VENC_L21__WC_CTL, config->l21__wc_ctl); - venc_write_reg(VENC_SAVID__EAVID, config->savid__eavid); - venc_write_reg(VENC_FLEN__FAL, config->flen__fal); - venc_write_reg(VENC_LAL__PHASE_RESET, config->lal__phase_reset); - venc_write_reg(VENC_HS_INT_START_STOP_X, config->hs_int_start_stop_x); - venc_write_reg(VENC_HS_EXT_START_STOP_X, config->hs_ext_start_stop_x); - venc_write_reg(VENC_VS_INT_START_X, config->vs_int_start_x); - venc_write_reg(VENC_VS_INT_STOP_X__VS_INT_START_Y, + venc_write_reg(venc, VENC_LLEN, config->llen); + venc_write_reg(venc, VENC_FLENS, config->flens); + venc_write_reg(venc, VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr); + venc_write_reg(venc, VENC_C_PHASE, config->c_phase); + venc_write_reg(venc, VENC_GAIN_U, config->gain_u); + venc_write_reg(venc, VENC_GAIN_V, config->gain_v); + venc_write_reg(venc, VENC_GAIN_Y, config->gain_y); + venc_write_reg(venc, VENC_BLACK_LEVEL, config->black_level); + venc_write_reg(venc, VENC_BLANK_LEVEL, config->blank_level); + venc_write_reg(venc, VENC_M_CONTROL, config->m_control); + venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | + venc->wss_data); + venc_write_reg(venc, VENC_S_CARR, config->s_carr); + venc_write_reg(venc, VENC_L21__WC_CTL, config->l21__wc_ctl); + venc_write_reg(venc, VENC_SAVID__EAVID, config->savid__eavid); + venc_write_reg(venc, VENC_FLEN__FAL, config->flen__fal); + venc_write_reg(venc, VENC_LAL__PHASE_RESET, config->lal__phase_reset); + venc_write_reg(venc, VENC_HS_INT_START_STOP_X, + config->hs_int_start_stop_x); + venc_write_reg(venc, VENC_HS_EXT_START_STOP_X, + config->hs_ext_start_stop_x); + venc_write_reg(venc, VENC_VS_INT_START_X, config->vs_int_start_x); + venc_write_reg(venc, VENC_VS_INT_STOP_X__VS_INT_START_Y, config->vs_int_stop_x__vs_int_start_y); - venc_write_reg(VENC_VS_INT_STOP_Y__VS_EXT_START_X, + venc_write_reg(venc, VENC_VS_INT_STOP_Y__VS_EXT_START_X, config->vs_int_stop_y__vs_ext_start_x); - venc_write_reg(VENC_VS_EXT_STOP_X__VS_EXT_START_Y, + venc_write_reg(venc, VENC_VS_EXT_STOP_X__VS_EXT_START_Y, config->vs_ext_stop_x__vs_ext_start_y); - venc_write_reg(VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y); - venc_write_reg(VENC_AVID_START_STOP_X, config->avid_start_stop_x); - venc_write_reg(VENC_AVID_START_STOP_Y, config->avid_start_stop_y); - venc_write_reg(VENC_FID_INT_START_X__FID_INT_START_Y, + venc_write_reg(venc, VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y); + venc_write_reg(venc, VENC_AVID_START_STOP_X, config->avid_start_stop_x); + venc_write_reg(venc, VENC_AVID_START_STOP_Y, config->avid_start_stop_y); + venc_write_reg(venc, VENC_FID_INT_START_X__FID_INT_START_Y, config->fid_int_start_x__fid_int_start_y); - venc_write_reg(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X, + venc_write_reg(venc, VENC_FID_INT_OFFSET_Y__FID_EXT_START_X, config->fid_int_offset_y__fid_ext_start_x); - venc_write_reg(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y, + venc_write_reg(venc, VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y, config->fid_ext_start_y__fid_ext_offset_y); - venc_write_reg(VENC_DAC_B__DAC_C, venc_read_reg(VENC_DAC_B__DAC_C)); - venc_write_reg(VENC_VIDOUT_CTRL, config->vidout_ctrl); - venc_write_reg(VENC_HFLTR_CTRL, config->hfltr_ctrl); - venc_write_reg(VENC_X_COLOR, config->x_color); - venc_write_reg(VENC_LINE21, config->line21); - venc_write_reg(VENC_LN_SEL, config->ln_sel); - venc_write_reg(VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger); - venc_write_reg(VENC_TVDETGP_INT_START_STOP_X, + venc_write_reg(venc, VENC_DAC_B__DAC_C, + venc_read_reg(venc, VENC_DAC_B__DAC_C)); + venc_write_reg(venc, VENC_VIDOUT_CTRL, config->vidout_ctrl); + venc_write_reg(venc, VENC_HFLTR_CTRL, config->hfltr_ctrl); + venc_write_reg(venc, VENC_X_COLOR, config->x_color); + venc_write_reg(venc, VENC_LINE21, config->line21); + venc_write_reg(venc, VENC_LN_SEL, config->ln_sel); + venc_write_reg(venc, VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger); + venc_write_reg(venc, VENC_TVDETGP_INT_START_STOP_X, config->tvdetgp_int_start_stop_x); - venc_write_reg(VENC_TVDETGP_INT_START_STOP_Y, + venc_write_reg(venc, VENC_TVDETGP_INT_START_STOP_Y, config->tvdetgp_int_start_stop_y); - venc_write_reg(VENC_GEN_CTRL, config->gen_ctrl); - venc_write_reg(VENC_F_CONTROL, config->f_control); - venc_write_reg(VENC_SYNC_CTRL, config->sync_ctrl); + venc_write_reg(venc, VENC_GEN_CTRL, config->gen_ctrl); + venc_write_reg(venc, VENC_F_CONTROL, config->f_control); + venc_write_reg(venc, VENC_SYNC_CTRL, config->sync_ctrl); } -static void venc_reset(void) +static void venc_reset(struct venc_device *venc) { int t = 1000; - venc_write_reg(VENC_F_CONTROL, 1<<8); - while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) { + venc_write_reg(venc, VENC_F_CONTROL, 1<<8); + while (venc_read_reg(venc, VENC_F_CONTROL) & (1<<8)) { if (--t == 0) { DSSERR("Failed to reset venc\n"); return; @@ -425,24 +431,24 @@ static void venc_reset(void) #endif } -static int venc_runtime_get(void) +static int venc_runtime_get(struct venc_device *venc) { int r; DSSDBG("venc_runtime_get\n"); - r = pm_runtime_get_sync(&venc.pdev->dev); + r = pm_runtime_get_sync(&venc->pdev->dev); WARN_ON(r < 0); return r < 0 ? r : 0; } -static void venc_runtime_put(void) +static void venc_runtime_put(struct venc_device *venc) { int r; DSSDBG("venc_runtime_put\n"); - r = pm_runtime_put_sync(&venc.pdev->dev); + r = pm_runtime_put_sync(&venc->pdev->dev); WARN_ON(r < 0 && r != -ENOSYS); } @@ -458,116 +464,119 @@ static const struct venc_config *venc_timings_to_config(struct videomode *vm) } } -static int venc_power_on(struct omap_dss_device *dssdev) +static int venc_power_on(struct venc_device *venc) { u32 l; int r; - r = venc_runtime_get(); + r = venc_runtime_get(venc); if (r) goto err0; - venc_reset(); - venc_write_config(venc_timings_to_config(&venc.vm)); + venc_reset(venc); + venc_write_config(venc, venc_timings_to_config(&venc->vm)); - dss_set_venc_output(venc.dss, venc.type); - dss_set_dac_pwrdn_bgz(venc.dss, 1); + dss_set_venc_output(venc->dss, venc->type); + dss_set_dac_pwrdn_bgz(venc->dss, 1); l = 0; - if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) + if (venc->type == OMAP_DSS_VENC_TYPE_COMPOSITE) l |= 1 << 1; else /* S-Video */ l |= (1 << 0) | (1 << 2); - if (venc.invert_polarity == false) + if (venc->invert_polarity == false) l |= 1 << 3; - venc_write_reg(VENC_OUTPUT_CONTROL, l); + venc_write_reg(venc, VENC_OUTPUT_CONTROL, l); - dss_mgr_set_timings(&venc.output, &venc.vm); + dss_mgr_set_timings(&venc->output, &venc->vm); - r = regulator_enable(venc.vdda_dac_reg); + r = regulator_enable(venc->vdda_dac_reg); if (r) goto err1; - r = dss_mgr_enable(&venc.output); + r = dss_mgr_enable(&venc->output); if (r) goto err2; return 0; err2: - regulator_disable(venc.vdda_dac_reg); + regulator_disable(venc->vdda_dac_reg); err1: - venc_write_reg(VENC_OUTPUT_CONTROL, 0); - dss_set_dac_pwrdn_bgz(venc.dss, 0); + venc_write_reg(venc, VENC_OUTPUT_CONTROL, 0); + dss_set_dac_pwrdn_bgz(venc->dss, 0); - venc_runtime_put(); + venc_runtime_put(venc); err0: return r; } -static void venc_power_off(struct omap_dss_device *dssdev) +static void venc_power_off(struct venc_device *venc) { - venc_write_reg(VENC_OUTPUT_CONTROL, 0); - dss_set_dac_pwrdn_bgz(venc.dss, 0); + venc_write_reg(venc, VENC_OUTPUT_CONTROL, 0); + dss_set_dac_pwrdn_bgz(venc->dss, 0); - dss_mgr_disable(&venc.output); + dss_mgr_disable(&venc->output); - regulator_disable(venc.vdda_dac_reg); + regulator_disable(venc->vdda_dac_reg); - venc_runtime_put(); + venc_runtime_put(venc); } static int venc_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_device *out = &venc.output; + struct venc_device *venc = dssdev_to_venc(dssdev); int r; DSSDBG("venc_display_enable\n"); - mutex_lock(&venc.venc_lock); + mutex_lock(&venc->venc_lock); - if (!out->dispc_channel_connected) { + if (!dssdev->dispc_channel_connected) { DSSERR("Failed to enable display: no output/manager\n"); r = -ENODEV; goto err0; } - r = venc_power_on(dssdev); + r = venc_power_on(venc); if (r) goto err0; - venc.wss_data = 0; + venc->wss_data = 0; - mutex_unlock(&venc.venc_lock); + mutex_unlock(&venc->venc_lock); return 0; err0: - mutex_unlock(&venc.venc_lock); + mutex_unlock(&venc->venc_lock); return r; } static void venc_display_disable(struct omap_dss_device *dssdev) { + struct venc_device *venc = dssdev_to_venc(dssdev); + DSSDBG("venc_display_disable\n"); - mutex_lock(&venc.venc_lock); + mutex_lock(&venc->venc_lock); - venc_power_off(dssdev); + venc_power_off(venc); - mutex_unlock(&venc.venc_lock); + mutex_unlock(&venc->venc_lock); } static void venc_set_timings(struct omap_dss_device *dssdev, struct videomode *vm) { + struct venc_device *venc = dssdev_to_venc(dssdev); struct videomode actual_vm; DSSDBG("venc_set_timings\n"); - mutex_lock(&venc.venc_lock); + mutex_lock(&venc->venc_lock); switch (venc_get_videomode(vm)) { default: @@ -581,14 +590,14 @@ static void venc_set_timings(struct omap_dss_device *dssdev, } /* Reset WSS data when the TV standard changes. */ - if (memcmp(&venc.vm, &actual_vm, sizeof(actual_vm))) - venc.wss_data = 0; + if (memcmp(&venc->vm, &actual_vm, sizeof(actual_vm))) + venc->wss_data = 0; - venc.vm = actual_vm; + venc->vm = actual_vm; - dispc_set_tv_pclk(venc.dss->dispc, 13500000); + dispc_set_tv_pclk(venc->dss->dispc, 13500000); - mutex_unlock(&venc.venc_lock); + mutex_unlock(&venc->venc_lock); } static int venc_check_timings(struct omap_dss_device *dssdev, @@ -608,128 +617,136 @@ static int venc_check_timings(struct omap_dss_device *dssdev, static void venc_get_timings(struct omap_dss_device *dssdev, struct videomode *vm) { - mutex_lock(&venc.venc_lock); + struct venc_device *venc = dssdev_to_venc(dssdev); + + mutex_lock(&venc->venc_lock); - *vm = venc.vm; + *vm = venc->vm; - mutex_unlock(&venc.venc_lock); + mutex_unlock(&venc->venc_lock); } static u32 venc_get_wss(struct omap_dss_device *dssdev) { + struct venc_device *venc = dssdev_to_venc(dssdev); + /* Invert due to VENC_L21_WC_CTL:INV=1 */ - return (venc.wss_data >> 8) ^ 0xfffff; + return (venc->wss_data >> 8) ^ 0xfffff; } static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) { + struct venc_device *venc = dssdev_to_venc(dssdev); const struct venc_config *config; int r; DSSDBG("venc_set_wss\n"); - mutex_lock(&venc.venc_lock); + mutex_lock(&venc->venc_lock); - config = venc_timings_to_config(&venc.vm); + config = venc_timings_to_config(&venc->vm); /* Invert due to VENC_L21_WC_CTL:INV=1 */ - venc.wss_data = (wss ^ 0xfffff) << 8; + venc->wss_data = (wss ^ 0xfffff) << 8; - r = venc_runtime_get(); + r = venc_runtime_get(venc); if (r) goto err; - venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | - venc.wss_data); + venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | + venc->wss_data); - venc_runtime_put(); + venc_runtime_put(venc); err: - mutex_unlock(&venc.venc_lock); + mutex_unlock(&venc->venc_lock); return r; } -static int venc_init_regulator(void) +static int venc_init_regulator(struct venc_device *venc) { struct regulator *vdda_dac; - if (venc.vdda_dac_reg != NULL) + if (venc->vdda_dac_reg != NULL) return 0; - vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda"); + vdda_dac = devm_regulator_get(&venc->pdev->dev, "vdda"); if (IS_ERR(vdda_dac)) { if (PTR_ERR(vdda_dac) != -EPROBE_DEFER) DSSERR("can't get VDDA_DAC regulator\n"); return PTR_ERR(vdda_dac); } - venc.vdda_dac_reg = vdda_dac; + venc->vdda_dac_reg = vdda_dac; return 0; } static int venc_dump_regs(struct seq_file *s, void *p) { -#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) + struct venc_device *venc = s->private; + +#define DUMPREG(venc, r) \ + seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(venc, r)) - if (venc_runtime_get()) + if (venc_runtime_get(venc)) return 0; - DUMPREG(VENC_F_CONTROL); - DUMPREG(VENC_VIDOUT_CTRL); - DUMPREG(VENC_SYNC_CTRL); - DUMPREG(VENC_LLEN); - DUMPREG(VENC_FLENS); - DUMPREG(VENC_HFLTR_CTRL); - DUMPREG(VENC_CC_CARR_WSS_CARR); - DUMPREG(VENC_C_PHASE); - DUMPREG(VENC_GAIN_U); - DUMPREG(VENC_GAIN_V); - DUMPREG(VENC_GAIN_Y); - DUMPREG(VENC_BLACK_LEVEL); - DUMPREG(VENC_BLANK_LEVEL); - DUMPREG(VENC_X_COLOR); - DUMPREG(VENC_M_CONTROL); - DUMPREG(VENC_BSTAMP_WSS_DATA); - DUMPREG(VENC_S_CARR); - DUMPREG(VENC_LINE21); - DUMPREG(VENC_LN_SEL); - DUMPREG(VENC_L21__WC_CTL); - DUMPREG(VENC_HTRIGGER_VTRIGGER); - DUMPREG(VENC_SAVID__EAVID); - DUMPREG(VENC_FLEN__FAL); - DUMPREG(VENC_LAL__PHASE_RESET); - DUMPREG(VENC_HS_INT_START_STOP_X); - DUMPREG(VENC_HS_EXT_START_STOP_X); - DUMPREG(VENC_VS_INT_START_X); - DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y); - DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X); - DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y); - DUMPREG(VENC_VS_EXT_STOP_Y); - DUMPREG(VENC_AVID_START_STOP_X); - DUMPREG(VENC_AVID_START_STOP_Y); - DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y); - DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X); - DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y); - DUMPREG(VENC_TVDETGP_INT_START_STOP_X); - DUMPREG(VENC_TVDETGP_INT_START_STOP_Y); - DUMPREG(VENC_GEN_CTRL); - DUMPREG(VENC_OUTPUT_CONTROL); - DUMPREG(VENC_OUTPUT_TEST); - - venc_runtime_put(); + DUMPREG(venc, VENC_F_CONTROL); + DUMPREG(venc, VENC_VIDOUT_CTRL); + DUMPREG(venc, VENC_SYNC_CTRL); + DUMPREG(venc, VENC_LLEN); + DUMPREG(venc, VENC_FLENS); + DUMPREG(venc, VENC_HFLTR_CTRL); + DUMPREG(venc, VENC_CC_CARR_WSS_CARR); + DUMPREG(venc, VENC_C_PHASE); + DUMPREG(venc, VENC_GAIN_U); + DUMPREG(venc, VENC_GAIN_V); + DUMPREG(venc, VENC_GAIN_Y); + DUMPREG(venc, VENC_BLACK_LEVEL); + DUMPREG(venc, VENC_BLANK_LEVEL); + DUMPREG(venc, VENC_X_COLOR); + DUMPREG(venc, VENC_M_CONTROL); + DUMPREG(venc, VENC_BSTAMP_WSS_DATA); + DUMPREG(venc, VENC_S_CARR); + DUMPREG(venc, VENC_LINE21); + DUMPREG(venc, VENC_LN_SEL); + DUMPREG(venc, VENC_L21__WC_CTL); + DUMPREG(venc, VENC_HTRIGGER_VTRIGGER); + DUMPREG(venc, VENC_SAVID__EAVID); + DUMPREG(venc, VENC_FLEN__FAL); + DUMPREG(venc, VENC_LAL__PHASE_RESET); + DUMPREG(venc, VENC_HS_INT_START_STOP_X); + DUMPREG(venc, VENC_HS_EXT_START_STOP_X); + DUMPREG(venc, VENC_VS_INT_START_X); + DUMPREG(venc, VENC_VS_INT_STOP_X__VS_INT_START_Y); + DUMPREG(venc, VENC_VS_INT_STOP_Y__VS_EXT_START_X); + DUMPREG(venc, VENC_VS_EXT_STOP_X__VS_EXT_START_Y); + DUMPREG(venc, VENC_VS_EXT_STOP_Y); + DUMPREG(venc, VENC_AVID_START_STOP_X); + DUMPREG(venc, VENC_AVID_START_STOP_Y); + DUMPREG(venc, VENC_FID_INT_START_X__FID_INT_START_Y); + DUMPREG(venc, VENC_FID_INT_OFFSET_Y__FID_EXT_START_X); + DUMPREG(venc, VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y); + DUMPREG(venc, VENC_TVDETGP_INT_START_STOP_X); + DUMPREG(venc, VENC_TVDETGP_INT_START_STOP_Y); + DUMPREG(venc, VENC_GEN_CTRL); + DUMPREG(venc, VENC_OUTPUT_CONTROL); + DUMPREG(venc, VENC_OUTPUT_TEST); + + venc_runtime_put(venc); #undef DUMPREG return 0; } -static int venc_get_clocks(struct platform_device *pdev) +static int venc_get_clocks(struct venc_device *venc) { struct clk *clk; - if (venc.requires_tv_dac_clk) { - clk = devm_clk_get(&pdev->dev, "tv_dac_clk"); + if (venc->requires_tv_dac_clk) { + clk = devm_clk_get(&venc->pdev->dev, "tv_dac_clk"); if (IS_ERR(clk)) { DSSERR("can't get tv_dac_clk\n"); return PTR_ERR(clk); @@ -738,7 +755,7 @@ static int venc_get_clocks(struct platform_device *pdev) clk = NULL; } - venc.tv_dac_clk = clk; + venc->tv_dac_clk = clk; return 0; } @@ -746,13 +763,14 @@ static int venc_get_clocks(struct platform_device *pdev) static int venc_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + struct venc_device *venc = dssdev_to_venc(dssdev); int r; - r = venc_init_regulator(); + r = venc_init_regulator(venc); if (r) return r; - r = dss_mgr_connect(&venc.output, dssdev); + r = dss_mgr_connect(&venc->output, dssdev); if (r) return r; @@ -760,7 +778,7 @@ static int venc_connect(struct omap_dss_device *dssdev, if (r) { DSSERR("failed to connect output to new device: %s\n", dst->name); - dss_mgr_disconnect(&venc.output, dssdev); + dss_mgr_disconnect(&venc->output, dssdev); return r; } @@ -770,6 +788,8 @@ static int venc_connect(struct omap_dss_device *dssdev, static void venc_disconnect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) { + struct venc_device *venc = dssdev_to_venc(dssdev); + WARN_ON(dst != dssdev->dst); if (dst != dssdev->dst) @@ -777,7 +797,7 @@ static void venc_disconnect(struct omap_dss_device *dssdev, omapdss_output_unset_device(dssdev); - dss_mgr_disconnect(&venc.output, dssdev); + dss_mgr_disconnect(&venc->output, dssdev); } static const struct omapdss_atv_ops venc_ops = { @@ -795,11 +815,11 @@ static const struct omapdss_atv_ops venc_ops = { .get_wss = venc_get_wss, }; -static void venc_init_output(struct platform_device *pdev) +static void venc_init_output(struct venc_device *venc) { - struct omap_dss_device *out = &venc.output; + struct omap_dss_device *out = &venc->output; - out->dev = &pdev->dev; + out->dev = &venc->pdev->dev; out->id = OMAP_DSS_OUTPUT_VENC; out->output_type = OMAP_DISPLAY_TYPE_VENC; out->name = "venc.0"; @@ -810,16 +830,14 @@ static void venc_init_output(struct platform_device *pdev) omapdss_register_output(out); } -static void venc_uninit_output(struct platform_device *pdev) +static void venc_uninit_output(struct venc_device *venc) { - struct omap_dss_device *out = &venc.output; - - omapdss_unregister_output(out); + omapdss_unregister_output(&venc->output); } -static int venc_probe_of(struct platform_device *pdev) +static int venc_probe_of(struct venc_device *venc) { - struct device_node *node = pdev->dev.of_node; + struct device_node *node = venc->pdev->dev.of_node; struct device_node *ep; u32 channels; int r; @@ -828,24 +846,25 @@ static int venc_probe_of(struct platform_device *pdev) if (!ep) return 0; - venc.invert_polarity = of_property_read_bool(ep, "ti,invert-polarity"); + venc->invert_polarity = of_property_read_bool(ep, "ti,invert-polarity"); r = of_property_read_u32(ep, "ti,channels", &channels); if (r) { - dev_err(&pdev->dev, + dev_err(&venc->pdev->dev, "failed to read property 'ti,channels': %d\n", r); goto err; } switch (channels) { case 1: - venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE; + venc->type = OMAP_DSS_VENC_TYPE_COMPOSITE; break; case 2: - venc.type = OMAP_DSS_VENC_TYPE_SVIDEO; + venc->type = OMAP_DSS_VENC_TYPE_SVIDEO; break; default: - dev_err(&pdev->dev, "bad channel propert '%d'\n", channels); + dev_err(&venc->pdev->dev, "bad channel propert '%d'\n", + channels); r = -EINVAL; goto err; } @@ -870,69 +889,81 @@ static int venc_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct dss_device *dss = dss_get_device(master); + struct venc_device *venc; u8 rev_id; struct resource *venc_mem; int r; - venc.pdev = pdev; - venc.dss = dss; + venc = kzalloc(sizeof(*venc), GFP_KERNEL); + if (!venc) + return -ENOMEM; + + venc->pdev = pdev; + venc->dss = dss; + dev_set_drvdata(dev, venc); /* The OMAP34xx, OMAP35xx and AM35xx VENC require the TV DAC clock. */ if (soc_device_match(venc_soc_devices)) - venc.requires_tv_dac_clk = true; + venc->requires_tv_dac_clk = true; - mutex_init(&venc.venc_lock); + mutex_init(&venc->venc_lock); - venc.wss_data = 0; + venc->wss_data = 0; - venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0); - venc.base = devm_ioremap_resource(&pdev->dev, venc_mem); - if (IS_ERR(venc.base)) - return PTR_ERR(venc.base); + venc_mem = platform_get_resource(venc->pdev, IORESOURCE_MEM, 0); + venc->base = devm_ioremap_resource(&pdev->dev, venc_mem); + if (IS_ERR(venc->base)) { + r = PTR_ERR(venc->base); + goto err_free; + } - r = venc_get_clocks(pdev); + r = venc_get_clocks(venc); if (r) - return r; + goto err_free; pm_runtime_enable(&pdev->dev); - r = venc_runtime_get(); + r = venc_runtime_get(venc); if (r) goto err_runtime_get; - rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); + rev_id = (u8)(venc_read_reg(venc, VENC_REV_ID) & 0xff); dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id); - venc_runtime_put(); + venc_runtime_put(venc); - r = venc_probe_of(pdev); + r = venc_probe_of(venc); if (r) { DSSERR("Invalid DT data\n"); goto err_probe_of; } - venc.debugfs = dss_debugfs_create_file(dss, "venc", venc_dump_regs, - &venc); + venc->debugfs = dss_debugfs_create_file(dss, "venc", venc_dump_regs, + venc); - venc_init_output(pdev); + venc_init_output(venc); return 0; err_probe_of: err_runtime_get: pm_runtime_disable(&pdev->dev); +err_free: + kfree(venc); return r; } static void venc_unbind(struct device *dev, struct device *master, void *data) { - struct platform_device *pdev = to_platform_device(dev); + struct venc_device *venc = dev_get_drvdata(dev); - dss_debugfs_remove_file(venc.debugfs); + dss_debugfs_remove_file(venc->debugfs); - venc_uninit_output(pdev); + venc_uninit_output(venc); - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); + + kfree(venc); } static const struct component_ops venc_component_ops = { @@ -953,24 +984,27 @@ static int venc_remove(struct platform_device *pdev) static int venc_runtime_suspend(struct device *dev) { - if (venc.tv_dac_clk) - clk_disable_unprepare(venc.tv_dac_clk); + struct venc_device *venc = dev_get_drvdata(dev); + + if (venc->tv_dac_clk) + clk_disable_unprepare(venc->tv_dac_clk); - dispc_runtime_put(venc.dss->dispc); + dispc_runtime_put(venc->dss->dispc); return 0; } static int venc_runtime_resume(struct device *dev) { + struct venc_device *venc = dev_get_drvdata(dev); int r; - r = dispc_runtime_get(venc.dss->dispc); + r = dispc_runtime_get(venc->dss->dispc); if (r < 0) return r; - if (venc.tv_dac_clk) - clk_prepare_enable(venc.tv_dac_clk); + if (venc->tv_dac_clk) + clk_prepare_enable(venc->tv_dac_clk); return 0; } -- cgit v1.2.3 From fe6b503910e9d794d64e6dd311f4d5c80514069f Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 12 Feb 2018 09:16:08 +0200 Subject: drm/omap: reorganize locking in mgr_fld_write Fix sparse warning: drivers/gpu/drm/omapdrm/dss/dispc.c:387:9: warning: context imbalance in 'mgr_fld_write' - different lock contexts for basic block Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dispc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index ce470b51e326..d2d95c76a313 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -396,13 +396,13 @@ static void mgr_fld_write(struct dispc_device *dispc, enum omap_channel channel, const bool need_lock = rfld.reg == DISPC_CONTROL || rfld.reg == DISPC_CONFIG; unsigned long flags; - if (need_lock) + if (need_lock) { spin_lock_irqsave(&dispc->control_lock, flags); - - REG_FLD_MOD(dispc, rfld.reg, val, rfld.high, rfld.low); - - if (need_lock) + REG_FLD_MOD(dispc, rfld.reg, val, rfld.high, rfld.low); spin_unlock_irqrestore(&dispc->control_lock, flags); + } else { + REG_FLD_MOD(dispc, rfld.reg, val, rfld.high, rfld.low); + } } static int dispc_get_num_ovls(struct dispc_device *dispc) -- cgit v1.2.3 From 45bfdabf6fa501f05d65d43229f550dc09198ab1 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 12 Feb 2018 09:19:52 +0200 Subject: drm/omap: acx565akm: use __be32 when reading status Fix sparse warning: drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c:224:23: warning: cast to restricted __be32 Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c index c4bb33a247d0..92fe125ce22e 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c @@ -216,12 +216,12 @@ static void set_display_state(struct panel_drv_data *ddata, int enabled) static int panel_enabled(struct panel_drv_data *ddata) { + __be32 v; u32 disp_status; int enabled; - acx565akm_read(ddata, MIPID_CMD_READ_DISP_STATUS, - (u8 *)&disp_status, 4); - disp_status = __be32_to_cpu(disp_status); + acx565akm_read(ddata, MIPID_CMD_READ_DISP_STATUS, (u8 *)&v, 4); + disp_status = __be32_to_cpu(v); enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10)); dev_dbg(&ddata->spi->dev, "LCD panel %senabled by bootloader (status 0x%04x)\n", -- cgit v1.2.3 From 5db08a7e487a8a8e4e667b63fa37fec14f185e64 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 12 Feb 2018 09:52:57 +0200 Subject: drm/omap: fbdev: use 'screen_buffer' field Fix sparse warning: drivers/gpu/drm/omapdrm/omap_fbdev.c:191:26: warning: incorrect type in assignment (different address spaces) drivers/gpu/drm/omapdrm/omap_fbdev.c:191:26: expected char [noderef] *screen_base drivers/gpu/drm/omapdrm/omap_fbdev.c:191:26: got void * Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_fbdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index fb309d19ca1b..211ab0b865c9 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -188,7 +188,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, dev->mode_config.fb_base = dma_addr; - fbi->screen_base = omap_gem_vaddr(fbdev->bo); + fbi->screen_buffer = omap_gem_vaddr(fbdev->bo); fbi->screen_size = fbdev->bo->size; fbi->fix.smem_start = dma_addr; fbi->fix.smem_len = fbdev->bo->size; -- cgit v1.2.3 From f9b34a0fa4e25d9c0b72f124680c37c0c38f9934 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 12 Feb 2018 09:55:45 +0200 Subject: drm/omap: fbdev: avoid double initializer entry Fix sparse warning: drivers/gpu/drm/omapdrm/omap_fbdev.c:83:9: warning: Initializer entry defined twice drivers/gpu/drm/omapdrm/omap_fbdev.c:91:10: also defined here Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_fbdev.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 211ab0b865c9..1ace63e2ff22 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -80,15 +80,21 @@ fallback: static struct fb_ops omap_fb_ops = { .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, + + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_setcmap = drm_fb_helper_setcmap, + .fb_blank = drm_fb_helper_blank, + .fb_pan_display = omap_fbdev_pan_display, + .fb_debug_enter = drm_fb_helper_debug_enter, + .fb_debug_leave = drm_fb_helper_debug_leave, + .fb_ioctl = drm_fb_helper_ioctl, .fb_read = drm_fb_helper_sys_read, .fb_write = drm_fb_helper_sys_write, .fb_fillrect = drm_fb_helper_sys_fillrect, .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, - - .fb_pan_display = omap_fbdev_pan_display, }; static int omap_fbdev_create(struct drm_fb_helper *helper, -- cgit v1.2.3 From e6204a58b9e9ad01ab9c6d4b8b2b8b9c4e38bbba Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 9 Feb 2018 09:30:44 +0200 Subject: drm/omap: fix omap_fbdev_free() when omap_fbdev_create() wasn't called If we have no crtcs/connectors, fbdev init goes fine, but omap_fbdev_create() is never called. This means that omap_fbdev->bo is NULL and omap_fbdev_free() crashes. Add a check to omap_fbdev_free() to handle the NULL case. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_fbdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 1ace63e2ff22..632ebcf2165f 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -303,7 +303,8 @@ void omap_fbdev_free(struct drm_device *dev) fbdev = to_omap_fbdev(priv->fbdev); /* unpin the GEM object pinned in omap_fbdev_create() */ - omap_gem_unpin(fbdev->bo); + if (fbdev->bo) + omap_gem_unpin(fbdev->bo); /* this will free the backing object */ if (fbdev->fb) -- cgit v1.2.3 From efd1f06be004a6a384f0482ef76c12bc202e1b8e Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 9 Feb 2018 09:36:23 +0200 Subject: drm/omap: cleanup fbdev init/free omap_fbdev_init() and omap_fbdev_free() use priv->fbdev directly. However, omap_fbdev_init() returns the fbdev, and omap_drv.c also assigns the return value to priv->fbdev. This is slightly confusing. Clean this up by removing the omap_fbdev_init() return value, as we don't care whether fbdev init succeeded or not. Also change omap_drv.c to call omap_fbdev_free() always, and omap_fbdev_free() does the check if fbdev was initialized. While at it, rename omap_fbdev_free() to omap_fbdev_fini() to better match the "init" counterpart. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_drv.c | 9 ++++----- drivers/gpu/drm/omapdrm/omap_fbdev.c | 18 ++++++++---------- drivers/gpu/drm/omapdrm/omap_fbdev.h | 9 ++++----- 3 files changed, 16 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 65a567dcf3ab..4f48b908bdc6 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -570,7 +570,7 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) for (i = 0; i < priv->num_crtcs; i++) drm_crtc_vblank_off(priv->crtcs[i]); - priv->fbdev = omap_fbdev_init(ddev); + omap_fbdev_init(ddev); drm_kms_helper_poll_init(ddev); omap_modeset_enable_external_hpd(); @@ -588,8 +588,8 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) err_cleanup_helpers: omap_modeset_disable_external_hpd(); drm_kms_helper_poll_fini(ddev); - if (priv->fbdev) - omap_fbdev_free(ddev); + + omap_fbdev_fini(ddev); err_cleanup_modeset: drm_mode_config_cleanup(ddev); omap_drm_irq_uninstall(ddev); @@ -615,8 +615,7 @@ static void omapdrm_cleanup(struct omap_drm_private *priv) omap_modeset_disable_external_hpd(); drm_kms_helper_poll_fini(ddev); - if (priv->fbdev) - omap_fbdev_free(ddev); + omap_fbdev_fini(ddev); drm_atomic_helper_shutdown(ddev); diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 632ebcf2165f..be94480326d7 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -242,7 +242,7 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi) } /* initialize fbdev helper */ -struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) +void omap_fbdev_init(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_fbdev *fbdev = NULL; @@ -260,10 +260,8 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) drm_fb_helper_prepare(dev, helper, &omap_fb_helper_funcs); ret = drm_fb_helper_init(dev, helper, priv->num_connectors); - if (ret) { - dev_err(dev->dev, "could not init fbdev: ret=%d\n", ret); + if (ret) goto fail; - } ret = drm_fb_helper_single_add_all_connectors(helper); if (ret) @@ -275,7 +273,7 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) priv->fbdev = helper; - return helper; + return; fini: drm_fb_helper_fini(helper); @@ -283,12 +281,9 @@ fail: kfree(fbdev); dev_warn(dev->dev, "omap_fbdev_init failed\n"); - /* well, limp along without an fbdev.. maybe X11 will work? */ - - return NULL; } -void omap_fbdev_free(struct drm_device *dev) +void omap_fbdev_fini(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct drm_fb_helper *helper = priv->fbdev; @@ -296,11 +291,14 @@ void omap_fbdev_free(struct drm_device *dev) DBG(); + if (!helper) + return; + drm_fb_helper_unregister_fbi(helper); drm_fb_helper_fini(helper); - fbdev = to_omap_fbdev(priv->fbdev); + fbdev = to_omap_fbdev(helper); /* unpin the GEM object pinned in omap_fbdev_create() */ if (fbdev->bo) diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.h b/drivers/gpu/drm/omapdrm/omap_fbdev.h index 1f5ba0996a1a..7dfd843f73f1 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.h +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.h @@ -24,14 +24,13 @@ struct drm_device; struct drm_fb_helper; #ifdef CONFIG_DRM_FBDEV_EMULATION -struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev); -void omap_fbdev_free(struct drm_device *dev); +void omap_fbdev_init(struct drm_device *dev); +void omap_fbdev_fini(struct drm_device *dev); #else -static inline struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) +static inline void omap_fbdev_init(struct drm_device *dev) { - return NULL; } -static inline void omap_fbdev_free(struct drm_device *dev) +static inline void omap_fbdev_fini(struct drm_device *dev) { } #endif -- cgit v1.2.3 From da77772172059e609ef5135881df55e3e6c5c808 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 15 Dec 2017 16:08:31 +0200 Subject: drm/omap: Init fbdev emulation only when we have displays Do not try to init the fbdev if either num_crtcs or num_connectors is 0. In this case we do not have display so the fbdev init would fail anyways. Signed-off-by: Peter Ujfalusi Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_fbdev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index be94480326d7..0f66c74a54b0 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -249,6 +249,9 @@ void omap_fbdev_init(struct drm_device *dev) struct drm_fb_helper *helper; int ret = 0; + if (!priv->num_crtcs || !priv->num_connectors) + return; + fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); if (!fbdev) goto fail; -- cgit v1.2.3 From 588fd85d2706619b88cf287d89d8bee26b4e9f31 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 15 Dec 2017 16:08:23 +0200 Subject: drm/omap: add HPD support to connector-dvi Add HPD support to the DVI connector driver. The code is almost identical to the HPD code in the HDMI connector driver. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/displays/connector-dvi.c | 118 +++++++++++++++++++++++ 1 file changed, 118 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c index 391d80364346..6d8cbd9e2110 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c @@ -9,6 +9,7 @@ * the Free Software Foundation. */ +#include #include #include #include @@ -44,6 +45,14 @@ struct panel_drv_data { struct videomode vm; struct i2c_adapter *i2c_adapter; + + struct gpio_desc *hpd_gpio; + + void (*hpd_cb)(void *cb_data, enum drm_connector_status status); + void *hpd_cb_data; + bool hpd_enabled; + /* mutex for hpd fields above */ + struct mutex hpd_lock; }; #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) @@ -189,6 +198,9 @@ static int dvic_read_edid(struct omap_dss_device *dssdev, struct panel_drv_data *ddata = to_panel_data(dssdev); int r, l, bytes_read; + if (ddata->hpd_gpio && !gpiod_get_value_cansleep(ddata->hpd_gpio)) + return -ENODEV; + if (!ddata->i2c_adapter) return -ENODEV; @@ -220,6 +232,9 @@ static bool dvic_detect(struct omap_dss_device *dssdev) unsigned char out; int r; + if (ddata->hpd_gpio) + return gpiod_get_value_cansleep(ddata->hpd_gpio); + if (!ddata->i2c_adapter) return true; @@ -228,6 +243,60 @@ static bool dvic_detect(struct omap_dss_device *dssdev) return r == 0; } +static int dvic_register_hpd_cb(struct omap_dss_device *dssdev, + void (*cb)(void *cb_data, + enum drm_connector_status status), + void *cb_data) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + + if (!ddata->hpd_gpio) + return -ENOTSUPP; + + mutex_lock(&ddata->hpd_lock); + ddata->hpd_cb = cb; + ddata->hpd_cb_data = cb_data; + mutex_unlock(&ddata->hpd_lock); + return 0; +} + +static void dvic_unregister_hpd_cb(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + + if (!ddata->hpd_gpio) + return; + + mutex_lock(&ddata->hpd_lock); + ddata->hpd_cb = NULL; + ddata->hpd_cb_data = NULL; + mutex_unlock(&ddata->hpd_lock); +} + +static void dvic_enable_hpd(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + + if (!ddata->hpd_gpio) + return; + + mutex_lock(&ddata->hpd_lock); + ddata->hpd_enabled = true; + mutex_unlock(&ddata->hpd_lock); +} + +static void dvic_disable_hpd(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + + if (!ddata->hpd_gpio) + return; + + mutex_lock(&ddata->hpd_lock); + ddata->hpd_enabled = false; + mutex_unlock(&ddata->hpd_lock); +} + static struct omap_dss_driver dvic_driver = { .connect = dvic_connect, .disconnect = dvic_disconnect, @@ -241,14 +310,60 @@ static struct omap_dss_driver dvic_driver = { .read_edid = dvic_read_edid, .detect = dvic_detect, + + .register_hpd_cb = dvic_register_hpd_cb, + .unregister_hpd_cb = dvic_unregister_hpd_cb, + .enable_hpd = dvic_enable_hpd, + .disable_hpd = dvic_disable_hpd, }; +static irqreturn_t dvic_hpd_isr(int irq, void *data) +{ + struct panel_drv_data *ddata = data; + + mutex_lock(&ddata->hpd_lock); + if (ddata->hpd_enabled && ddata->hpd_cb) { + enum drm_connector_status status; + + if (dvic_detect(&ddata->dssdev)) + status = connector_status_connected; + else + status = connector_status_disconnected; + + ddata->hpd_cb(ddata->hpd_cb_data, status); + } + mutex_unlock(&ddata->hpd_lock); + + return IRQ_HANDLED; +} + static int dvic_probe_of(struct platform_device *pdev) { struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct device_node *node = pdev->dev.of_node; struct device_node *adapter_node; struct i2c_adapter *adapter; + struct gpio_desc *gpio; + int r; + + gpio = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN); + if (IS_ERR(gpio)) { + dev_err(&pdev->dev, "failed to parse HPD gpio\n"); + return PTR_ERR(gpio); + } + + ddata->hpd_gpio = gpio; + + mutex_init(&ddata->hpd_lock); + + if (ddata->hpd_gpio) { + r = devm_request_threaded_irq(&pdev->dev, + gpiod_to_irq(ddata->hpd_gpio), NULL, dvic_hpd_isr, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "DVI HPD", ddata); + if (r) + return r; + } adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0); if (adapter_node) { @@ -300,6 +415,7 @@ static int dvic_probe(struct platform_device *pdev) err_reg: i2c_put_adapter(ddata->i2c_adapter); + mutex_destroy(&ddata->hpd_lock); return r; } @@ -316,6 +432,8 @@ static int __exit dvic_remove(struct platform_device *pdev) i2c_put_adapter(ddata->i2c_adapter); + mutex_destroy(&ddata->hpd_lock); + return 0; } -- cgit v1.2.3 From 249e3da9b087f7691efbf1fd6691da69a4c1857d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 27 Jan 2017 09:28:47 +0200 Subject: drm/omap: remove leftover enums A few enums are not used anywhere, so remove them. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/dss/omapdss.h | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index a4f71e082c1c..162f36fa3431 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -163,21 +163,6 @@ enum omap_overlay_caps { OMAP_DSS_OVL_CAP_REPLICATION = 1 << 5, }; -enum omap_dss_clk_source { - OMAP_DSS_CLK_SRC_FCK = 0, /* OMAP2/3: DSS1_ALWON_FCLK - * OMAP4: DSS_FCLK */ - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, /* OMAP3: DSI1_PLL_FCLK - * OMAP4: PLL1_CLK1 */ - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, /* OMAP3: DSI2_PLL_FCLK - * OMAP4: PLL1_CLK2 */ - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC, /* OMAP4: PLL2_CLK1 */ - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI, /* OMAP4: PLL2_CLK2 */ -}; - -enum omap_hdmi_flags { - OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP = 1 << 0, -}; - enum omap_dss_output_id { OMAP_DSS_OUTPUT_DPI = 1 << 0, OMAP_DSS_OUTPUT_DBI = 1 << 1, -- cgit v1.2.3 From b5d025eff5206300be0f59bfe10c5b9e1c895af4 Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Wed, 22 Jun 2016 12:59:50 -0500 Subject: drm/omap: dispc: disp_wb_setup to check return code When dispc_wb_setup() calls dispc_ovl_setup_common() it does not check for failure but instead keeps on partially setting up WB. This causes the WB H/W to be partially initialized and yield unexpected behavior. Make sure return code is successful before proceeding. Signed-off-by: Benoit Parrot Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/dss/dispc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index d2d95c76a313..f0f729fc4ca2 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -2783,6 +2783,8 @@ int dispc_wb_setup(struct dispc_device *dispc, wi->height, wi->fourcc, wi->rotation, zorder, wi->pre_mult_alpha, global_alpha, wi->rotation_type, replication, vm, mem_to_mem); + if (r) + return r; switch (wi->fourcc) { case DRM_FORMAT_RGB565: @@ -2823,7 +2825,7 @@ int dispc_wb_setup(struct dispc_device *dispc, REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0); } - return r; + return 0; } static int dispc_ovl_enable(struct dispc_device *dispc, -- cgit v1.2.3 From 9deb5ad3c47ead2b3c63e44435e9eff0f6f38835 Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Mon, 16 May 2016 16:42:50 -0500 Subject: drm/omap: Add pclk setting case when channel is DSS_WB In dispc_set_ovl_common() we need to initialize pclk to a valid value when we use WB in capture mode (i.e. mem_2_mem is false). Otherwise dispc_ovl_calc_scaling() fails. Signed-off-by: Benoit Parrot Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dispc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index f0f729fc4ca2..3ad56b30c90a 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -2590,6 +2590,10 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc, unsigned long pclk = dispc_plane_pclk_rate(dispc, plane); unsigned long lclk = dispc_plane_lclk_rate(dispc, plane); + /* when setting up WB, dispc_plane_pclk_rate() returns 0 */ + if (plane == OMAP_DSS_WB) + pclk = vm->pixelclock; + if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER) return -EINVAL; -- cgit v1.2.3 From 9f7853ae751849f50486759197d86993551663c2 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 9 Jan 2018 15:36:47 +0200 Subject: drm/omap: set WB channel-in in wb_setup() We need to know the WB channel-in in wb_setup() to be able to configure WB properly for capture mode. At the moment channel-in is set separately. This patch moves channel-in to wb_setup(). Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dispc.c | 12 +++--------- drivers/gpu/drm/omapdrm/dss/dss.h | 3 ++- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 3ad56b30c90a..ccfafce1ea89 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -1234,14 +1234,6 @@ static enum omap_channel dispc_ovl_get_channel_out(struct dispc_device *dispc, } } -void dispc_wb_set_channel_in(struct dispc_device *dispc, - enum dss_writeback_channel channel) -{ - enum omap_plane_id plane = OMAP_DSS_WB; - - REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16); -} - static void dispc_ovl_set_burst_size(struct dispc_device *dispc, enum omap_plane_id plane, enum omap_burst_size burst_size) @@ -2764,7 +2756,8 @@ static int dispc_ovl_setup(struct dispc_device *dispc, int dispc_wb_setup(struct dispc_device *dispc, const struct omap_dss_writeback_info *wi, - bool mem_to_mem, const struct videomode *vm) + bool mem_to_mem, const struct videomode *vm, + enum dss_writeback_channel channel_in) { int r; u32 l; @@ -2809,6 +2802,7 @@ int dispc_wb_setup(struct dispc_device *dispc, /* setup extra DISPC_WB_ATTRIBUTES */ l = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */ + l = FLD_MOD(l, channel_in, 18, 16); /* CHANNELIN */ l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */ if (mem_to_mem) l = FLD_MOD(l, 1, 26, 24); /* CAPTUREMODE */ diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 6f6fd3d1b159..c56c3c59bf18 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -455,7 +455,8 @@ void dispc_wb_set_channel_in(struct dispc_device *dispc, enum dss_writeback_channel channel); int dispc_wb_setup(struct dispc_device *dispc, const struct omap_dss_writeback_info *wi, - bool mem_to_mem, const struct videomode *vm); + bool mem_to_mem, const struct videomode *vm, + enum dss_writeback_channel channel_in); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS static inline void dss_collect_irq_stats(u32 irqstatus, unsigned int *irq_arr) -- cgit v1.2.3 From 46a930418544a5c28abec8dc3e0899d53381814a Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 3 Jun 2016 13:29:59 +0300 Subject: drm/omap: fix WBDELAYCOUNT for HDMI For HDMI, WBDELAYCOUNT starts counting at the start of vsync, not at the start of vfp. This patch adjusts the wbdelay for HDMI accordingly. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dispc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index ccfafce1ea89..7398039954a5 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -2816,8 +2816,12 @@ int dispc_wb_setup(struct dispc_device *dispc, } else { int wbdelay; - wbdelay = min(vm->vfront_porch + - vm->vsync_len + vm->vback_porch, (u32)255); + if (channel_in == DSS_WB_TV_MGR) + wbdelay = min(vm->vsync_len + vm->vback_porch, + (u32)255); + else + wbdelay = min(vm->vfront_porch + + vm->vsync_len + vm->vback_porch, (u32)255); /* WBDELAYCOUNT */ REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0); -- cgit v1.2.3 From b994e53c2c6437689873af4ff61803bef78a2330 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 26 Oct 2017 14:40:12 +0300 Subject: drm/omap: fix WBDELAYCOUNT with interlace Vertical blanking needs to be halved on interlace modes. WBDELAYCOUNT was calculated without such halving, resulting in WBUNCOMPLETE errors. Signed-off-by: Tomi Valkeinen Acked-by: Benoit Parrot --- drivers/gpu/drm/omapdrm/dss/dispc.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 7398039954a5..000a3d4a27bf 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -2814,14 +2814,18 @@ int dispc_wb_setup(struct dispc_device *dispc, /* WBDELAYCOUNT */ REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0); } else { - int wbdelay; + u32 wbdelay; if (channel_in == DSS_WB_TV_MGR) - wbdelay = min(vm->vsync_len + vm->vback_porch, - (u32)255); + wbdelay = vm->vsync_len + vm->vback_porch; else - wbdelay = min(vm->vfront_porch + - vm->vsync_len + vm->vback_porch, (u32)255); + wbdelay = vm->vfront_porch + vm->vsync_len + + vm->vback_porch; + + if (vm->flags & DISPLAY_FLAGS_INTERLACED) + wbdelay /= 2; + + wbdelay = min(wbdelay, 255u); /* WBDELAYCOUNT */ REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0); -- cgit v1.2.3 From 1317ef2113a14b631df15c9d09ce1283836c1456 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 26 Oct 2017 14:40:13 +0300 Subject: drm/omap: fix WB height with interlace When using WB capture from interlaced source, we need to halve the picture heights correctly. Unfortunately the current dispc_ovl_setup_common() doesn't deal with interlace very neatly, so the end result is a bit messy. Signed-off-by: Tomi Valkeinen Acked-by: Benoit Parrot --- drivers/gpu/drm/omapdrm/dss/dispc.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 000a3d4a27bf..72f00e8a1329 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -2597,18 +2597,19 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc, out_width = out_width == 0 ? width : out_width; out_height = out_height == 0 ? height : out_height; - if (ilace && height == out_height) - fieldmode = true; - - if (ilace) { - if (fieldmode) - in_height /= 2; - pos_y /= 2; - out_height /= 2; - - DSSDBG("adjusting for ilace: height %d, pos_y %d, " - "out_height %d\n", in_height, pos_y, - out_height); + if (plane != OMAP_DSS_WB) { + if (ilace && height == out_height) + fieldmode = true; + + if (ilace) { + if (fieldmode) + in_height /= 2; + pos_y /= 2; + out_height /= 2; + + DSSDBG("adjusting for ilace: height %d, pos_y %d, out_height %d\n", + in_height, pos_y, out_height); + } } if (!dispc_ovl_color_mode_supported(dispc, plane, fourcc)) @@ -2771,6 +2772,9 @@ int dispc_wb_setup(struct dispc_device *dispc, enum omap_overlay_caps caps = OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA; + if (vm->flags & DISPLAY_FLAGS_INTERLACED) + in_height /= 2; + DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, " "rot %d\n", wi->paddr, wi->p_uv_addr, in_width, in_height, wi->width, wi->height, wi->fourcc, wi->rotation); -- cgit v1.2.3 From 13bb1601c721f395d272d58438c9e747317f7c1a Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 22 Dec 2015 15:45:20 -0600 Subject: drm/omap: fix scaling limits for WB WB has additional scaling limits when the output color format is one of the YUV formats. These limits are not handled at the moment, causing bad scaling and/or NULL dereference crash. This patchs adds the check so that dispc returns an error for bad scaling request. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dispc.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 72f00e8a1329..2aa72845f819 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -2475,6 +2475,7 @@ static int dispc_ovl_calc_scaling_44xx(struct dispc_device *dispc, ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100)) static int dispc_ovl_calc_scaling(struct dispc_device *dispc, + enum omap_plane_id plane, unsigned long pclk, unsigned long lclk, enum omap_overlay_caps caps, const struct videomode *vm, @@ -2485,7 +2486,8 @@ static int dispc_ovl_calc_scaling(struct dispc_device *dispc, enum omap_dss_rotation_type rotation_type, bool mem_to_mem) { - const int maxdownscale = dispc->feat->max_downscale; + int maxhdownscale = dispc->feat->max_downscale; + int maxvdownscale = dispc->feat->max_downscale; const int max_decim_limit = 16; unsigned long core_clk = 0; int decim_x, decim_y, ret; @@ -2493,6 +2495,20 @@ static int dispc_ovl_calc_scaling(struct dispc_device *dispc, if (width == out_width && height == out_height) return 0; + if (plane == OMAP_DSS_WB) { + switch (fourcc) { + case DRM_FORMAT_NV12: + maxhdownscale = maxvdownscale = 2; + break; + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + maxhdownscale = 2; + maxvdownscale = 4; + break; + default: + break; + } + } if (!mem_to_mem && (pclk == 0 || vm->pixelclock == 0)) { DSSERR("cannot calculate scaling settings: pclk is zero\n"); return -EINVAL; @@ -2510,8 +2526,8 @@ static int dispc_ovl_calc_scaling(struct dispc_device *dispc, 2 : max_decim_limit; } - decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale); - decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale); + decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxhdownscale); + decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxvdownscale); if (decim_x > *x_predecim || out_width > width * 8) return -EINVAL; @@ -2615,7 +2631,7 @@ static int dispc_ovl_setup_common(struct dispc_device *dispc, if (!dispc_ovl_color_mode_supported(dispc, plane, fourcc)) return -EINVAL; - r = dispc_ovl_calc_scaling(dispc, pclk, lclk, caps, vm, in_width, + r = dispc_ovl_calc_scaling(dispc, plane, pclk, lclk, caps, vm, in_width, in_height, out_width, out_height, fourcc, &five_taps, &x_predecim, &y_predecim, pos_x, rotation_type, mem_to_mem); -- cgit v1.2.3 From 7c00985109f95474a7fe31f03022126e23e355ff Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 10 Nov 2015 17:59:50 -0600 Subject: drm/omap: add writeback funcs to dispc_ops Add writeback specific dispc functions to dispc_ops so that omapdrm can use them. Also move 'enum dss_writeback_channel' to the public omapdss.h for omapdrm. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dispc.c | 19 +++++++++++++++---- drivers/gpu/drm/omapdrm/dss/dss.h | 21 --------------------- drivers/gpu/drm/omapdrm/dss/omapdss.h | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 2aa72845f819..57960df1517a 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -715,7 +715,7 @@ static u32 dispc_mgr_get_sync_lost_irq(struct dispc_device *dispc, return mgr_desc[channel].sync_lost_irq; } -u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc) +static u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc) { return DISPC_IRQ_FRAMEDONEWB; } @@ -750,12 +750,12 @@ static void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel) mgr_fld_write(dispc, channel, DISPC_MGR_FLD_GO, 1); } -bool dispc_wb_go_busy(struct dispc_device *dispc) +static bool dispc_wb_go_busy(struct dispc_device *dispc) { return REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1; } -void dispc_wb_go(struct dispc_device *dispc) +static void dispc_wb_go(struct dispc_device *dispc) { enum omap_plane_id plane = OMAP_DSS_WB; bool enable, go; @@ -2771,7 +2771,7 @@ static int dispc_ovl_setup(struct dispc_device *dispc, return r; } -int dispc_wb_setup(struct dispc_device *dispc, +static int dispc_wb_setup(struct dispc_device *dispc, const struct omap_dss_writeback_info *wi, bool mem_to_mem, const struct videomode *vm, enum dss_writeback_channel channel_in) @@ -2854,6 +2854,11 @@ int dispc_wb_setup(struct dispc_device *dispc, return 0; } +static bool dispc_has_writeback(struct dispc_device *dispc) +{ + return dispc->feat->has_writeback; +} + static int dispc_ovl_enable(struct dispc_device *dispc, enum omap_plane_id plane, bool enable) { @@ -4709,6 +4714,12 @@ static const struct dispc_ops dispc_ops = { .ovl_enable = dispc_ovl_enable, .ovl_setup = dispc_ovl_setup, .ovl_get_color_modes = dispc_ovl_get_color_modes, + + .wb_get_framedone_irq = dispc_wb_get_framedone_irq, + .wb_setup = dispc_wb_setup, + .has_writeback = dispc_has_writeback, + .wb_go_busy = dispc_wb_go_busy, + .wb_go = dispc_wb_go, }; /* DISPC HW IP initialisation */ diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index c56c3c59bf18..c601ed9a09c2 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -102,17 +102,6 @@ enum dss_dsi_content_type { DSS_DSI_CONTENT_GENERIC, }; -enum dss_writeback_channel { - DSS_WB_LCD1_MGR = 0, - DSS_WB_LCD2_MGR = 1, - DSS_WB_TV_MGR = 2, - DSS_WB_OVL0 = 3, - DSS_WB_OVL1 = 4, - DSS_WB_OVL2 = 5, - DSS_WB_OVL3 = 6, - DSS_WB_LCD3_MGR = 7, -}; - enum dss_clk_source { DSS_CLK_SRC_FCK = 0, @@ -448,16 +437,6 @@ int dispc_mgr_get_clock_div(struct dispc_device *dispc, struct dispc_clock_info *cinfo); void dispc_set_tv_pclk(struct dispc_device *dispc, unsigned long pclk); -u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc); -bool dispc_wb_go_busy(struct dispc_device *dispc); -void dispc_wb_go(struct dispc_device *dispc); -void dispc_wb_set_channel_in(struct dispc_device *dispc, - enum dss_writeback_channel channel); -int dispc_wb_setup(struct dispc_device *dispc, - const struct omap_dss_writeback_info *wi, - bool mem_to_mem, const struct videomode *vm, - enum dss_writeback_channel channel_in); - #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS static inline void dss_collect_irq_stats(u32 irqstatus, unsigned int *irq_arr) { diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 162f36fa3431..14d74adb13fb 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -626,6 +626,17 @@ omapdss_of_find_source_for_first_ep(struct device_node *node); struct device_node *dss_of_port_get_parent_device(struct device_node *port); u32 dss_of_port_get_port_number(struct device_node *port); +enum dss_writeback_channel { + DSS_WB_LCD1_MGR = 0, + DSS_WB_LCD2_MGR = 1, + DSS_WB_TV_MGR = 2, + DSS_WB_OVL0 = 3, + DSS_WB_OVL1 = 4, + DSS_WB_OVL2 = 5, + DSS_WB_OVL3 = 6, + DSS_WB_LCD3_MGR = 7, +}; + struct dss_mgr_ops { int (*connect)(struct omap_drm_private *priv, enum omap_channel channel, @@ -732,6 +743,15 @@ struct dispc_ops { const u32 *(*ovl_get_color_modes)(struct dispc_device *dispc, enum omap_plane_id plane); + + u32 (*wb_get_framedone_irq)(struct dispc_device *dispc); + int (*wb_setup)(struct dispc_device *dispc, + const struct omap_dss_writeback_info *wi, + bool mem_to_mem, const struct videomode *vm, + enum dss_writeback_channel channel_in); + bool (*has_writeback)(struct dispc_device *dispc); + bool (*wb_go_busy)(struct dispc_device *dispc); + void (*wb_go)(struct dispc_device *dispc); }; struct dispc_device *dispc_get_dispc(struct dss_device *dss); -- cgit v1.2.3 From 1915d7fa93397b3dc8bf9c6973d8662c0a661daf Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 10 Jan 2018 11:31:18 +0200 Subject: drm/omap: fix maximum sizes We define max width and height in mode_config to 2048. These maximums affect many things, which are independent and depend on platform. We need to do more fine grained checks in the code paths for each component, and so the maximum values in mode_config should just be "big enough" to cover all use cases. Change the maximum width & height to 8192. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_drv.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 4f48b908bdc6..3632854c2b91 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -310,11 +310,14 @@ static int omap_modeset_init(struct drm_device *dev) dev->mode_config.min_width = 8; dev->mode_config.min_height = 2; - /* note: eventually will need some cpu_is_omapXYZ() type stuff here - * to fill in these limits properly on different OMAP generations.. + /* + * Note: these values are used for multiple independent things: + * connector mode filtering, buffer sizes, crtc sizes... + * Use big enough values here to cover all use cases, and do more + * specific checking in the respective code paths. */ - dev->mode_config.max_width = 2048; - dev->mode_config.max_height = 2048; + dev->mode_config.max_width = 8192; + dev->mode_config.max_height = 8192; dev->mode_config.funcs = &omap_mode_config_funcs; dev->mode_config.helper_private = &omap_mode_config_helper_funcs; -- cgit v1.2.3 From c1899cb368c1d280af48661c6edaa975cf653533 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 16 Mar 2017 12:05:04 +0200 Subject: drm/omap: Allow HDMI audio setup even if we do not have video configured Allow HDMI audio setup even if we do not have video configured. Audio will get configured at the same time with video if the video is configured soon enough. If it is not the audio DMA will timeout in couple of seconds and audio playback will be aborted. Signed-off-by: Jyri Sarha Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 33 ++++++++++++++------------------- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 37 ++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 1f7897c58f2f..97c88861d67a 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -615,21 +615,16 @@ static int hdmi_audio_startup(struct device *dev, void (*abort_cb)(struct device *dev)) { struct omap_hdmi *hd = dev_get_drvdata(dev); - int ret = 0; mutex_lock(&hd->lock); - if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { - ret = -EPERM; - goto out; - } + WARN_ON(hd->audio_abort_cb != NULL); hd->audio_abort_cb = abort_cb; -out: mutex_unlock(&hd->lock); - return ret; + return 0; } static int hdmi_audio_shutdown(struct device *dev) @@ -650,12 +645,14 @@ static int hdmi_audio_start(struct device *dev) struct omap_hdmi *hd = dev_get_drvdata(dev); unsigned long flags; - WARN_ON(!hdmi_mode_has_audio(&hd->cfg)); - spin_lock_irqsave(&hd->audio_playing_lock, flags); - if (hd->display_enabled) + if (hd->display_enabled) { + if (!hdmi_mode_has_audio(&hd->cfg)) + DSSERR("%s: Video mode does not support audio\n", + __func__); hdmi_start_audio_stream(hd); + } hd->audio_playing = true; spin_unlock_irqrestore(&hd->audio_playing_lock, flags); @@ -686,17 +683,15 @@ static int hdmi_audio_config(struct device *dev, mutex_lock(&hd->lock); - if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { - ret = -EPERM; - goto out; + if (hd->display_enabled) { + ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio, + hd->cfg.vm.pixelclock); + if (ret) + goto out; } - ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio, - hd->cfg.vm.pixelclock); - if (!ret) { - hd->audio_configured = true; - hd->audio_config = *dss_audio; - } + hd->audio_configured = true; + hd->audio_config = *dss_audio; out: mutex_unlock(&hd->lock); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 4a0178ab8016..d28da9ac3e90 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -606,21 +606,16 @@ static int hdmi_audio_startup(struct device *dev, void (*abort_cb)(struct device *dev)) { struct omap_hdmi *hd = dev_get_drvdata(dev); - int ret = 0; mutex_lock(&hd->lock); - if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { - ret = -EPERM; - goto out; - } + WARN_ON(hd->audio_abort_cb != NULL); hd->audio_abort_cb = abort_cb; -out: mutex_unlock(&hd->lock); - return ret; + return 0; } static int hdmi_audio_shutdown(struct device *dev) @@ -641,12 +636,14 @@ static int hdmi_audio_start(struct device *dev) struct omap_hdmi *hd = dev_get_drvdata(dev); unsigned long flags; - WARN_ON(!hdmi_mode_has_audio(&hd->cfg)); - spin_lock_irqsave(&hd->audio_playing_lock, flags); - if (hd->display_enabled) + if (hd->display_enabled) { + if (!hdmi_mode_has_audio(&hd->cfg)) + DSSERR("%s: Video mode does not support audio\n", + __func__); hdmi_start_audio_stream(hd); + } hd->audio_playing = true; spin_unlock_irqrestore(&hd->audio_playing_lock, flags); @@ -658,7 +655,8 @@ static void hdmi_audio_stop(struct device *dev) struct omap_hdmi *hd = dev_get_drvdata(dev); unsigned long flags; - WARN_ON(!hdmi_mode_has_audio(&hd->cfg)); + if (!hdmi_mode_has_audio(&hd->cfg)) + DSSERR("%s: Video mode does not support audio\n", __func__); spin_lock_irqsave(&hd->audio_playing_lock, flags); @@ -677,18 +675,15 @@ static int hdmi_audio_config(struct device *dev, mutex_lock(&hd->lock); - if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { - ret = -EPERM; - goto out; + if (hd->display_enabled) { + ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio, + hd->cfg.vm.pixelclock); + if (ret) + goto out; } - ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio, - hd->cfg.vm.pixelclock); - - if (!ret) { - hd->audio_configured = true; - hd->audio_config = *dss_audio; - } + hd->audio_configured = true; + hd->audio_config = *dss_audio; out: mutex_unlock(&hd->lock); -- cgit v1.2.3 From 4cba7071b70de271415a4d9e8bfb1e420d5942b1 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 12 Sep 2016 10:00:15 +0300 Subject: drm/omap: cleanup color space conversion The setup code for color space conversion is a bit messy. This patch cleans it up. For some reason the TRM uses values in YCrCb order, which is also used in the current driver, whereas everywhere else it's YCbCr (which also matches YUV order). This patch changes the tables to use the common order to avoid confusion. The tables are split into separate lines, and comments added for clarity. WB color conversion registers are similar but different than non-WB, but the same function was used to write both. It worked fine because the coef table was adjusted accordingly, but that was rather confusing. This patch adds a separate function to write the WB values so that the coef table can be written in an understandable way. Recalculation also showed that 'bcb' value in yuv-to-rgb conversion had been rounded wrongly, and it should be 516 instead of 517. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/dss/dispc.c | 59 +++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 57960df1517a..5e2e65e88847 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -352,11 +352,6 @@ static const struct { }, }; -struct color_conv_coef { - int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; - int full_range; -}; - static unsigned long dispc_fclk_rate(struct dispc_device *dispc); static unsigned long dispc_core_clk_rate(struct dispc_device *dispc); static unsigned long dispc_mgr_lclk_rate(struct dispc_device *dispc, @@ -868,10 +863,19 @@ static void dispc_ovl_set_scale_coef(struct dispc_device *dispc, } } +struct csc_coef_yuv2rgb { + int ry, rcb, rcr, gy, gcb, gcr, by, bcb, bcr; + bool full_range; +}; + +struct csc_coef_rgb2yuv { + int yr, yg, yb, cbr, cbg, cbb, crr, crg, crb; + bool full_range; +}; static void dispc_ovl_write_color_conv_coef(struct dispc_device *dispc, enum omap_plane_id plane, - const struct color_conv_coef *ct) + const struct csc_coef_yuv2rgb *ct) { #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) @@ -886,25 +890,50 @@ static void dispc_ovl_write_color_conv_coef(struct dispc_device *dispc, #undef CVAL } +static void dispc_wb_write_color_conv_coef(struct dispc_device *dispc, + const struct csc_coef_rgb2yuv *ct) +{ + const enum omap_plane_id plane = OMAP_DSS_WB; + +#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) + + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->yg, ct->yr)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->crr, ct->yb)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->crb, ct->crg)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->cbg, ct->cbr)); + dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->cbb)); + + REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); + +#undef CVAL +} + static void dispc_setup_color_conv_coef(struct dispc_device *dispc) { int i; int num_ovl = dispc_get_num_ovls(dispc); - const struct color_conv_coef ctbl_bt601_5_ovl = { - /* YUV -> RGB */ - 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, + + /* YUV -> RGB, ITU-R BT.601, limited range */ + const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_lim = { + 298, 0, 409, /* ry, rcb, rcr */ + 298, -100, -208, /* gy, gcb, gcr */ + 298, 516, 0, /* by, bcb, bcr */ + false, /* limited range */ }; - const struct color_conv_coef ctbl_bt601_5_wb = { - /* RGB -> YUV */ - 66, 129, 25, 112, -94, -18, -38, -74, 112, 0, + + /* RGB -> YUV, ITU-R BT.601, limited range */ + const struct csc_coef_rgb2yuv coefs_rgb2yuv_bt601_lim = { + 66, 129, 25, /* yr, yg, yb */ + -38, -74, 112, /* cbr, cbg, cbb */ + 112, -94, -18, /* crr, crg, crb */ + false, /* limited range */ }; for (i = 1; i < num_ovl; i++) - dispc_ovl_write_color_conv_coef(dispc, i, &ctbl_bt601_5_ovl); + dispc_ovl_write_color_conv_coef(dispc, i, &coefs_yuv2rgb_bt601_lim); if (dispc->feat->has_writeback) - dispc_ovl_write_color_conv_coef(dispc, OMAP_DSS_WB, - &ctbl_bt601_5_wb); + dispc_wb_write_color_conv_coef(dispc, &coefs_rgb2yuv_bt601_lim); } static void dispc_ovl_set_ba0(struct dispc_device *dispc, -- cgit v1.2.3 From e64b6afa98f3629d0c0c46233bbdbe8acdb56f06 Mon Sep 17 00:00:00 2001 From: Giulio Benetti Date: Wed, 28 Feb 2018 17:46:53 +0100 Subject: drm/sun4i: Fix dclk_set_phase Phase value is not shifted before writing. Shift left of 28 bits to fit right bits Signed-off-by: Giulio Benetti Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/1519836413-35023-1-git-send-email-giulio.benetti@micronovasrl.com --- drivers/gpu/drm/sun4i/sun4i_dotclock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c index 023f39bda633..e36004fbe453 100644 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c @@ -132,10 +132,13 @@ static int sun4i_dclk_get_phase(struct clk_hw *hw) static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees) { struct sun4i_dclk *dclk = hw_to_dclk(hw); + u32 val = degrees / 120; + + val <<= 28; regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG, GENMASK(29, 28), - degrees / 120); + val); return 0; } -- cgit v1.2.3 From b758dbd57650b4157da98b2c734974b409849625 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 28 Feb 2018 12:09:56 +0100 Subject: platform/x86: intel-vbtn: Reset wakeup capable flag on removal The intel-vbtn device will not be able to wake up the system any more after removing the notify handler provided by its driver, so make its sysfs attributes reflect that. Fixes: 91f9e850d465 (platform: x86: intel-vbtn: Wake up the system from suspend-to-idle) Signed-off-by: Rafael J. Wysocki Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel-vbtn.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index 8173307d6bb1..c13780b8dabb 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -166,6 +166,7 @@ static int intel_vbtn_remove(struct platform_device *device) { acpi_handle handle = ACPI_HANDLE(&device->dev); + device_init_wakeup(&device->dev, false); acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); /* -- cgit v1.2.3 From 38c08aa54b50640302a6529f4b6eb441b3bfc5dd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 28 Feb 2018 12:10:59 +0100 Subject: platform/x86: intel-hid: Reset wakeup capable flag on removal The intel-hid device will not be able to wake up the system any more after removing the notify handler provided by its driver, so make its sysfs attributes reflect that. Fixes: ef884112e55c (platform: x86: intel-hid: Wake up the system from suspend-to-idle) Signed-off-by: Rafael J. Wysocki Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel-hid.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index d1a01311c1a2..5e3df194723e 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -376,6 +376,7 @@ static int intel_hid_remove(struct platform_device *device) { acpi_handle handle = ACPI_HANDLE(&device->dev); + device_init_wakeup(&device->dev, false); acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); intel_hid_set_enable(&device->dev, false); intel_button_array_enable(&device->dev, false); -- cgit v1.2.3 From 7d4e981d41e3338699d43803bf28d21b087cbbea Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Wed, 7 Feb 2018 18:53:09 +0100 Subject: drm/rockchip: Add device links for master and components Since we are trying to access components' resources in the master's suspend/resume PM callbacks(e.g. panel), add device links to correct the suspend/resume and shutdown ordering. Signed-off-by: Jeffy Chen Signed-off-by: Enric Balletbo i Serra Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20180207175309.21095-1-enric.balletbo@collabora.com --- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 88084ca15115..1920334dbdaa 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -314,6 +314,14 @@ static int compare_dev(struct device *dev, void *data) return dev == (struct device *)data; } +static void rockchip_drm_match_remove(struct device *dev) +{ + struct device_link *link; + + list_for_each_entry(link, &dev->links.consumers, s_node) + device_link_del(link); +} + static struct component_match *rockchip_drm_match_add(struct device *dev) { struct component_match *match = NULL; @@ -331,10 +339,15 @@ static struct component_match *rockchip_drm_match_add(struct device *dev) if (!d) break; + + device_link_add(dev, d, DL_FLAG_STATELESS); component_match_add(dev, &match, compare_dev, d); } while (true); } + if (IS_ERR(match)) + rockchip_drm_match_remove(dev); + return match ?: ERR_PTR(-ENODEV); } @@ -411,13 +424,21 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev) if (IS_ERR(match)) return PTR_ERR(match); - return component_master_add_with_match(dev, &rockchip_drm_ops, match); + ret = component_master_add_with_match(dev, &rockchip_drm_ops, match); + if (ret < 0) { + rockchip_drm_match_remove(dev); + return ret; + } + + return 0; } static int rockchip_drm_platform_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &rockchip_drm_ops); + rockchip_drm_match_remove(&pdev->dev); + return 0; } -- cgit v1.2.3 From ce91d373d870b69b5dbbac033d8411ef0c16ac6f Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Fri, 23 Feb 2018 14:22:50 +0800 Subject: drm/rockchip: vop: Init vskiplines in scl_vop_cal_scale() Currently we are calling scl_vop_cal_scale() to get vskiplines for yrgb and cbcr. So the cbcr's vskiplines might be an unexpected value if the second scl_vop_cal_scale() didn't update it. Init vskiplines in scl_vop_cal_scale() to avoid that. Signed-off-by: Jeffy Chen Reviewed-by: Sean Paul Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20180223062250.10470-1-jeffy.chen@rock-chips.com --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 66736227c96e..9f72762532bf 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -256,6 +256,9 @@ static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, { uint16_t val = 1 << SCL_FT_DEFAULT_FIXPOINT_SHIFT; + if (vskiplines) + *vskiplines = 0; + if (is_horizontal) { if (mode == SCALE_UP) val = GET_SCL_FT_BIC(src, dst); @@ -296,7 +299,7 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, uint16_t vsu_mode; uint16_t lb_mode; uint32_t val; - int vskiplines = 0; + int vskiplines; if (dst_w > 3840) { DRM_DEV_ERROR(vop->dev, "Maximum dst width (3840) exceeded\n"); -- cgit v1.2.3 From 6b2d8fd98d051f8697c45f96249dca73842a2362 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Wed, 10 Jan 2018 17:23:41 +0100 Subject: drm/bridge: analogix: Do not use device's drvdata The driver that instantiates the bridge should own the drvdata, as all driver model callbacks (probe, remove, shutdown, PM ops, etc.) are also owned by its driver struct. Moreover, storing two different pointer types in driver data depending on driver initialization status is barely a good practice and in fact has led to many bugs in this driver. Let's clean up this mess and change Analogix entry points to simply accept some opaque struct pointer, adjusting their users at the same time to avoid breaking the compilation. Signed-off-by: Tomasz Figa Signed-off-by: Jeffy Chen Signed-off-by: Thierry Escande Reviewed-by: Andrzej Hajda Reviewed-by: Sean Paul Acked-by: Jingoo Han Acked-by: Archit Taneja Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20180110162348.22765-2-thierry.escande@collabora.com --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 +++++++++------------- drivers/gpu/drm/exynos/exynos_dp.c | 26 ++++++----- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 48 ++++++++++++--------- 3 files changed, 63 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index b2756bc4225a..5940dc4eac6c 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -98,17 +98,15 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } -int analogix_dp_psr_supported(struct device *dev) +int analogix_dp_psr_supported(struct analogix_dp_device *dp) { - struct analogix_dp_device *dp = dev_get_drvdata(dev); return dp->psr_support; } EXPORT_SYMBOL_GPL(analogix_dp_psr_supported); -int analogix_dp_enable_psr(struct device *dev) +int analogix_dp_enable_psr(struct analogix_dp_device *dp) { - struct analogix_dp_device *dp = dev_get_drvdata(dev); struct edp_vsc_psr psr_vsc; if (!dp->psr_support) @@ -129,9 +127,8 @@ int analogix_dp_enable_psr(struct device *dev) } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); -int analogix_dp_disable_psr(struct device *dev) +int analogix_dp_disable_psr(struct analogix_dp_device *dp) { - struct analogix_dp_device *dp = dev_get_drvdata(dev); struct edp_vsc_psr psr_vsc; int ret; @@ -1279,8 +1276,9 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux, return analogix_dp_transfer(dp, msg); } -int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, - struct analogix_dp_plat_data *plat_data) +struct analogix_dp_device * +analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, + struct analogix_dp_plat_data *plat_data) { struct platform_device *pdev = to_platform_device(dev); struct analogix_dp_device *dp; @@ -1290,14 +1288,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, if (!plat_data) { dev_err(dev, "Invalided input plat_data\n"); - return -EINVAL; + return ERR_PTR(-EINVAL); } dp = devm_kzalloc(dev, sizeof(struct analogix_dp_device), GFP_KERNEL); if (!dp) - return -ENOMEM; - - dev_set_drvdata(dev, dp); + return ERR_PTR(-ENOMEM); dp->dev = &pdev->dev; dp->dpms_mode = DRM_MODE_DPMS_OFF; @@ -1314,7 +1310,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, ret = analogix_dp_dt_parse_pdata(dp); if (ret) - return ret; + return ERR_PTR(ret); dp->phy = devm_phy_get(dp->dev, "dp"); if (IS_ERR(dp->phy)) { @@ -1328,14 +1324,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, if (ret == -ENOSYS || ret == -ENODEV) dp->phy = NULL; else - return ret; + return ERR_PTR(ret); } } dp->clock = devm_clk_get(&pdev->dev, "dp"); if (IS_ERR(dp->clock)) { dev_err(&pdev->dev, "failed to get clock\n"); - return PTR_ERR(dp->clock); + return ERR_CAST(dp->clock); } clk_prepare_enable(dp->clock); @@ -1344,7 +1340,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, dp->reg_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dp->reg_base)) - return PTR_ERR(dp->reg_base); + return ERR_CAST(dp->reg_base); dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd"); @@ -1365,7 +1361,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, "hpd_gpio"); if (ret) { dev_err(&pdev->dev, "failed to get hpd gpio\n"); - return ret; + return ERR_PTR(ret); } dp->irq = gpio_to_irq(dp->hpd_gpio); irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; @@ -1377,7 +1373,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, if (dp->irq == -ENXIO) { dev_err(&pdev->dev, "failed to get irq\n"); - return -ENODEV; + return ERR_PTR(-ENODEV); } pm_runtime_enable(dev); @@ -1418,7 +1414,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, phy_power_off(dp->phy); pm_runtime_put(dev); - return 0; + return dp; err_disable_pm_runtime: @@ -1426,15 +1422,12 @@ err_disable_pm_runtime: pm_runtime_put(dev); pm_runtime_disable(dev); - return ret; + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(analogix_dp_bind); -void analogix_dp_unbind(struct device *dev, struct device *master, - void *data) +void analogix_dp_unbind(struct analogix_dp_device *dp) { - struct analogix_dp_device *dp = dev_get_drvdata(dev); - analogix_dp_bridge_disable(dp->bridge); dp->connector.funcs->destroy(&dp->connector); dp->encoder->funcs->destroy(dp->encoder); @@ -1447,16 +1440,14 @@ void analogix_dp_unbind(struct device *dev, struct device *master, } drm_dp_aux_unregister(&dp->aux); - pm_runtime_disable(dev); + pm_runtime_disable(dp->dev); clk_disable_unprepare(dp->clock); } EXPORT_SYMBOL_GPL(analogix_dp_unbind); #ifdef CONFIG_PM -int analogix_dp_suspend(struct device *dev) +int analogix_dp_suspend(struct analogix_dp_device *dp) { - struct analogix_dp_device *dp = dev_get_drvdata(dev); - clk_disable_unprepare(dp->clock); if (dp->plat_data->panel) { @@ -1468,9 +1459,8 @@ int analogix_dp_suspend(struct device *dev) } EXPORT_SYMBOL_GPL(analogix_dp_suspend); -int analogix_dp_resume(struct device *dev) +int analogix_dp_resume(struct analogix_dp_device *dp) { - struct analogix_dp_device *dp = dev_get_drvdata(dev); int ret; ret = clk_prepare_enable(dp->clock); diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index 39629e7a80b9..f7e5b2c405ed 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -41,6 +41,7 @@ struct exynos_dp_device { struct device *dev; struct videomode vm; + struct analogix_dp_device *adp; struct analogix_dp_plat_data plat_data; }; @@ -157,13 +158,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) struct drm_device *drm_dev = data; int ret; - /* - * Just like the probe function said, we don't need the - * device drvrate anymore, we should leave the charge to - * analogix dp driver, set the device drvdata to NULL. - */ - dev_set_drvdata(dev, NULL); - dp->dev = dev; dp->drm_dev = drm_dev; @@ -190,13 +184,19 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) dp->plat_data.encoder = encoder; - return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); + dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); + if (IS_ERR(dp->adp)) + return PTR_ERR(dp->adp); + + return 0; } static void exynos_dp_unbind(struct device *dev, struct device *master, void *data) { - return analogix_dp_unbind(dev, master, data); + struct exynos_dp_device *dp = dev_get_drvdata(dev); + + return analogix_dp_unbind(dp->adp); } static const struct component_ops exynos_dp_ops = { @@ -257,12 +257,16 @@ static int exynos_dp_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int exynos_dp_suspend(struct device *dev) { - return analogix_dp_suspend(dev); + struct exynos_dp_device *dp = dev_get_drvdata(dev); + + return analogix_dp_suspend(dp->adp); } static int exynos_dp_resume(struct device *dev) { - return analogix_dp_resume(dev); + struct exynos_dp_device *dp = dev_get_drvdata(dev); + + return analogix_dp_resume(dp->adp); } #endif diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 1262120a3834..8a58ad80f509 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -77,6 +77,7 @@ struct rockchip_dp_device { const struct rockchip_dp_chip_data *data; + struct analogix_dp_device *adp; struct analogix_dp_plat_data plat_data; }; @@ -84,7 +85,7 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) { struct rockchip_dp_device *dp = to_dp(encoder); - if (!analogix_dp_psr_supported(dp->dev)) + if (!analogix_dp_psr_supported(dp->adp)) return; DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); @@ -114,9 +115,9 @@ static void analogix_dp_psr_work(struct work_struct *work) mutex_lock(&dp->psr_lock); if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE) - analogix_dp_enable_psr(dp->dev); + analogix_dp_enable_psr(dp->adp); else - analogix_dp_disable_psr(dp->dev); + analogix_dp_disable_psr(dp->adp); mutex_unlock(&dp->psr_lock); } @@ -334,13 +335,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, struct drm_device *drm_dev = data; int ret; - /* - * Just like the probe function said, we don't need the - * device drvrate anymore, we should leave the charge to - * analogix dp driver, set the device drvdata to NULL. - */ - dev_set_drvdata(dev, NULL); - dp_data = of_device_get_match_data(dev); if (!dp_data) return -ENODEV; @@ -367,7 +361,11 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); - return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); + dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); + if (IS_ERR(dp->adp)) + return PTR_ERR(dp->adp); + + return 0; } static void rockchip_dp_unbind(struct device *dev, struct device *master, @@ -376,8 +374,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master, struct rockchip_dp_device *dp = dev_get_drvdata(dev); rockchip_drm_psr_unregister(&dp->encoder); - - analogix_dp_unbind(dev, master, data); + analogix_dp_unbind(dp->adp); } static const struct component_ops rockchip_dp_component_ops = { @@ -407,11 +404,6 @@ static int rockchip_dp_probe(struct platform_device *pdev) if (ret < 0) return ret; - /* - * We just use the drvdata until driver run into component - * add function, and then we would set drvdata to null, so - * that analogix dp driver could take charge of the drvdata. - */ platform_set_drvdata(pdev, dp); return component_add(dev, &rockchip_dp_component_ops); @@ -424,10 +416,26 @@ static int rockchip_dp_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int rockchip_dp_suspend(struct device *dev) +{ + struct rockchip_dp_device *dp = dev_get_drvdata(dev); + + return analogix_dp_suspend(dp->adp); +} + +static int rockchip_dp_resume(struct device *dev) +{ + struct rockchip_dp_device *dp = dev_get_drvdata(dev); + + return analogix_dp_resume(dp->adp); +} +#endif + static const struct dev_pm_ops rockchip_dp_pm_ops = { #ifdef CONFIG_PM_SLEEP - .suspend = analogix_dp_suspend, - .resume_early = analogix_dp_resume, + .suspend = rockchip_dp_suspend, + .resume_early = rockchip_dp_resume, #endif }; -- cgit v1.2.3 From 7fe201cd55bb3527c4b7152fc099a3c5fb9054c3 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Wed, 10 Jan 2018 17:23:42 +0100 Subject: drm/bridge: analogix_dp: Fix connector and encoder cleanup Since we are initing connector in the core driver and encoder in the plat driver, let's clean them up in the right places. Signed-off-by: Jeffy Chen Signed-off-by: Thierry Escande Reviewed-by: Andrzej Hajda Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20180110162348.22765-3-thierry.escande@collabora.com --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 2 -- drivers/gpu/drm/exynos/exynos_dp.c | 7 +++++-- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 12 +++++------- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5940dc4eac6c..3f7a796b27e4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1407,7 +1407,6 @@ analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, ret = analogix_dp_create_bridge(drm_dev, dp); if (ret) { DRM_ERROR("failed to create bridge (%d)\n", ret); - drm_encoder_cleanup(dp->encoder); goto err_disable_pm_runtime; } @@ -1430,7 +1429,6 @@ void analogix_dp_unbind(struct analogix_dp_device *dp) { analogix_dp_bridge_disable(dp->bridge); dp->connector.funcs->destroy(&dp->connector); - dp->encoder->funcs->destroy(dp->encoder); if (dp->plat_data->panel) { if (drm_panel_unprepare(dp->plat_data->panel)) diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index f7e5b2c405ed..33319a858f3a 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -185,8 +185,10 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) dp->plat_data.encoder = encoder; dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); - if (IS_ERR(dp->adp)) + if (IS_ERR(dp->adp)) { + dp->encoder.funcs->destroy(&dp->encoder); return PTR_ERR(dp->adp); + } return 0; } @@ -196,7 +198,8 @@ static void exynos_dp_unbind(struct device *dev, struct device *master, { struct exynos_dp_device *dp = dev_get_drvdata(dev); - return analogix_dp_unbind(dp->adp); + analogix_dp_unbind(dp->adp); + dp->encoder.funcs->destroy(&dp->encoder); } static const struct component_ops exynos_dp_ops = { diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 8a58ad80f509..37250ab63bd7 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -259,13 +259,8 @@ static struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = { .atomic_check = rockchip_dp_drm_encoder_atomic_check, }; -static void rockchip_dp_drm_encoder_destroy(struct drm_encoder *encoder) -{ - drm_encoder_cleanup(encoder); -} - static struct drm_encoder_funcs rockchip_dp_encoder_funcs = { - .destroy = rockchip_dp_drm_encoder_destroy, + .destroy = drm_encoder_cleanup, }; static int rockchip_dp_of_probe(struct rockchip_dp_device *dp) @@ -362,8 +357,10 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); - if (IS_ERR(dp->adp)) + if (IS_ERR(dp->adp)) { + dp->encoder.funcs->destroy(&dp->encoder); return PTR_ERR(dp->adp); + } return 0; } @@ -375,6 +372,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master, rockchip_drm_psr_unregister(&dp->encoder); analogix_dp_unbind(dp->adp); + dp->encoder.funcs->destroy(&dp->encoder); } static const struct component_ops rockchip_dp_component_ops = { -- cgit v1.2.3 From c8c045142125e7c054f66241d9f3b3151bb70daf Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Wed, 10 Jan 2018 17:23:43 +0100 Subject: drm/rockchip: analogix_dp: Add a sanity check for rockchip_drm_psr_register() The rockchip_drm_psr_register() can fail, so add a sanity check for that. Signed-off-by: Jeffy Chen Signed-off-by: Thierry Escande [moved psr_unregister reordering in unbind to separate patch] Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20180110162348.22765-4-thierry.escande@collabora.com --- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 37250ab63bd7..ea47573f5b75 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -354,15 +354,22 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; INIT_WORK(&dp->psr_work, analogix_dp_psr_work); - rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); + ret = rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); + if (ret < 0) + goto err_cleanup_encoder; dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); if (IS_ERR(dp->adp)) { - dp->encoder.funcs->destroy(&dp->encoder); - return PTR_ERR(dp->adp); + ret = PTR_ERR(dp->adp); + goto err_unreg_psr; } return 0; +err_unreg_psr: + rockchip_drm_psr_unregister(&dp->encoder); +err_cleanup_encoder: + dp->encoder.funcs->destroy(&dp->encoder); + return ret; } static void rockchip_dp_unbind(struct device *dev, struct device *master, -- cgit v1.2.3 From d8e7e73e66d0566a82cb91642680ec0d1f77eda6 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Thu, 1 Mar 2018 16:25:58 +0100 Subject: drm/rockchip: analogix_dp: reorder psr_unregister call in unbind In bind the psr handler gets registered first before the core analogix_dp_bind() gets called. So it should be the other way around in unbind, first unbind the analogix_dp and then unregister the psr. Signed-off-by: Jeffy Chen Signed-off-by: Thierry Escande Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/76025075.yWNtk1v57f@phil --- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index ea47573f5b75..eb88c52336a7 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -377,8 +377,8 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master, { struct rockchip_dp_device *dp = dev_get_drvdata(dev); - rockchip_drm_psr_unregister(&dp->encoder); analogix_dp_unbind(dp->adp); + rockchip_drm_psr_unregister(&dp->encoder); dp->encoder.funcs->destroy(&dp->encoder); } -- cgit v1.2.3 From 158e61865a31ef7abf39629c37285810504d60b5 Mon Sep 17 00:00:00 2001 From: Jiufei Xue Date: Tue, 27 Feb 2018 20:10:22 +0800 Subject: block: fix a typo Fix a typo in pkt_start_recovery. Fixes: 74d46992e0d9 ("block: replace bi_bdev with a gendisk pointer and partitions index") Reviewed-by: Christoph Hellwig Signed-off-by: Jiufei Xue Signed-off-by: Jens Axboe --- drivers/block/pktcdvd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 531a0915066b..c61d20c9f3f8 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1122,7 +1122,7 @@ static int pkt_start_recovery(struct packet_data *pkt) pkt->sector = new_sector; bio_reset(pkt->bio); - bio_set_set(pkt->bio, pd->bdev); + bio_set_dev(pkt->bio, pd->bdev); bio_set_op_attrs(pkt->bio, REQ_OP_WRITE, 0); pkt->bio->bi_iter.bi_sector = new_sector; pkt->bio->bi_iter.bi_size = pkt->frames * CD_FRAMESIZE; -- cgit v1.2.3 From 651438bb0af5213f1f70d66e75bf11d08cb5537a Mon Sep 17 00:00:00 2001 From: Wen Xiong Date: Thu, 15 Feb 2018 14:05:10 -0600 Subject: nvme-pci: Fix EEH failure on ppc Triggering PPC EEH detection and handling requires a memory mapped read failure. The NVMe driver removed the periodic health check MMIO, so there's no early detection mechanism to trigger the recovery. Instead, the detection now happens when the nvme driver handles an IO timeout event. This takes the pci channel offline, so we do not want the driver to proceed with escalating its own recovery efforts that may conflict with the EEH handler. This patch ensures the driver will observe the channel was set to offline after a failed MMIO read and resets the IO timer so the EEH handler has a chance to recover the device. Signed-off-by: Wen Xiong [updated change log] Signed-off-by: Keith Busch --- drivers/nvme/host/pci.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 5933a5c732e8..e5ce07f4966f 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1153,12 +1153,6 @@ static bool nvme_should_reset(struct nvme_dev *dev, u32 csts) if (!(csts & NVME_CSTS_CFS) && !nssro) return false; - /* If PCI error recovery process is happening, we cannot reset or - * the recovery mechanism will surely fail. - */ - if (pci_channel_offline(to_pci_dev(dev->dev))) - return false; - return true; } @@ -1189,6 +1183,13 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved) struct nvme_command cmd; u32 csts = readl(dev->bar + NVME_REG_CSTS); + /* If PCI error recovery process is happening, we cannot reset or + * the recovery mechanism will surely fail. + */ + mb(); + if (pci_channel_offline(to_pci_dev(dev->dev))) + return BLK_EH_RESET_TIMER; + /* * Reset immediately if the controller is failed */ -- cgit v1.2.3 From cb57469c9573f6018cd1302953dd45d6e05aba7b Mon Sep 17 00:00:00 2001 From: Joel Fernandes Date: Fri, 16 Feb 2018 11:02:01 -0800 Subject: staging: android: ashmem: Fix lockdep issue during llseek ashmem_mutex create a chain of dependencies like so: (1) mmap syscall -> mmap_sem -> (acquired) ashmem_mmap ashmem_mutex (try to acquire) (block) (2) llseek syscall -> ashmem_llseek -> ashmem_mutex -> (acquired) inode_lock -> inode->i_rwsem (try to acquire) (block) (3) getdents -> iterate_dir -> inode_lock -> inode->i_rwsem (acquired) copy_to_user -> mmap_sem (try to acquire) There is a lock ordering created between mmap_sem and inode->i_rwsem causing a lockdep splat [2] during a syzcaller test, this patch fixes the issue by unlocking the mutex earlier. Functionally that's Ok since we don't need to protect vfs_llseek. [1] https://patchwork.kernel.org/patch/10185031/ [2] https://lkml.org/lkml/2018/1/10/48 Acked-by: Todd Kjos Cc: Arve Hjonnevag Cc: stable@vger.kernel.org Reported-by: syzbot+8ec30bb7bf1a981a2012@syzkaller.appspotmail.com Signed-off-by: Joel Fernandes Acked-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ashmem.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 6dbba5aff191..d5450365769c 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -326,24 +326,23 @@ static loff_t ashmem_llseek(struct file *file, loff_t offset, int origin) mutex_lock(&ashmem_mutex); if (asma->size == 0) { - ret = -EINVAL; - goto out; + mutex_unlock(&ashmem_mutex); + return -EINVAL; } if (!asma->file) { - ret = -EBADF; - goto out; + mutex_unlock(&ashmem_mutex); + return -EBADF; } + mutex_unlock(&ashmem_mutex); + ret = vfs_llseek(asma->file, offset, origin); if (ret < 0) - goto out; + return ret; /** Copy f_pos from backing file, since f_ops->llseek() sets it */ file->f_pos = asma->file->f_pos; - -out: - mutex_unlock(&ashmem_mutex); return ret; } -- cgit v1.2.3 From 16ccfff2897613007b5eda9e29d65303c6280026 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 6 Feb 2018 20:17:42 +0800 Subject: nvme: pci: pass max vectors as num_possible_cpus() to pci_alloc_irq_vectors 84676c1f21 ("genirq/affinity: assign vectors to all possible CPUs") has switched to do irq vectors spread among all possible CPUs, so pass num_possible_cpus() as max vecotrs to be assigned. For example, in a 8 cores system, 0~3 online, 4~8 offline/not present, see 'lscpu': [ming@box]$lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 4 On-line CPU(s) list: 0-3 Thread(s) per core: 1 Core(s) per socket: 2 Socket(s): 2 NUMA node(s): 2 ... NUMA node0 CPU(s): 0-3 NUMA node1 CPU(s): ... 1) before this patch, follows the allocated vectors and their affinity: irq 47, cpu list 0,4 irq 48, cpu list 1,6 irq 49, cpu list 2,5 irq 50, cpu list 3,7 2) after this patch, follows the allocated vectors and their affinity: irq 43, cpu list 0 irq 44, cpu list 1 irq 45, cpu list 2 irq 46, cpu list 3 irq 47, cpu list 4 irq 48, cpu list 6 irq 49, cpu list 5 irq 50, cpu list 7 Cc: Keith Busch Cc: Sagi Grimberg Cc: Thomas Gleixner Cc: Christoph Hellwig Signed-off-by: Ming Lei Reviewed-by: Christoph Hellwig Signed-off-by: Keith Busch --- drivers/nvme/host/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index e5ce07f4966f..b6f43b738f03 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1914,7 +1914,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) int result, nr_io_queues; unsigned long size; - nr_io_queues = num_present_cpus(); + nr_io_queues = num_possible_cpus(); result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues); if (result < 0) return result; -- cgit v1.2.3 From 711826656bebb09b814349fac21cb13f88f92665 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Mon, 25 Dec 2017 15:14:58 +0800 Subject: drm/amdgpu: stop all rings before doing gpu recover MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit found recover_vram_from_shadow sometimes get executed in paralle with SDMA scheduler, should stop all schedulers before doing gpu reset/recover Signed-off-by: Monk Liu Reviewed-by: Christian König Tested-by: Andrey Grodzovsky Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 40 +++++++++++------------------- 1 file changed, 15 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 41244858df64..64bd30075951 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2648,22 +2648,23 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, /* block TTM */ resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); + /* store modesetting */ if (amdgpu_device_has_dc_support(adev)) state = drm_atomic_helper_suspend(adev->ddev); - /* block scheduler */ + /* block all schedulers and reset given job's ring */ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; if (!ring || !ring->sched.thread) continue; - /* only focus on the ring hit timeout if &job not NULL */ + kthread_park(ring->sched.thread); + if (job && job->ring->idx != i) continue; - kthread_park(ring->sched.thread); drm_sched_hw_job_reset(&ring->sched, &job->base); /* after all hw jobs are reset, hw fence is meaningless, so force_completion */ @@ -2706,33 +2707,22 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, } dma_fence_put(fence); } + } - for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { - struct amdgpu_ring *ring = adev->rings[i]; - - if (!ring || !ring->sched.thread) - continue; + for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { + struct amdgpu_ring *ring = adev->rings[i]; - /* only focus on the ring hit timeout if &job not NULL */ - if (job && job->ring->idx != i) - continue; + if (!ring || !ring->sched.thread) + continue; + /* only need recovery sched of the given job's ring + * or all rings (in the case @job is NULL) + * after above amdgpu_reset accomplished + */ + if ((!job || job->ring->idx == i) && !r) drm_sched_job_recovery(&ring->sched); - kthread_unpark(ring->sched.thread); - } - } else { - for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { - struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) - continue; - - /* only focus on the ring hit timeout if &job not NULL */ - if (job && job->ring->idx != i) - continue; - - kthread_unpark(adev->rings[i]->sched.thread); - } + kthread_unpark(ring->sched.thread); } if (amdgpu_device_has_dc_support(adev)) { -- cgit v1.2.3 From c41d1cf62d3615294c1dee291b05ee3220a4de6c Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Mon, 25 Dec 2017 11:59:27 +0800 Subject: drm/amdgpu: cleanups for vram lost handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1)create a routine "handle_vram_lost" to do the vram recovery, and put it into amdgpu_device_reset/reset_sriov, this way no need of the extra paramter to hold the VRAM LOST information and the related macros can be removed. 3)show vram_recover failure if time out, and set TMO equal to lockup_timeout if vram_recover is under SRIOV runtime mode. 4)report error if any ip reset failed for SR-IOV Signed-off-by: Monk Liu Acked-by: Christian König Acked-by: Andrey Grodzovsky Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 4 - drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 137 +++++++++++++++-------------- 2 files changed, 72 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index f281fa8cc831..86fbc8649af0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -181,10 +181,6 @@ extern int amdgpu_cik_support; #define CIK_CURSOR_WIDTH 128 #define CIK_CURSOR_HEIGHT 128 -/* GPU RESET flags */ -#define AMDGPU_RESET_INFO_VRAM_LOST (1 << 0) -#define AMDGPU_RESET_INFO_FULLRESET (1 << 1) - struct amdgpu_device; struct amdgpu_ib; struct amdgpu_cs_parser; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 64bd30075951..856378434ea2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1591,6 +1591,8 @@ static int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev) r = block->version->funcs->hw_init(adev); DRM_INFO("RE-INIT: %s %s\n", block->version->funcs->name, r?"failed":"successed"); + if (r) + return r; } } @@ -1624,6 +1626,8 @@ static int amdgpu_device_ip_reinit_late_sriov(struct amdgpu_device *adev) r = block->version->funcs->hw_init(adev); DRM_INFO("RE-INIT: %s %s\n", block->version->funcs->name, r?"failed":"successed"); + if (r) + return r; } } @@ -2470,17 +2474,71 @@ err: return r; } +static int amdgpu_device_handle_vram_lost(struct amdgpu_device *adev) +{ + struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; + struct amdgpu_bo *bo, *tmp; + struct dma_fence *fence = NULL, *next = NULL; + long r = 1; + int i = 0; + long tmo; + + if (amdgpu_sriov_runtime(adev)) + tmo = msecs_to_jiffies(amdgpu_lockup_timeout); + else + tmo = msecs_to_jiffies(100); + + DRM_INFO("recover vram bo from shadow start\n"); + mutex_lock(&adev->shadow_list_lock); + list_for_each_entry_safe(bo, tmp, &adev->shadow_list, shadow_list) { + next = NULL; + amdgpu_device_recover_vram_from_shadow(adev, ring, bo, &next); + if (fence) { + r = dma_fence_wait_timeout(fence, false, tmo); + if (r == 0) + pr_err("wait fence %p[%d] timeout\n", fence, i); + else if (r < 0) + pr_err("wait fence %p[%d] interrupted\n", fence, i); + if (r < 1) { + dma_fence_put(fence); + fence = next; + break; + } + i++; + } + + dma_fence_put(fence); + fence = next; + } + mutex_unlock(&adev->shadow_list_lock); + + if (fence) { + r = dma_fence_wait_timeout(fence, false, tmo); + if (r == 0) + pr_err("wait fence %p[%d] timeout\n", fence, i); + else if (r < 0) + pr_err("wait fence %p[%d] interrupted\n", fence, i); + + } + dma_fence_put(fence); + + if (r > 0) + DRM_INFO("recover vram bo from shadow done\n"); + else + DRM_ERROR("recover vram bo from shadow failed\n"); + + return (r > 0?0:1); +} + /* * amdgpu_device_reset - reset ASIC/GPU for bare-metal or passthrough * * @adev: amdgpu device pointer - * @reset_flags: output param tells caller the reset result * * attempt to do soft-reset or full-reset and reinitialize Asic * return 0 means successed otherwise failed */ -static int amdgpu_device_reset(struct amdgpu_device *adev, - uint64_t* reset_flags) +static int amdgpu_device_reset(struct amdgpu_device *adev) { bool need_full_reset, vram_lost = 0; int r; @@ -2495,7 +2553,6 @@ static int amdgpu_device_reset(struct amdgpu_device *adev, DRM_INFO("soft reset failed, will fallback to full reset!\n"); need_full_reset = true; } - } if (need_full_reset) { @@ -2544,13 +2601,8 @@ out: } } - if (reset_flags) { - if (vram_lost) - (*reset_flags) |= AMDGPU_RESET_INFO_VRAM_LOST; - - if (need_full_reset) - (*reset_flags) |= AMDGPU_RESET_INFO_FULLRESET; - } + if (!r && ((need_full_reset && !(adev->flags & AMD_IS_APU)) || vram_lost)) + r = amdgpu_device_handle_vram_lost(adev); return r; } @@ -2559,14 +2611,11 @@ out: * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf * * @adev: amdgpu device pointer - * @reset_flags: output param tells caller the reset result * * do VF FLR and reinitialize Asic * return 0 means successed otherwise failed */ -static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, - uint64_t *reset_flags, - bool from_hypervisor) +static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, bool from_hypervisor) { int r; @@ -2587,28 +2636,20 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, /* now we are okay to resume SMC/CP/SDMA */ r = amdgpu_device_ip_reinit_late_sriov(adev); + amdgpu_virt_release_full_gpu(adev, true); if (r) goto error; amdgpu_irq_gpu_reset_resume_helper(adev); r = amdgpu_ib_ring_tests(adev); - if (r) - dev_err(adev->dev, "[GPU_RESET] ib ring test failed (%d).\n", r); -error: - /* release full control of GPU after ib test */ - amdgpu_virt_release_full_gpu(adev, true); - - if (reset_flags) { - if (adev->virt.gim_feature & AMDGIM_FEATURE_GIM_FLR_VRAMLOST) { - (*reset_flags) |= AMDGPU_RESET_INFO_VRAM_LOST; - atomic_inc(&adev->vram_lost_counter); - } - - /* VF FLR or hotlink reset is always full-reset */ - (*reset_flags) |= AMDGPU_RESET_INFO_FULLRESET; + if (!r && adev->virt.gim_feature & AMDGIM_FEATURE_GIM_FLR_VRAMLOST) { + atomic_inc(&adev->vram_lost_counter); + r = amdgpu_device_handle_vram_lost(adev); } +error: + return r; } @@ -2626,7 +2667,6 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, struct amdgpu_job *job, bool force) { struct drm_atomic_state *state = NULL; - uint64_t reset_flags = 0; int i, r, resched; if (!force && !amdgpu_device_ip_check_soft_reset(adev)) { @@ -2672,42 +2712,9 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, } if (amdgpu_sriov_vf(adev)) - r = amdgpu_device_reset_sriov(adev, &reset_flags, job ? false : true); + r = amdgpu_device_reset_sriov(adev, job ? false : true); else - r = amdgpu_device_reset(adev, &reset_flags); - - if (!r) { - if (((reset_flags & AMDGPU_RESET_INFO_FULLRESET) && !(adev->flags & AMD_IS_APU)) || - (reset_flags & AMDGPU_RESET_INFO_VRAM_LOST)) { - struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; - struct amdgpu_bo *bo, *tmp; - struct dma_fence *fence = NULL, *next = NULL; - - DRM_INFO("recover vram bo from shadow\n"); - mutex_lock(&adev->shadow_list_lock); - list_for_each_entry_safe(bo, tmp, &adev->shadow_list, shadow_list) { - next = NULL; - amdgpu_device_recover_vram_from_shadow(adev, ring, bo, &next); - if (fence) { - r = dma_fence_wait(fence, false); - if (r) { - WARN(r, "recovery from shadow isn't completed\n"); - break; - } - } - - dma_fence_put(fence); - fence = next; - } - mutex_unlock(&adev->shadow_list_lock); - if (fence) { - r = dma_fence_wait(fence, false); - if (r) - WARN(r, "recovery from shadow isn't completed\n"); - } - dma_fence_put(fence); - } - } + r = amdgpu_device_reset(adev); for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; -- cgit v1.2.3 From e82df670235138575b37ff0ec24412a471efd97f Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Fri, 23 Feb 2018 19:41:30 +0800 Subject: virtio_ring: fix num_free handling in error case The vq->vq.num_free hasn't been changed when error happens, so it shouldn't be changed when handling the error. Fixes: 780bc7903a32 ("virtio_ring: Support DMA APIs") Cc: Andy Lutomirski Cc: Michael S. Tsirkin Cc: stable@vger.kernel.org Signed-off-by: Tiwei Bie Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_ring.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index eb30f3e09a47..71458f493cf8 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -428,8 +428,6 @@ unmap_release: i = virtio16_to_cpu(_vq->vdev, vq->vring.desc[i].next); } - vq->vq.num_free += total_sg; - if (indirect) kfree(desc); -- cgit v1.2.3 From a22144a58f784265fe8140724a7390443f63ef53 Mon Sep 17 00:00:00 2001 From: Monk Liu Date: Mon, 25 Dec 2017 15:59:30 +0800 Subject: drm/amdgpu: try again kiq access if not in IRQ(v4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sometimes GPU is switched to other VFs and won't swich back soon, so the kiq reg access will not signal within a short period, instead of busy waiting a long time(MAX_KEQ_REG_WAIT) and returning TMO we can istead sleep 5ms and try again later (non irq context) And since the waiting in kiq_r/weg is busy wait, so MAX_KIQ_REG_WAIT shouldn't set to a long time, set it to 10ms is more appropriate. if gpu already in reset state, don't retry the KIQ reg access otherwise it would always hang because KIQ was already die usually. v2: replace schedule() with msleep() for the wait v3: use while loop for the wait repeating use macros for the sleep period more description for it v4: drop unused variable Signed-off-by: Monk Liu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 64 ++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index b832651d2137..42c140155b70 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -22,7 +22,9 @@ */ #include "amdgpu.h" -#define MAX_KIQ_REG_WAIT 100000000 /* in usecs */ +#define MAX_KIQ_REG_WAIT 5000 /* in usecs, 5ms */ +#define MAX_KIQ_REG_BAILOUT_INTERVAL 5 /* in msecs, 5ms */ +#define MAX_KIQ_REG_TRY 20 uint64_t amdgpu_csa_vaddr(struct amdgpu_device *adev) { @@ -137,9 +139,9 @@ void amdgpu_virt_init_setting(struct amdgpu_device *adev) uint32_t amdgpu_virt_kiq_rreg(struct amdgpu_device *adev, uint32_t reg) { - signed long r; + signed long r, cnt = 0; unsigned long flags; - uint32_t val, seq; + uint32_t seq; struct amdgpu_kiq *kiq = &adev->gfx.kiq; struct amdgpu_ring *ring = &kiq->ring; @@ -153,18 +155,36 @@ uint32_t amdgpu_virt_kiq_rreg(struct amdgpu_device *adev, uint32_t reg) spin_unlock_irqrestore(&kiq->ring_lock, flags); r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT); - if (r < 1) { - DRM_ERROR("wait for kiq fence error: %ld\n", r); - return ~0; + + /* don't wait anymore for gpu reset case because this way may + * block gpu_recover() routine forever, e.g. this virt_kiq_rreg + * is triggered in TTM and ttm_bo_lock_delayed_workqueue() will + * never return if we keep waiting in virt_kiq_rreg, which cause + * gpu_recover() hang there. + * + * also don't wait anymore for IRQ context + * */ + if (r < 1 && (adev->in_gpu_reset || in_interrupt())) + goto failed_kiq_read; + + while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) { + msleep(MAX_KIQ_REG_BAILOUT_INTERVAL); + r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT); } - val = adev->wb.wb[adev->virt.reg_val_offs]; - return val; + if (cnt > MAX_KIQ_REG_TRY) + goto failed_kiq_read; + + return adev->wb.wb[adev->virt.reg_val_offs]; + +failed_kiq_read: + pr_err("failed to read reg:%x\n", reg); + return ~0; } void amdgpu_virt_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v) { - signed long r; + signed long r, cnt = 0; unsigned long flags; uint32_t seq; struct amdgpu_kiq *kiq = &adev->gfx.kiq; @@ -180,8 +200,30 @@ void amdgpu_virt_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v) spin_unlock_irqrestore(&kiq->ring_lock, flags); r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT); - if (r < 1) - DRM_ERROR("wait for kiq fence error: %ld\n", r); + + /* don't wait anymore for gpu reset case because this way may + * block gpu_recover() routine forever, e.g. this virt_kiq_rreg + * is triggered in TTM and ttm_bo_lock_delayed_workqueue() will + * never return if we keep waiting in virt_kiq_rreg, which cause + * gpu_recover() hang there. + * + * also don't wait anymore for IRQ context + * */ + if (r < 1 && (adev->in_gpu_reset || in_interrupt())) + goto failed_kiq_write; + + while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) { + msleep(MAX_KIQ_REG_BAILOUT_INTERVAL); + r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT); + } + + if (cnt > MAX_KIQ_REG_TRY) + goto failed_kiq_write; + + return; + +failed_kiq_write: + pr_err("failed to write reg:%x\n", reg); } /** -- cgit v1.2.3 From 9c5c71bbed4132a3a5f200064914db768c88302a Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Thu, 1 Mar 2018 09:39:57 -0500 Subject: drm/amd/amdgpu: Mask rptr as well in ring debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The read/write pointers on sdma4 devices increment beyond the ring size and should be masked. Tested on my Ryzen 2400G. Signed-off-by: Tom St Denis Reviewed-by: Alex Deucher Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index e223b0f6417b..d5f526f38e50 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -484,7 +484,7 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf, result = 0; if (*pos < 12) { - early[0] = amdgpu_ring_get_rptr(ring); + early[0] = amdgpu_ring_get_rptr(ring) & ring->buf_mask; early[1] = amdgpu_ring_get_wptr(ring) & ring->buf_mask; early[2] = ring->wptr & ring->buf_mask; for (i = *pos / 4; i < 3 && size; i++) { -- cgit v1.2.3 From 1cedc6385d5f7310af0a08831c6c4303486ba850 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 1 Mar 2018 08:08:23 -0800 Subject: platform/x86: wmi: Fix misuse of vsprintf extension %pULL %pULL doesn't officially exist but %pUL does. Miscellanea: o Add missing newlines to a couple logging messages Signed-off-by: Joe Perches Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index c0c8945603cb..8796211ef24a 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -945,7 +945,7 @@ static int wmi_dev_probe(struct device *dev) wblock->char_dev.mode = 0444; ret = misc_register(&wblock->char_dev); if (ret) { - dev_warn(dev, "failed to register char dev: %d", ret); + dev_warn(dev, "failed to register char dev: %d\n", ret); ret = -ENOMEM; goto probe_misc_failure; } @@ -1048,7 +1048,7 @@ static int wmi_create_device(struct device *wmi_bus_dev, if (result) { dev_warn(wmi_bus_dev, - "%s data block query control method not found", + "%s data block query control method not found\n", method); return result; } @@ -1198,7 +1198,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) retval = device_add(&wblock->dev.dev); if (retval) { - dev_err(wmi_bus_dev, "failed to register %pULL\n", + dev_err(wmi_bus_dev, "failed to register %pUL\n", wblock->gblock.guid); if (debug_event) wmi_method_enable(wblock, 0); -- cgit v1.2.3 From f0e8c61110c2c85903b136ba070daf643a8b6842 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 28 Feb 2018 11:57:50 +0100 Subject: Bluetooth: btusb: Remove Yoga 920 from the btusb_needs_reset_resume_table Commit 1fdb92697469 ("Bluetooth: btusb: Use DMI matching for QCA reset_resume quirking"), added the Lenovo Yoga 920 to the btusb_needs_reset_resume_table. Testing has shown that this is a false positive and the problems where caused by issues with the initial fix: commit fd865802c66b ("Bluetooth: btusb: fix QCA Rome suspend/resume"), which has already been reverted. So the QCA Rome BT in the Yoga 920 does not need a reset-resume quirk at all and this commit removes it from the btusb_needs_reset_resume_table. Note that after this commit the btusb_needs_reset_resume_table is now empty. It is kept around on purpose, since this whole series of commits started for a reason and there are actually broken platforms around, which need to be added to it. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1514836 Fixes: 1fdb92697469 ("Bluetooth: btusb: Use DMI matching for QCA ...") Cc: stable@vger.kernel.org Cc: Brian Norris Cc: Kai-Heng Feng Tested-by: Kevin Fenzi Suggested-by: Brian Norris Signed-off-by: Hans de Goede Reviewed-by: Brian Norris Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 60bf04b8f103..041c17e0c668 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -385,13 +385,6 @@ static const struct usb_device_id blacklist_table[] = { * the module itself. So we use a DMI list to match known broken platforms. */ static const struct dmi_system_id btusb_needs_reset_resume_table[] = { - { - /* Lenovo Yoga 920 (QCA Rome device 0cf3:e300) */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920"), - }, - }, {} }; -- cgit v1.2.3 From 0c6e526646c04ce31d4aaa280ed2237dd1cd774c Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Thu, 1 Mar 2018 13:42:52 +0800 Subject: Bluetooth: btusb: Add Dell OptiPlex 3060 to btusb_needs_reset_resume_table The issue can be reproduced before commit fd865802c66b ("Bluetooth: btusb: fix QCA Rome suspend/resume") gets introduced, so the reset resume quirk is still needed for this system. T: Bus=01 Lev=01 Prnt=01 Port=13 Cnt=01 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 2.01 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=e007 Rev=00.01 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Cc: stable@vger.kernel.org Cc: Brian Norris Cc: Hans de Goede Signed-off-by: Kai-Heng Feng Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 041c17e0c668..382be00a8329 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -385,6 +385,13 @@ static const struct usb_device_id blacklist_table[] = { * the module itself. So we use a DMI list to match known broken platforms. */ static const struct dmi_system_id btusb_needs_reset_resume_table[] = { + { + /* Dell OptiPlex 3060 (QCA ROME device 0cf3:e007) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 3060"), + }, + }, {} }; -- cgit v1.2.3 From 6f54120e17e311fd7ac42b9ec2a0611caa5b46ad Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Wed, 28 Feb 2018 09:11:10 +0800 Subject: ata: do not schedule hot plug if it is a sas host We've got a kernel panic when using sata disk with sas controller: [115946.152283] Unable to handle kernel NULL pointer dereference at virtual address 000007d8 [115946.223963] CPU: 0 PID: 22175 Comm: kworker/0:1 Tainted: G W OEL 4.14.0 #1 [115946.232925] Workqueue: events ata_scsi_hotplug [115946.237938] task: ffff8021ee50b180 task.stack: ffff00000d5d0000 [115946.244717] PC is at sas_find_dev_by_rphy+0x44/0x114 [115946.250224] LR is at sas_find_dev_by_rphy+0x3c/0x114 ...... [115946.355701] Process kworker/0:1 (pid: 22175, stack limit = 0xffff00000d5d0000) [115946.363369] Call trace: [115946.456356] [] sas_find_dev_by_rphy+0x44/0x114 [115946.462908] [] sas_target_alloc+0x20/0x5c [115946.469408] [] scsi_alloc_target+0x250/0x308 [115946.475781] [] __scsi_add_device+0xb0/0x154 [115946.481991] [] ata_scsi_scan_host+0x180/0x218 [115946.488367] [] ata_scsi_hotplug+0xb0/0xcc [115946.494801] [] process_one_work+0x144/0x390 [115946.501115] [] worker_thread+0x144/0x418 [115946.507093] [] kthread+0x10c/0x138 [115946.512792] [] ret_from_fork+0x10/0x18 We found that Ding Xiang has reported a similar bug before: https://patchwork.kernel.org/patch/9179817/ And this bug still exists in mainline. Since libsas handles hotplug and device adding/removing itself, do not need to schedule ata hot plug task here if it is a sas host. Signed-off-by: Jason Yan Cc: Ding Xiang Cc: stable@vger.kernel.org Signed-off-by: Tejun Heo --- drivers/ata/libata-eh.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 11c3137d7b0a..c016829a38fd 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -815,7 +815,8 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) if (ap->pflags & ATA_PFLAG_LOADING) ap->pflags &= ~ATA_PFLAG_LOADING; - else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) + else if ((ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) && + !(ap->flags & ATA_FLAG_SAS_HOST)) schedule_delayed_work(&ap->hotplug_task, 0); if (ap->pflags & ATA_PFLAG_RECOVERED) -- cgit v1.2.3 From 1514839b366417934e2f1328edb50ed1e8a719f5 Mon Sep 17 00:00:00 2001 From: "himanshu.madhani@cavium.com" Date: Mon, 12 Feb 2018 10:28:14 -0800 Subject: scsi: qla2xxx: Fix NULL pointer crash due to active timer for ABTS This patch fixes NULL pointer crash due to active timer running for abort IOCB. From crash dump analysis it was discoverd that get_next_timer_interrupt() encountered a corrupted entry on the timer list. #9 [ffff95e1f6f0fd40] page_fault at ffffffff914fe8f8 [exception RIP: get_next_timer_interrupt+440] RIP: ffffffff90ea3088 RSP: ffff95e1f6f0fdf0 RFLAGS: 00010013 RAX: ffff95e1f6451028 RBX: 000218e2389e5f40 RCX: 00000001232ad600 RDX: 0000000000000001 RSI: ffff95e1f6f0fdf0 RDI: 0000000001232ad6 RBP: ffff95e1f6f0fe40 R8: ffff95e1f6451188 R9: 0000000000000001 R10: 0000000000000016 R11: 0000000000000016 R12: 00000001232ad5f6 R13: ffff95e1f6450000 R14: ffff95e1f6f0fdf8 R15: ffff95e1f6f0fe10 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 Looking at the assembly of get_next_timer_interrupt(), address came from %r8 (ffff95e1f6451188) which is pointing to list_head with single entry at ffff95e5ff621178. 0xffffffff90ea307a : mov (%r8),%rdx 0xffffffff90ea307d : cmp %r8,%rdx 0xffffffff90ea3080 : je 0xffffffff90ea30a7 0xffffffff90ea3082 : nopw 0x0(%rax,%rax,1) 0xffffffff90ea3088 : testb $0x1,0x18(%rdx) crash> rd ffff95e1f6451188 10 ffff95e1f6451188: ffff95e5ff621178 ffff95e5ff621178 x.b.....x.b..... ffff95e1f6451198: ffff95e1f6451198 ffff95e1f6451198 ..E.......E..... ffff95e1f64511a8: ffff95e1f64511a8 ffff95e1f64511a8 ..E.......E..... ffff95e1f64511b8: ffff95e77cf509a0 ffff95e77cf509a0 ...|.......|.... ffff95e1f64511c8: ffff95e1f64511c8 ffff95e1f64511c8 ..E.......E..... crash> rd ffff95e5ff621178 10 ffff95e5ff621178: 0000000000000001 ffff95e15936aa00 ..........6Y.... ffff95e5ff621188: 0000000000000000 00000000ffffffff ................ ffff95e5ff621198: 00000000000000a0 0000000000000010 ................ ffff95e5ff6211a8: ffff95e5ff621198 000000000000000c ..b............. ffff95e5ff6211b8: 00000f5800000000 ffff95e751f8d720 ....X... ..Q.... ffff95e5ff621178 belongs to freed mempool object at ffff95e5ff621080. CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE ffff95dc7fd74d00 mnt_cache 384 19785 24948 594 16k SLAB MEMORY NODE TOTAL ALLOCATED FREE ffffdc5dabfd8800 ffff95e5ff620000 1 42 29 13 FREE / [ALLOCATED] ffff95e5ff621080 (cpu 6 cache) Examining the contents of that memory reveals a pointer to a constant string in the driver, "abort\0", which is set by qla24xx_async_abort_cmd(). crash> rd ffffffffc059277c 20 ffffffffc059277c: 6e490074726f6261 0074707572726574 abort.Interrupt. ffffffffc059278c: 00676e696c6c6f50 6920726576697244 Polling.Driver i ffffffffc059279c: 646f6d207325206e 6974736554000a65 n %s mode..Testi ffffffffc05927ac: 636976656420676e 786c252074612065 ng device at %lx ffffffffc05927bc: 6b63656843000a2e 646f727020676e69 ...Checking prod ffffffffc05927cc: 6f20444920746375 0a2e706968632066 uct ID of chip.. ffffffffc05927dc: 5120646e756f4600 204130303232414c .Found QLA2200A ffffffffc05927ec: 43000a2e70696843 20676e696b636568 Chip...Checking ffffffffc05927fc: 65786f626c69616d 6c636e69000a2e73 mailboxes...incl ffffffffc059280c: 756e696c2f656475 616d2d616d642f78 ude/linux/dma-ma crash> struct -ox srb_iocb struct srb_iocb { union { struct {...} logio; struct {...} els_logo; struct {...} tmf; struct {...} fxiocb; struct {...} abt; struct ct_arg ctarg; struct {...} mbx; struct {...} nack; [0x0 ] } u; [0xb8] struct timer_list timer; [0x108] void (*timeout)(void *); } SIZE: 0x110 crash> ! bc ibase=16 obase=10 B8+40 F8 The object is a srb_t, and at offset 0xf8 within that structure (i.e. ffff95e5ff621080 + f8 -> ffff95e5ff621178) is a struct timer_list. Cc: #4.4+ Fixes: 4440e46d5db7 ("[SCSI] qla2xxx: Add IOCB Abort command asynchronous handling.") Signed-off-by: Himanshu Madhani Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 2dea1129d396..04870621e712 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1527,6 +1527,7 @@ qla24xx_abort_sp_done(void *ptr, int res) srb_t *sp = ptr; struct srb_iocb *abt = &sp->u.iocb_cmd; + del_timer(&sp->u.iocb_cmd.timer); complete(&abt->u.abt.comp); } -- cgit v1.2.3 From 1c6cacf4ea6c04a58a0e3057f5ed60c24a4ffeff Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 22 Feb 2018 09:49:35 +0100 Subject: scsi: qla2xxx: Fixup locking for session deletion Commit d8630bb95f46 ('Serialize session deletion by using work_lock') tries to fixup a deadlock when deleting sessions, but fails to take into account the locking rules. This patch resolves the situation by introducing a separate lock for processing the GNLIST response, and ensures that sess_lock is released before calling qlt_schedule_sess_delete(). Cc: Himanshu Madhani Cc: Quinn Tran Fixes: d8630bb95f46 ("scsi: qla2xxx: Serialize session deletion by using work_lock") Signed-off-by: Hannes Reinecke Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 4 ++-- drivers/scsi/qla2xxx/qla_init.c | 24 +++++++++++++++--------- drivers/scsi/qla2xxx/qla_os.c | 7 ++++++- drivers/scsi/qla2xxx/qla_target.c | 17 ++++++----------- 4 files changed, 29 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index be7d6824581a..3ca4b6a5eddd 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -261,9 +261,9 @@ struct name_list_extended { struct get_name_list_extended *l; dma_addr_t ldma; - struct list_head fcports; /* protect by sess_list */ + struct list_head fcports; + spinlock_t fcports_lock; u32 size; - u8 sent; }; /* * Timeout timer counts in seconds diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 04870621e712..cacf2ccc081b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -643,8 +643,7 @@ qla24xx_async_gnl_sp_done(void *s, int res) (loop_id & 0x7fff)); } - spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); - vha->gnl.sent = 0; + spin_lock_irqsave(&vha->gnl.fcports_lock, flags); INIT_LIST_HEAD(&h); fcport = tf = NULL; @@ -653,12 +652,16 @@ qla24xx_async_gnl_sp_done(void *s, int res) list_for_each_entry_safe(fcport, tf, &h, gnl_entry) { list_del_init(&fcport->gnl_entry); + spin_lock(&vha->hw->tgt.sess_lock); fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); + spin_unlock(&vha->hw->tgt.sess_lock); ea.fcport = fcport; qla2x00_fcport_event_handler(vha, &ea); } + spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); /* create new fcport if fw has knowledge of new sessions */ for (i = 0; i < n; i++) { port_id_t id; @@ -710,18 +713,21 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) ql_dbg(ql_dbg_disc, vha, 0x20d9, "Async-gnlist WWPN %8phC \n", fcport->port_name); - spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + spin_lock_irqsave(&vha->gnl.fcports_lock, flags); + if (!list_empty(&fcport->gnl_entry)) { + spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); + rval = QLA_SUCCESS; + goto done; + } + + spin_lock(&vha->hw->tgt.sess_lock); fcport->disc_state = DSC_GNL; fcport->last_rscn_gen = fcport->rscn_gen; fcport->last_login_gen = fcport->login_gen; + spin_unlock(&vha->hw->tgt.sess_lock); list_add_tail(&fcport->gnl_entry, &vha->gnl.fcports); - if (vha->gnl.sent) { - spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); - return QLA_SUCCESS; - } - vha->gnl.sent = 1; - spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index afcb5567998a..585f37155f29 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -4577,6 +4577,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, spin_lock_init(&vha->work_lock); spin_lock_init(&vha->cmd_list_lock); + spin_lock_init(&vha->gnl.fcports_lock); init_waitqueue_head(&vha->fcport_waitQ); init_waitqueue_head(&vha->vref_waitq); @@ -4877,6 +4878,8 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) } qlt_plogi_ack_unref(vha, pla); } else { + fc_port_t *dfcp = NULL; + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); tfcp = qla2x00_find_fcport_by_nportid(vha, &e->u.new_sess.id, 1); @@ -4899,11 +4902,13 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) default: fcport->login_pause = 1; tfcp->conflict = fcport; - qlt_schedule_sess_for_deletion(tfcp); + dfcp = tfcp; break; } } spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + if (dfcp) + qlt_schedule_sess_for_deletion(tfcp); wwn = wwn_to_u64(fcport->node_name); diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 896b2d8bd803..b49ac85f3de2 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1224,10 +1224,10 @@ static void qla24xx_chk_fcp_state(struct fc_port *sess) } } -/* ha->tgt.sess_lock supposed to be held on entry */ void qlt_schedule_sess_for_deletion(struct fc_port *sess) { struct qla_tgt *tgt = sess->tgt; + struct qla_hw_data *ha = sess->vha->hw; unsigned long flags; if (sess->disc_state == DSC_DELETE_PEND) @@ -1244,16 +1244,16 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) return; } + spin_lock_irqsave(&ha->tgt.sess_lock, flags); if (sess->deleted == QLA_SESS_DELETED) sess->logout_on_delete = 0; - spin_lock_irqsave(&sess->vha->work_lock, flags); if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { - spin_unlock_irqrestore(&sess->vha->work_lock, flags); + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); return; } sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; - spin_unlock_irqrestore(&sess->vha->work_lock, flags); + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); sess->disc_state = DSC_DELETE_PEND; @@ -1262,13 +1262,10 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) ql_dbg(ql_dbg_tgt, sess->vha, 0xe001, "Scheduling sess %p for deletion\n", sess); - /* use cancel to push work element through before re-queue */ - cancel_work_sync(&sess->del_work); INIT_WORK(&sess->del_work, qla24xx_delete_sess_fn); - queue_work(sess->vha->hw->wq, &sess->del_work); + WARN_ON(!queue_work(sess->vha->hw->wq, &sess->del_work)); } -/* ha->tgt.sess_lock supposed to be held on entry */ static void qlt_clear_tgt_db(struct qla_tgt *tgt) { struct fc_port *sess; @@ -1451,8 +1448,8 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen) ql_dbg(ql_dbg_tgt_mgt, vha, 0xf008, "qla_tgt_fc_port_deleted %p", sess); sess->local = 1; - qlt_schedule_sess_for_deletion(sess); spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + qlt_schedule_sess_for_deletion(sess); } static inline int test_tgt_sess_count(struct qla_tgt *tgt) @@ -1512,10 +1509,8 @@ int qlt_stop_phase1(struct qla_tgt *tgt) * Lock is needed, because we still can get an incoming packet. */ mutex_lock(&vha->vha_tgt.tgt_mutex); - spin_lock_irqsave(&ha->tgt.sess_lock, flags); tgt->tgt_stop = 1; qlt_clear_tgt_db(tgt); - spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); mutex_unlock(&vha->vha_tgt.tgt_mutex); mutex_unlock(&qla_tgt_mutex); -- cgit v1.2.3 From 07ea4b6026ee8b8dfaf9bbe83a09b3ba905d20fd Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 22 Feb 2018 09:49:36 +0100 Subject: scsi: qla2xxx: do not check login_state if no loop id is assigned When no loop id is assigned in qla24xx_fcport_handle_login() the login state needs to be ignored; it will get set later on in qla_chk_n2n_b4_login(). Cc: Quinn Tran Cc: Himanshu Madhani Fixes: 040036bb0bc1 ("scsi: qla2xxx: Delay loop id allocation at login") Signed-off-by: Hannes Reinecke Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index cacf2ccc081b..4efc25700e99 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1157,8 +1157,9 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) if (fcport->scan_state != QLA_FCPORT_FOUND) return 0; - if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || - (fcport->fw_login_state == DSC_LS_PRLI_PEND)) + if ((fcport->loop_id != FC_NO_LOOP_ID) && + ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || + (fcport->fw_login_state == DSC_LS_PRLI_PEND))) return 0; if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) { -- cgit v1.2.3 From fa83e65885b9147e2f2b89fdd4ecf7b4ff91571d Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 22 Feb 2018 09:49:37 +0100 Subject: scsi: qla2xxx: ensure async flags are reset correctly The fcport flags FCF_ASYNC_ACTIVE and FCF_ASYNC_SENT are used to throttle the state machine, so we need to ensure to always set and unset them correctly. Not doing so will lead to the state machine getting confused and no login attempt into remote ports. Cc: Quinn Tran Cc: Himanshu Madhani Fixes: 3dbec59bdf63 ("scsi: qla2xxx: Prevent multiple active discovery commands per session") Signed-off-by: Hannes Reinecke Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 2 ++ drivers/scsi/qla2xxx/qla_init.c | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 5bf9a59432f6..21eff2d30266 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3179,6 +3179,7 @@ done_free_sp: sp->free(sp); fcport->flags &= ~FCF_ASYNC_SENT; done: + fcport->flags &= ~FCF_ASYNC_ACTIVE; return rval; } @@ -3370,6 +3371,7 @@ done_free_sp: sp->free(sp); fcport->flags &= ~FCF_ASYNC_SENT; done: + fcport->flags &= ~FCF_ASYNC_ACTIVE; return rval; } diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 4efc25700e99..d5a45c4981ec 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -213,6 +213,7 @@ done_free_sp: sp->free(sp); fcport->flags &= ~FCF_ASYNC_SENT; done: + fcport->flags &= ~FCF_ASYNC_ACTIVE; return rval; } @@ -263,7 +264,7 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) done_free_sp: sp->free(sp); done: - fcport->flags &= ~FCF_ASYNC_SENT; + fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); return rval; } @@ -271,6 +272,7 @@ void qla2x00_async_prlo_done(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) { + fcport->flags &= ~FCF_ASYNC_ACTIVE; /* Don't re-login in target mode */ if (!fcport->tgt_session) qla2x00_mark_device_lost(vha, fcport, 1, 0); @@ -284,6 +286,7 @@ qla2x00_async_prlo_sp_done(void *s, int res) struct srb_iocb *lio = &sp->u.iocb_cmd; struct scsi_qla_host *vha = sp->vha; + sp->fcport->flags &= ~FCF_ASYNC_ACTIVE; if (!test_bit(UNLOADING, &vha->dpc_flags)) qla2x00_post_async_prlo_done_work(sp->fcport->vha, sp->fcport, lio->u.logio.data); @@ -322,6 +325,7 @@ qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t *fcport) done_free_sp: sp->free(sp); done: + fcport->flags &= ~FCF_ASYNC_ACTIVE; return rval; } @@ -375,6 +379,8 @@ qla2x00_async_adisc_sp_done(void *ptr, int res) "Async done-%s res %x %8phC\n", sp->name, res, sp->fcport->port_name); + sp->fcport->flags &= ~FCF_ASYNC_SENT; + memset(&ea, 0, sizeof(ea)); ea.event = FCME_ADISC_DONE; ea.rc = res; @@ -425,7 +431,7 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, done_free_sp: sp->free(sp); done: - fcport->flags &= ~FCF_ASYNC_SENT; + fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); qla2x00_post_async_adisc_work(vha, fcport, data); return rval; } @@ -1799,6 +1805,7 @@ qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport, qla2x00_mark_device_lost(vha, fcport, 1, 0); qlt_logo_completion_handler(fcport, data[0]); fcport->login_gen++; + fcport->flags &= ~FCF_ASYNC_ACTIVE; return; } @@ -1806,6 +1813,7 @@ void qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) { + fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); if (data[0] == MBS_COMMAND_COMPLETE) { qla2x00_update_fcport(vha, fcport); @@ -1813,7 +1821,6 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, } /* Retry login. */ - fcport->flags &= ~FCF_ASYNC_SENT; if (data[1] & QLA_LOGIO_LOGIN_RETRIED) set_bit(RELOGIN_NEEDED, &vha->dpc_flags); else -- cgit v1.2.3 From 3be8828fc507cdafe7040a3dcf361a2bcd8e305b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 22 Feb 2018 11:30:20 -0800 Subject: scsi: core: Avoid that ATA error handling can trigger a kernel hang or oops Avoid that the recently introduced call_rcu() call in the SCSI core triggers a double call_rcu() call. Reported-by: Natanael Copa Reported-by: Damien Le Moal References: https://bugzilla.kernel.org/show_bug.cgi?id=198861 Fixes: 3bd6f43f5cb3 ("scsi: core: Ensure that the SCSI error handler gets woken up") Signed-off-by: Bart Van Assche Reviewed-by: Damien Le Moal Tested-by: Damien Le Moal Cc: Natanael Copa Cc: Damien Le Moal Cc: Alexandre Oliva Cc: Pavel Tikhomirov Cc: Hannes Reinecke Cc: Johannes Thumshirn Cc: Signed-off-by: Martin K. Petersen --- drivers/scsi/hosts.c | 3 --- drivers/scsi/scsi_error.c | 5 +++-- drivers/scsi/scsi_lib.c | 2 ++ 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 57bf43e34863..dd9464920456 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -328,8 +328,6 @@ static void scsi_host_dev_release(struct device *dev) if (shost->work_q) destroy_workqueue(shost->work_q); - destroy_rcu_head(&shost->rcu); - if (shost->shost_state == SHOST_CREATED) { /* * Free the shost_dev device name here if scsi_host_alloc() @@ -404,7 +402,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) INIT_LIST_HEAD(&shost->starved_list); init_waitqueue_head(&shost->host_wait); mutex_init(&shost->scan_mutex); - init_rcu_head(&shost->rcu); index = ida_simple_get(&host_index_ida, 0, 0, GFP_KERNEL); if (index < 0) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index d042915ce895..ca53a5f785ee 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -223,7 +223,8 @@ static void scsi_eh_reset(struct scsi_cmnd *scmd) static void scsi_eh_inc_host_failed(struct rcu_head *head) { - struct Scsi_Host *shost = container_of(head, typeof(*shost), rcu); + struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu); + struct Scsi_Host *shost = scmd->device->host; unsigned long flags; spin_lock_irqsave(shost->host_lock, flags); @@ -259,7 +260,7 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd) * Ensure that all tasks observe the host state change before the * host_failed change. */ - call_rcu(&shost->rcu, scsi_eh_inc_host_failed); + call_rcu(&scmd->rcu, scsi_eh_inc_host_failed); } /** diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 5cbc69b2b1ae..4af1682f5ff5 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -670,6 +670,7 @@ static bool scsi_end_request(struct request *req, blk_status_t error, if (!blk_rq_is_scsi(req)) { WARN_ON_ONCE(!(cmd->flags & SCMD_INITIALIZED)); cmd->flags &= ~SCMD_INITIALIZED; + destroy_rcu_head(&cmd->rcu); } if (req->mq_ctx) { @@ -1150,6 +1151,7 @@ static void scsi_initialize_rq(struct request *rq) struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); scsi_req_init(&cmd->req); + init_rcu_head(&cmd->rcu); cmd->jiffies_at_alloc = jiffies; cmd->retries = 0; } -- cgit v1.2.3 From e39a97353e5378eb46bf01679799c5704d397f32 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 26 Feb 2018 08:39:59 +0100 Subject: scsi: core: return BLK_STS_OK for DID_OK in __scsi_error_from_host_byte() When converting __scsi_error_from_host_byte() to BLK_STS error codes the case DID_OK was forgotten, resulting in it always returning an error. Fixes: 2a842acab109 ("block: introduce new block status code type") Cc: Doug Gilbert Signed-off-by: Hannes Reinecke Reviewed-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 4af1682f5ff5..c9844043504e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -720,6 +720,8 @@ static blk_status_t __scsi_error_from_host_byte(struct scsi_cmnd *cmd, int result) { switch (host_byte(result)) { + case DID_OK: + return BLK_STS_OK; case DID_TRANSPORT_FAILFAST: return BLK_STS_TRANSPORT; case DID_TARGET_FAILURE: -- cgit v1.2.3 From 2b5b96473efceb755d7700d47982370d49e8815f Mon Sep 17 00:00:00 2001 From: Darren Trapp Date: Tue, 27 Feb 2018 16:31:12 -0800 Subject: scsi: qla2xxx: Fix FC-NVMe LUN discovery commit a4239945b8ad ("scsi: qla2xxx: Add switch command to simplify fabric discovery") introduced regression when it did not consider FC-NVMe code path which broke NVMe LUN discovery. Fixes: a4239945b8ad ("scsi: qla2xxx: Add switch command to simplify fabric discovery") Signed-off-by: Darren Trapp Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_gs.c | 3 +++ drivers/scsi/qla2xxx/qla_init.c | 8 +++++++- drivers/scsi/qla2xxx/qla_os.c | 7 +++++-- 4 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 3ca4b6a5eddd..c9689f97c307 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2217,6 +2217,7 @@ typedef struct { /* FCP-4 types */ #define FC4_TYPE_FCP_SCSI 0x08 +#define FC4_TYPE_NVME 0x28 #define FC4_TYPE_OTHER 0x0 #define FC4_TYPE_UNKNOWN 0xff diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 21eff2d30266..403fa096f8c8 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3973,6 +3973,9 @@ out: spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; spin_unlock_irqrestore(&vha->work_lock, flags); + + if ((fc4type == FC4_TYPE_FCP_SCSI) && vha->flags.nvme_enabled) + qla24xx_async_gpnft(vha, FC4_TYPE_NVME); } static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d5a45c4981ec..00329dda6179 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1061,6 +1061,7 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) fc_port_t *fcport = ea->fcport; struct port_database_24xx *pd; struct srb *sp = ea->sp; + uint8_t ls; pd = (struct port_database_24xx *)sp->u.iocb_cmd.u.mbx.in; @@ -1073,7 +1074,12 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) if (fcport->disc_state == DSC_DELETE_PEND) return; - switch (pd->current_login_state) { + if (fcport->fc4f_nvme) + ls = pd->current_login_state >> 4; + else + ls = pd->current_login_state & 0xf; + + switch (ls) { case PDS_PRLI_COMPLETE: __qla24xx_parse_gpdb(vha, fcport, pd); break; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 585f37155f29..285911e81728 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -4807,9 +4807,12 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) fcport->d_id = e->u.new_sess.id; fcport->flags |= FCF_FABRIC_DEVICE; fcport->fw_login_state = DSC_LS_PLOGI_PEND; - if (e->u.new_sess.fc4_type == FC4_TYPE_FCP_SCSI) + if (e->u.new_sess.fc4_type == FC4_TYPE_FCP_SCSI) { fcport->fc4_type = FC4_TYPE_FCP_SCSI; - + } else if (e->u.new_sess.fc4_type == FC4_TYPE_NVME) { + fcport->fc4_type = FC4_TYPE_OTHER; + fcport->fc4f_nvme = FC4_TYPE_NVME; + } memcpy(fcport->port_name, e->u.new_sess.port_name, WWN_SIZE); } else { -- cgit v1.2.3 From 967823d6c3980a30e214b92bfe6a101e7b46d025 Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Mon, 26 Feb 2018 01:01:17 -0800 Subject: scsi: qedi: Fix kernel crash during port toggle BUG: unable to handle kernel NULL pointer dereference at 0000000000000100 [ 985.596918] IP: _raw_spin_lock_bh+0x17/0x30 [ 985.601581] PGD 0 P4D 0 [ 985.604405] Oops: 0002 [#1] SMP : [ 985.704533] CPU: 16 PID: 1156 Comm: qedi_thread/16 Not tainted 4.16.0-rc2 #1 [ 985.712397] Hardware name: Dell Inc. PowerEdge R730/0599V5, BIOS 2.4.3 01/17/2017 [ 985.720747] RIP: 0010:_raw_spin_lock_bh+0x17/0x30 [ 985.725996] RSP: 0018:ffffa4b1c43d3e10 EFLAGS: 00010246 [ 985.731823] RAX: 0000000000000000 RBX: ffff94a31bd03000 RCX: 0000000000000000 [ 985.739783] RDX: 0000000000000001 RSI: ffff94a32fa16938 RDI: 0000000000000100 [ 985.747744] RBP: 0000000000000004 R08: 0000000000000000 R09: 0000000000000a33 [ 985.755703] R10: 0000000000000000 R11: ffffa4b1c43d3af0 R12: 0000000000000000 [ 985.763662] R13: ffff94a301f40818 R14: 0000000000000000 R15: 000000000000000c [ 985.771622] FS: 0000000000000000(0000) GS:ffff94a32fa00000(0000) knlGS:0000000000000000 [ 985.780649] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 985.787057] CR2: 0000000000000100 CR3: 000000067a009006 CR4: 00000000001606e0 [ 985.795017] Call Trace: [ 985.797747] qedi_fp_process_cqes+0x258/0x980 [qedi] [ 985.803294] qedi_percpu_io_thread+0x10f/0x1b0 [qedi] [ 985.808931] kthread+0xf5/0x130 [ 985.812434] ? qedi_free_uio+0xd0/0xd0 [qedi] [ 985.817298] ? kthread_bind+0x10/0x10 [ 985.821372] ? do_syscall_64+0x6e/0x1a0 Signed-off-by: Manish Rangankar Signed-off-by: Martin K. Petersen --- drivers/scsi/qedi/qedi_fw.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c index 20a9259304f2..03c772c223fa 100644 --- a/drivers/scsi/qedi/qedi_fw.c +++ b/drivers/scsi/qedi/qedi_fw.c @@ -761,6 +761,11 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi, iscsi_cid = cqe->conn_id; qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid]; + if (!qedi_conn) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "icid not found 0x%x\n", cqe->conn_id); + return; + } /* Based on this itt get the corresponding qedi_cmd */ spin_lock_bh(&qedi_conn->tmf_work_lock); -- cgit v1.2.3 From 07c5ccd70ad702e561fcda8e4df494f098a42742 Mon Sep 17 00:00:00 2001 From: Alastair D'Silva Date: Thu, 22 Feb 2018 15:17:38 +1100 Subject: ocxl: Add get_metadata IOCTL to share OCXL information to userspace Some required information is not exposed to userspace currently (eg. the PASID), pass this information back, along with other information which is currently communicated via sysfs, which saves some parsing effort in userspace. Signed-off-by: Alastair D'Silva Acked-by: Andrew Donnellan Acked-by: Frederic Barrat Signed-off-by: Michael Ellerman --- drivers/misc/ocxl/file.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c index 337462e1569f..038509e5d031 100644 --- a/drivers/misc/ocxl/file.c +++ b/drivers/misc/ocxl/file.c @@ -102,10 +102,32 @@ static long afu_ioctl_attach(struct ocxl_context *ctx, return rc; } +static long afu_ioctl_get_metadata(struct ocxl_context *ctx, + struct ocxl_ioctl_metadata __user *uarg) +{ + struct ocxl_ioctl_metadata arg; + + memset(&arg, 0, sizeof(arg)); + + arg.version = 0; + + arg.afu_version_major = ctx->afu->config.version_major; + arg.afu_version_minor = ctx->afu->config.version_minor; + arg.pasid = ctx->pasid; + arg.pp_mmio_size = ctx->afu->config.pp_mmio_stride; + arg.global_mmio_size = ctx->afu->config.global_mmio_size; + + if (copy_to_user(uarg, &arg, sizeof(arg))) + return -EFAULT; + + return 0; +} + #define CMD_STR(x) (x == OCXL_IOCTL_ATTACH ? "ATTACH" : \ x == OCXL_IOCTL_IRQ_ALLOC ? "IRQ_ALLOC" : \ x == OCXL_IOCTL_IRQ_FREE ? "IRQ_FREE" : \ x == OCXL_IOCTL_IRQ_SET_FD ? "IRQ_SET_FD" : \ + x == OCXL_IOCTL_GET_METADATA ? "GET_METADATA" : \ "UNKNOWN") static long afu_ioctl(struct file *file, unsigned int cmd, @@ -159,6 +181,11 @@ static long afu_ioctl(struct file *file, unsigned int cmd, irq_fd.eventfd); break; + case OCXL_IOCTL_GET_METADATA: + rc = afu_ioctl_get_metadata(ctx, + (struct ocxl_ioctl_metadata __user *) args); + break; + default: rc = -EINVAL; } -- cgit v1.2.3 From f3e5feeb92a163c935659b7222a32965276c1c23 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 1 Mar 2018 22:34:32 +0100 Subject: drm/sun4i: Release exclusive clock lock when disabling TCON Currently exclusive TCON clock lock is never released, which, for example, prevents changing resolution on HDMI. In order to fix that, release clock when disabling TCON. TCON is always disabled first before new mode is set. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180301213442.16677-7-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index b3960118deb9..ade197b1a9ac 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -101,10 +101,12 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel, return; } - if (enabled) + if (enabled) { clk_prepare_enable(clk); - else + } else { + clk_rate_exclusive_put(clk); clk_disable_unprepare(clk); + } } static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon, -- cgit v1.2.3 From 1ceb5f1b7d699c8e891ca5bd9c6b89b256c540f0 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 1 Mar 2018 22:34:33 +0100 Subject: drm/sun4i: Add support for H3 display engine H3 display engine has two mixers which are connected to HDMI and TV output. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180301213442.16677-8-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun4i_drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 3957c2ff6870..a0f43b81c64c 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -359,6 +359,7 @@ static const struct of_device_id sun4i_drv_of_table[] = { { .compatible = "allwinner,sun7i-a20-display-engine" }, { .compatible = "allwinner,sun8i-a33-display-engine" }, { .compatible = "allwinner,sun8i-a83t-display-engine" }, + { .compatible = "allwinner,sun8i-h3-display-engine" }, { .compatible = "allwinner,sun8i-v3s-display-engine" }, { } }; -- cgit v1.2.3 From e679f4a13f0fd1da4ef5b9c59c78404cd421c61b Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 1 Mar 2018 22:34:34 +0100 Subject: drm/sun4i: Add support for H3 mixer 0 This mixer supports 1 VI plane, 3 UI plane and HW scaling on all planes. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180301213442.16677-9-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_mixer.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c index 9b0256d31a61..126899d6f0d3 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c @@ -492,6 +492,14 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = { .vi_num = 1, }; +static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = { + .ccsc = 0, + .mod_rate = 432000000, + .scaler_mask = 0xf, + .ui_num = 3, + .vi_num = 1, +}; + static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = { .vi_num = 2, .ui_num = 1, @@ -509,6 +517,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = { .compatible = "allwinner,sun8i-a83t-de2-mixer-1", .data = &sun8i_a83t_mixer1_cfg, }, + { + .compatible = "allwinner,sun8i-h3-de2-mixer-0", + .data = &sun8i_h3_mixer0_cfg, + }, { .compatible = "allwinner,sun8i-v3s-de2-mixer", .data = &sun8i_v3s_mixer_cfg, -- cgit v1.2.3 From e420ccd66d36e4ac2035620286495ce13a40b7f7 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 1 Mar 2018 22:34:35 +0100 Subject: drm/sun4i: Fix polarity configuration for DW HDMI PHY Current polarity configuration code is cleary wrong since it compares same flag two times. However, even if flag name is fixed, it won't work well for resolutions which have one polarity positive and another negative. Fix that by properly set each bit according to each polarity. Since those two bits are not described in any documentation, relationships were obtained by experimentation. Fixes: b7c7436a5ff0 ("drm/sun4i: Implement A83T HDMI driver") Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180301213442.16677-10-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index e5bfcdd43ec9..9d2f11ca3538 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -10,7 +10,8 @@ #define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000 #define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK BIT(0) #define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK GENMASK(15, 8) -#define SUN8I_HDMI_PHY_DBG_CTRL_POL(val) (val << 8) +#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC BIT(8) +#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC BIT(9) #define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK GENMASK(23, 16) #define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr) (addr << 16) @@ -35,14 +36,14 @@ static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data; u32 val = 0; - if ((mode->flags & DRM_MODE_FLAG_NHSYNC) && - (mode->flags & DRM_MODE_FLAG_NHSYNC)) { - val = 0x03; - } + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC; + + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC; regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, - SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, - SUN8I_HDMI_PHY_DBG_CTRL_POL(val)); + SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val); regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG, SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, -- cgit v1.2.3 From 6fd903102c9d9e1c2807d5fbbf011b44f122b20d Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 1 Mar 2018 22:34:36 +0100 Subject: drm/sun4i: Add support for variants to DW HDMI PHY There are multiple variants of DW HDMI PHYs in Allwinner SoCs. While some things like clock and reset setup are the same, PHY configuration differs a lot. Split out code which is PHY specific to separate functions and create a structure which holds pointers to those functions. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180301213442.16677-11-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 20 ++++++-- drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 89 +++++++++++++++++++++++----------- 2 files changed, 76 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index d8d0684fc8aa..1e9eb6072615 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h @@ -12,11 +12,23 @@ #include #include +struct sun8i_hdmi_phy; + +struct sun8i_hdmi_phy_variant { + void (*phy_init)(struct sun8i_hdmi_phy *phy); + void (*phy_disable)(struct dw_hdmi *hdmi, + struct sun8i_hdmi_phy *phy); + int (*phy_config)(struct dw_hdmi *hdmi, + struct sun8i_hdmi_phy *phy, + unsigned int clk_rate); +}; + struct sun8i_hdmi_phy { - struct clk *clk_bus; - struct clk *clk_mod; - struct regmap *regs; - struct reset_control *rst_phy; + struct clk *clk_bus; + struct clk *clk_mod; + struct regmap *regs; + struct reset_control *rst_phy; + struct sun8i_hdmi_phy_variant *variant; }; struct sun8i_dw_hdmi { diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index 9d2f11ca3538..17aada64bafd 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -30,21 +30,10 @@ */ #define I2C_ADDR 0x69 -static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, - struct drm_display_mode *mode) +static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi, + struct sun8i_hdmi_phy *phy, + unsigned int clk_rate) { - struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data; - u32 val = 0; - - if (mode->flags & DRM_MODE_FLAG_NHSYNC) - val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC; - - if (mode->flags & DRM_MODE_FLAG_NVSYNC) - val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC; - - regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, - SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val); - regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG, SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN); @@ -64,21 +53,21 @@ static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, * release any documentation, explanation of this values can * be found in i.MX 6Dual/6Quad Reference Manual. */ - if (mode->crtc_clock <= 27000) { + if (clk_rate <= 27000000) { dw_hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06); dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); dw_hdmi_phy_i2c_write(hdmi, 0x08da, 0x10); dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19); dw_hdmi_phy_i2c_write(hdmi, 0x0318, 0x0e); dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09); - } else if (mode->crtc_clock <= 74250) { + } else if (clk_rate <= 74250000) { dw_hdmi_phy_i2c_write(hdmi, 0x0540, 0x06); dw_hdmi_phy_i2c_write(hdmi, 0x0005, 0x15); dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10); dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19); dw_hdmi_phy_i2c_write(hdmi, 0x02b5, 0x0e); dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09); - } else if (mode->crtc_clock <= 148500) { + } else if (clk_rate <= 148500000) { dw_hdmi_phy_i2c_write(hdmi, 0x04a0, 0x06); dw_hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10); @@ -103,10 +92,27 @@ static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, return 0; }; -static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data) +static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, + struct drm_display_mode *mode) { struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data; + u32 val = 0; + + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC; + + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, + SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val); + + return phy->variant->phy_config(hdmi, phy, mode->crtc_clock * 1000); +}; + +static void sun8i_hdmi_phy_disable_a83t(struct dw_hdmi *hdmi, + struct sun8i_hdmi_phy *phy) +{ dw_hdmi_phy_gen2_txpwron(hdmi, 0); dw_hdmi_phy_gen2_pddq(hdmi, 1); @@ -114,6 +120,13 @@ static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data) SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0); } +static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data) +{ + struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data; + + phy->variant->phy_disable(hdmi, phy); +} + static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = { .init = &sun8i_hdmi_phy_config, .disable = &sun8i_hdmi_phy_disable, @@ -122,16 +135,8 @@ static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = { .setup_hpd = &dw_hdmi_phy_setup_hpd, }; -void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) +static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy) { - /* enable read access to HDMI controller */ - regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG, - SUN8I_HDMI_PHY_READ_EN_MAGIC); - - /* unscramble register offsets */ - regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG, - SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC); - regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK, SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK); @@ -145,6 +150,19 @@ void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR)); } +void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) +{ + /* enable read access to HDMI controller */ + regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG, + SUN8I_HDMI_PHY_READ_EN_MAGIC); + + /* unscramble register offsets */ + regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG, + SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC); + + phy->variant->phy_init(phy); +} + const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void) { return &sun8i_hdmi_phy_ops; @@ -158,20 +176,31 @@ static struct regmap_config sun8i_hdmi_phy_regmap_config = { .name = "phy" }; +static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = { + .phy_init = &sun8i_hdmi_phy_init_a83t, + .phy_disable = &sun8i_hdmi_phy_disable_a83t, + .phy_config = &sun8i_hdmi_phy_config_a83t, +}; + static const struct of_device_id sun8i_hdmi_phy_of_table[] = { - { .compatible = "allwinner,sun8i-a83t-hdmi-phy" }, + { + .compatible = "allwinner,sun8i-a83t-hdmi-phy", + .data = &sun8i_a83t_hdmi_phy, + }, { /* sentinel */ } }; int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node) { + const struct of_device_id *match; struct device *dev = hdmi->dev; struct sun8i_hdmi_phy *phy; struct resource res; void __iomem *regs; int ret; - if (!of_match_node(sun8i_hdmi_phy_of_table, node)) { + match = of_match_node(sun8i_hdmi_phy_of_table, node); + if (!match) { dev_err(dev, "Incompatible HDMI PHY\n"); return -EINVAL; } @@ -180,6 +209,8 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node) if (!phy) return -ENOMEM; + phy->variant = (struct sun8i_hdmi_phy_variant *)match->data; + ret = of_address_to_resource(node, 0, &res); if (ret) { dev_err(dev, "phy: Couldn't get our resources\n"); -- cgit v1.2.3 From 6876b160b70eeab5c7e0c3888f4907502a1df4a7 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 1 Mar 2018 22:34:37 +0100 Subject: drm/sun4i: Move and expand DW HDMI PHY register macros DW HDMI PHY macros are moved to header file and expanded with the registers present on newer SoCs like H3 and H5. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180301213442.16677-12-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 131 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 17 ----- 2 files changed, 131 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index 1e9eb6072615..49161326ea5a 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h @@ -12,6 +12,137 @@ #include #include +#define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000 +#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK BIT(0) +#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK GENMASK(15, 8) +#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC BIT(8) +#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC BIT(9) +#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK GENMASK(23, 16) +#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr) (addr << 16) + +#define SUN8I_HDMI_PHY_REXT_CTRL_REG 0x0004 +#define SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN BIT(31) + +#define SUN8I_HDMI_PHY_READ_EN_REG 0x0010 +#define SUN8I_HDMI_PHY_READ_EN_MAGIC 0x54524545 + +#define SUN8I_HDMI_PHY_UNSCRAMBLE_REG 0x0014 +#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC 0x42494E47 + +#define SUN8I_HDMI_PHY_ANA_CFG1_REG 0x0020 +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SWI BIT(31) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_PWEND BIT(30) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_PWENC BIT(29) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW BIT(28) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SVRCAL(x) ((x) << 26) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(x) ((x) << 24) +#define SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT BIT(23) +#define SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT BIT(22) +#define SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT BIT(21) +#define SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT BIT(20) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL BIT(19) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG BIT(18) +#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS BIT(17) +#define SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN BIT(16) +#define SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK GENMASK(15, 12) +#define SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL (0xf << 12) +#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK BIT(11) +#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 BIT(10) +#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 BIT(9) +#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 BIT(8) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK BIT(7) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 BIT(6) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 BIT(5) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 BIT(4) +#define SUN8I_HDMI_PHY_ANA_CFG1_CKEN BIT(3) +#define SUN8I_HDMI_PHY_ANA_CFG1_LDOEN BIT(2) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENVBS BIT(1) +#define SUN8I_HDMI_PHY_ANA_CFG1_ENBI BIT(0) + +#define SUN8I_HDMI_PHY_ANA_CFG2_REG 0x0024 +#define SUN8I_HDMI_PHY_ANA_CFG2_M_EN BIT(31) +#define SUN8I_HDMI_PHY_ANA_CFG2_PLLDBEN BIT(30) +#define SUN8I_HDMI_PHY_ANA_CFG2_SEN BIT(29) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_HPDPD BIT(28) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_HPDEN BIT(27) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_PLRCK BIT(26) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_PLR(x) ((x) << 23) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK BIT(22) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN BIT(21) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CD(x) ((x) << 19) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(x) ((x) << 17) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK BIT(16) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW BIT(15) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(x) ((x) << 13) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(x) ((x) << 10) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BOOSTCK(x) ((x) << 8) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BOOST(x) ((x) << 6) +#define SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(x) ((x) << 0) + +#define SUN8I_HDMI_PHY_ANA_CFG3_REG 0x0028 +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_SLOWCK(x) ((x) << 30) +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_SLOW(x) ((x) << 28) +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(x) ((x) << 18) +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(x) ((x) << 14) +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_EMPCK(x) ((x) << 11) +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(x) ((x) << 7) +#define SUN8I_HDMI_PHY_ANA_CFG3_REG_EMP(x) ((x) << 4) +#define SUN8I_HDMI_PHY_ANA_CFG3_SDAPD BIT(3) +#define SUN8I_HDMI_PHY_ANA_CFG3_SDAEN BIT(2) +#define SUN8I_HDMI_PHY_ANA_CFG3_SCLPD BIT(1) +#define SUN8I_HDMI_PHY_ANA_CFG3_SCLEN BIT(0) + +#define SUN8I_HDMI_PHY_PLL_CFG1_REG 0x002c +#define SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 BIT(31) +#define SUN8I_HDMI_PHY_PLL_CFG1_REG_OD BIT(30) +#define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN BIT(29) +#define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN BIT(28) +#define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 BIT(27) +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL BIT(26) +#define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN BIT(25) +#define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x) ((x) << 22) +#define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x) ((x) << 20) +#define SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN BIT(19) +#define SUN8I_HDMI_PHY_PLL_CFG1_CS BIT(18) +#define SUN8I_HDMI_PHY_PLL_CFG1_CP_S(x) ((x) << 13) +#define SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(x) ((x) << 7) +#define SUN8I_HDMI_PHY_PLL_CFG1_BWS BIT(6) +#define SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK GENMASK(5, 0) +#define SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT 0 + +#define SUN8I_HDMI_PHY_PLL_CFG2_REG 0x0030 +#define SUN8I_HDMI_PHY_PLL_CFG2_SV_H BIT(31) +#define SUN8I_HDMI_PHY_PLL_CFG2_PDCLKSEL(x) ((x) << 29) +#define SUN8I_HDMI_PHY_PLL_CFG2_CLKSTEP(x) ((x) << 27) +#define SUN8I_HDMI_PHY_PLL_CFG2_PSET(x) ((x) << 24) +#define SUN8I_HDMI_PHY_PLL_CFG2_PCLK_SEL BIT(23) +#define SUN8I_HDMI_PHY_PLL_CFG2_AUTOSYNC_DIS BIT(22) +#define SUN8I_HDMI_PHY_PLL_CFG2_VREG2_OUT_EN BIT(21) +#define SUN8I_HDMI_PHY_PLL_CFG2_VREG1_OUT_EN BIT(20) +#define SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN BIT(19) +#define SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN(x) ((x) << 16) +#define SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(x) ((x) << 12) +#define SUN8I_HDMI_PHY_PLL_CFG2_VCO_RST_IN BIT(11) +#define SUN8I_HDMI_PHY_PLL_CFG2_SINT_FRAC BIT(10) +#define SUN8I_HDMI_PHY_PLL_CFG2_SDIV2 BIT(9) +#define SUN8I_HDMI_PHY_PLL_CFG2_S(x) ((x) << 6) +#define SUN8I_HDMI_PHY_PLL_CFG2_S6P25_7P5 BIT(5) +#define SUN8I_HDMI_PHY_PLL_CFG2_S5_7 BIT(4) +#define SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK GENMASK(3, 0) +#define SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_SHIFT 0 +#define SUN8I_HDMI_PHY_PLL_CFG2_PREDIV(x) (((x) - 1) << 0) + +#define SUN8I_HDMI_PHY_PLL_CFG3_REG 0x0034 +#define SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2 BIT(0) + +#define SUN8I_HDMI_PHY_ANA_STS_REG 0x0038 +#define SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT 11 +#define SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK GENMASK(16, 11) +#define SUN8I_HDMI_PHY_ANA_STS_RCALEND2D BIT(7) +#define SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK GENMASK(5, 0) + +#define SUN8I_HDMI_PHY_CEC_REG 0x003c + struct sun8i_hdmi_phy; struct sun8i_hdmi_phy_variant { diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index 17aada64bafd..16889bc0c62d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -7,23 +7,6 @@ #include "sun8i_dw_hdmi.h" -#define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000 -#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK BIT(0) -#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK GENMASK(15, 8) -#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC BIT(8) -#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC BIT(9) -#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK GENMASK(23, 16) -#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr) (addr << 16) - -#define SUN8I_HDMI_PHY_REXT_CTRL_REG 0x0004 -#define SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN BIT(31) - -#define SUN8I_HDMI_PHY_READ_EN_REG 0x0010 -#define SUN8I_HDMI_PHY_READ_EN_MAGIC 0x54524545 - -#define SUN8I_HDMI_PHY_UNSCRAMBLE_REG 0x0014 -#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC 0x42494E47 - /* * Address can be actually any value. Here is set to same value as * it is set in BSP driver. -- cgit v1.2.3 From 4f86e81748fe230b9cf82a7fd69884c7a08ba9d1 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 1 Mar 2018 22:34:38 +0100 Subject: drm/sun4i: Add support for H3 HDMI PHY variant While A83T HDMI PHY seems to be just customized Synopsys HDMI PHY, H3 HDMI PHY is completely custom PHY. However, they still have many things in common like clock and reset setup, setting sync polarity and more. Add support for H3 HDMI PHY variant. While documentation exists for this PHY variant, it doesn't go in great details. Because of that, almost all settings are copied from BSP linux 4.4. Interestingly, those settings are slightly different to those found in a older BSP with Linux 3.4. For now, no user visible difference was found between them. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180301213442.16677-13-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/Makefile | 1 + drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 6 + drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 264 ++++++++++++++++++++++++++++- drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 132 +++++++++++++++ 4 files changed, 400 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile index 1610e748119b..330843ce4280 100644 --- a/drivers/gpu/drm/sun4i/Makefile +++ b/drivers/gpu/drm/sun4i/Makefile @@ -12,6 +12,7 @@ sun4i-drm-hdmi-y += sun4i_hdmi_tmds_clk.o sun8i-drm-hdmi-y += sun8i_dw_hdmi.o sun8i-drm-hdmi-y += sun8i_hdmi_phy.o +sun8i-drm-hdmi-y += sun8i_hdmi_phy_clk.o sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \ sun8i_vi_layer.o sun8i_ui_scaler.o \ diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index 49161326ea5a..79154f0f674a 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h @@ -146,6 +146,7 @@ struct sun8i_hdmi_phy; struct sun8i_hdmi_phy_variant { + bool has_phy_clk; void (*phy_init)(struct sun8i_hdmi_phy *phy); void (*phy_disable)(struct dw_hdmi *hdmi, struct sun8i_hdmi_phy *phy); @@ -157,6 +158,9 @@ struct sun8i_hdmi_phy_variant { struct sun8i_hdmi_phy { struct clk *clk_bus; struct clk *clk_mod; + struct clk *clk_phy; + struct clk *clk_pll0; + unsigned int rcal; struct regmap *regs; struct reset_control *rst_phy; struct sun8i_hdmi_phy_variant *variant; @@ -184,4 +188,6 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi); void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy); const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void); +int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev); + #endif /* _SUN8I_DW_HDMI_H_ */ diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index 16889bc0c62d..5a52fc489a9d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -3,6 +3,7 @@ * Copyright (c) 2018 Jernej Skrabec */ +#include #include #include "sun8i_dw_hdmi.h" @@ -73,7 +74,148 @@ static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi, dw_hdmi_phy_gen2_txpwron(hdmi, 1); return 0; -}; +} + +static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi, + struct sun8i_hdmi_phy *phy, + unsigned int clk_rate) +{ + u32 pll_cfg1_init; + u32 pll_cfg2_init; + u32 ana_cfg1_end; + u32 ana_cfg2_init; + u32 ana_cfg3_init; + u32 b_offset = 0; + u32 val; + + /* bandwidth / frequency independent settings */ + + pll_cfg1_init = SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN | + SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN | + SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(7) | + SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(1) | + SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN | + SUN8I_HDMI_PHY_PLL_CFG1_CS | + SUN8I_HDMI_PHY_PLL_CFG1_CP_S(2) | + SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63) | + SUN8I_HDMI_PHY_PLL_CFG1_BWS; + + pll_cfg2_init = SUN8I_HDMI_PHY_PLL_CFG2_SV_H | + SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN | + SUN8I_HDMI_PHY_PLL_CFG2_SDIV2; + + ana_cfg1_end = SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(1) | + SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT | + SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT | + SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT | + SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT | + SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL | + SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG | + SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS | + SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN | + SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK | + SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL | + SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK | + SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 | + SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 | + SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 | + SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 | + SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 | + SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 | + SUN8I_HDMI_PHY_ANA_CFG1_CKEN | + SUN8I_HDMI_PHY_ANA_CFG1_LDOEN | + SUN8I_HDMI_PHY_ANA_CFG1_ENVBS | + SUN8I_HDMI_PHY_ANA_CFG1_ENBI; + + ana_cfg2_init = SUN8I_HDMI_PHY_ANA_CFG2_M_EN | + SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK | + SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN | + SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(1) | + SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(1); + + ana_cfg3_init = SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(0x3e0) | + SUN8I_HDMI_PHY_ANA_CFG3_SDAEN | + SUN8I_HDMI_PHY_ANA_CFG3_SCLEN; + + /* bandwidth / frequency dependent settings */ + if (clk_rate <= 27000000) { + pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 | + SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32); + pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) | + SUN8I_HDMI_PHY_PLL_CFG2_S(4); + ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW; + ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) | + SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal); + ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(3) | + SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(5); + } else if (clk_rate <= 74250000) { + pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 | + SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32); + pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) | + SUN8I_HDMI_PHY_PLL_CFG2_S(5); + ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW; + ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) | + SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal); + ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(5) | + SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(7); + } else if (clk_rate <= 148500000) { + pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 | + SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32); + pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) | + SUN8I_HDMI_PHY_PLL_CFG2_S(6); + ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK | + SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW | + SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(2); + ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(7) | + SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(9); + } else { + b_offset = 2; + pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63); + pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(6) | + SUN8I_HDMI_PHY_PLL_CFG2_S(7); + ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK | + SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW | + SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4); + ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(9) | + SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(13); + } + + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, + SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0); + + regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, pll_cfg1_init); + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, + (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK, + pll_cfg2_init); + usleep_range(10000, 15000); + regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG3_REG, + SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2); + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, + SUN8I_HDMI_PHY_PLL_CFG1_PLLEN, + SUN8I_HDMI_PHY_PLL_CFG1_PLLEN); + msleep(100); + + /* get B value */ + regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val); + val = (val & SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK) >> + SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT; + val = min(val + b_offset, (u32)0x3f); + + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, + SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 | + SUN8I_HDMI_PHY_PLL_CFG1_REG_OD, + SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 | + SUN8I_HDMI_PHY_PLL_CFG1_REG_OD); + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, + SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK, + val << SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT); + msleep(100); + regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, ana_cfg1_end); + regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG2_REG, ana_cfg2_init); + regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG, ana_cfg3_init); + + return 0; +} static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, struct drm_display_mode *mode) @@ -90,6 +232,9 @@ static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val); + if (phy->variant->has_phy_clk) + clk_set_rate(phy->clk_phy, mode->crtc_clock * 1000); + return phy->variant->phy_config(hdmi, phy, mode->crtc_clock * 1000); }; @@ -103,6 +248,16 @@ static void sun8i_hdmi_phy_disable_a83t(struct dw_hdmi *hdmi, SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0); } +static void sun8i_hdmi_phy_disable_h3(struct dw_hdmi *hdmi, + struct sun8i_hdmi_phy *phy) +{ + regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, + SUN8I_HDMI_PHY_ANA_CFG1_LDOEN | + SUN8I_HDMI_PHY_ANA_CFG1_ENVBS | + SUN8I_HDMI_PHY_ANA_CFG1_ENBI); + regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0); +} + static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data) { struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data; @@ -133,6 +288,78 @@ static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy) SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR)); } +static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy) +{ + unsigned int val; + + regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0); + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, + SUN8I_HDMI_PHY_ANA_CFG1_ENBI, + SUN8I_HDMI_PHY_ANA_CFG1_ENBI); + udelay(5); + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, + SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN, + SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN); + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, + SUN8I_HDMI_PHY_ANA_CFG1_ENVBS, + SUN8I_HDMI_PHY_ANA_CFG1_ENVBS); + usleep_range(10, 20); + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, + SUN8I_HDMI_PHY_ANA_CFG1_LDOEN, + SUN8I_HDMI_PHY_ANA_CFG1_LDOEN); + udelay(5); + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, + SUN8I_HDMI_PHY_ANA_CFG1_CKEN, + SUN8I_HDMI_PHY_ANA_CFG1_CKEN); + usleep_range(40, 100); + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, + SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL, + SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL); + usleep_range(100, 200); + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, + SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG, + SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG); + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, + SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 | + SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 | + SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2, + SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 | + SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 | + SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2); + + /* wait for calibration to finish */ + regmap_read_poll_timeout(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, val, + (val & SUN8I_HDMI_PHY_ANA_STS_RCALEND2D), + 100, 2000); + + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, + SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK, + SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK); + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, + SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 | + SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 | + SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 | + SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK, + SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 | + SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 | + SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 | + SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK); + + /* enable DDC communication */ + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG, + SUN8I_HDMI_PHY_ANA_CFG3_SCLEN | + SUN8I_HDMI_PHY_ANA_CFG3_SDAEN, + SUN8I_HDMI_PHY_ANA_CFG3_SCLEN | + SUN8I_HDMI_PHY_ANA_CFG3_SDAEN); + + /* set HW control of CEC pins */ + regmap_write(phy->regs, SUN8I_HDMI_PHY_CEC_REG, 0); + + /* read calibration data */ + regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val); + phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2; +} + void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) { /* enable read access to HDMI controller */ @@ -155,7 +382,7 @@ static struct regmap_config sun8i_hdmi_phy_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .max_register = SUN8I_HDMI_PHY_UNSCRAMBLE_REG, + .max_register = SUN8I_HDMI_PHY_CEC_REG, .name = "phy" }; @@ -165,11 +392,22 @@ static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = { .phy_config = &sun8i_hdmi_phy_config_a83t, }; +static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = { + .has_phy_clk = true, + .phy_init = &sun8i_hdmi_phy_init_h3, + .phy_disable = &sun8i_hdmi_phy_disable_h3, + .phy_config = &sun8i_hdmi_phy_config_h3, +}; + static const struct of_device_id sun8i_hdmi_phy_of_table[] = { { .compatible = "allwinner,sun8i-a83t-hdmi-phy", .data = &sun8i_a83t_hdmi_phy, }, + { + .compatible = "allwinner,sun8i-h3-hdmi-phy", + .data = &sun8i_h3_hdmi_phy, + }, { /* sentinel */ } }; @@ -226,11 +464,26 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node) goto err_put_clk_bus; } + if (phy->variant->has_phy_clk) { + phy->clk_pll0 = of_clk_get_by_name(node, "pll-0"); + if (IS_ERR(phy->clk_pll0)) { + dev_err(dev, "Could not get pll-0 clock\n"); + ret = PTR_ERR(phy->clk_pll0); + goto err_put_clk_mod; + } + + ret = sun8i_phy_clk_create(phy, dev); + if (ret) { + dev_err(dev, "Couldn't create the PHY clock\n"); + goto err_put_clk_pll0; + } + } + phy->rst_phy = of_reset_control_get_shared(node, "phy"); if (IS_ERR(phy->rst_phy)) { dev_err(dev, "Could not get phy reset control\n"); ret = PTR_ERR(phy->rst_phy); - goto err_put_clk_mod; + goto err_put_clk_pll0; } ret = reset_control_deassert(phy->rst_phy); @@ -261,6 +514,9 @@ err_deassert_rst_phy: reset_control_assert(phy->rst_phy); err_put_rst_phy: reset_control_put(phy->rst_phy); +err_put_clk_pll0: + if (phy->variant->has_phy_clk) + clk_put(phy->clk_pll0); err_put_clk_mod: clk_put(phy->clk_mod); err_put_clk_bus: @@ -280,6 +536,8 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi) reset_control_put(phy->rst_phy); + if (phy->variant->has_phy_clk) + clk_put(phy->clk_pll0); clk_put(phy->clk_mod); clk_put(phy->clk_bus); } diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c new file mode 100644 index 000000000000..faea449812f8 --- /dev/null +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Jernej Skrabec + */ + +#include + +#include "sun8i_dw_hdmi.h" + +struct sun8i_phy_clk { + struct clk_hw hw; + struct sun8i_hdmi_phy *phy; +}; + +static inline struct sun8i_phy_clk *hw_to_phy_clk(struct clk_hw *hw) +{ + return container_of(hw, struct sun8i_phy_clk, hw); +} + +static int sun8i_phy_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + unsigned long rate = req->rate; + unsigned long best_rate = 0; + struct clk_hw *parent; + int best_div = 1; + int i; + + parent = clk_hw_get_parent(hw); + + for (i = 1; i <= 16; i++) { + unsigned long ideal = rate * i; + unsigned long rounded; + + rounded = clk_hw_round_rate(parent, ideal); + + if (rounded == ideal) { + best_rate = rounded; + best_div = i; + break; + } + + if (!best_rate || + abs(rate - rounded / i) < + abs(rate - best_rate / best_div)) { + best_rate = rounded; + best_div = i; + } + } + + req->rate = best_rate / best_div; + req->best_parent_rate = best_rate; + req->best_parent_hw = parent; + + return 0; +} + +static unsigned long sun8i_phy_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sun8i_phy_clk *priv = hw_to_phy_clk(hw); + u32 reg; + + regmap_read(priv->phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, ®); + reg = ((reg >> SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_SHIFT) & + SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK) + 1; + + return parent_rate / reg; +} + +static int sun8i_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct sun8i_phy_clk *priv = hw_to_phy_clk(hw); + unsigned long best_rate = 0; + u8 best_m = 0, m; + + for (m = 1; m <= 16; m++) { + unsigned long tmp_rate = parent_rate / m; + + if (tmp_rate > rate) + continue; + + if (!best_rate || + (rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_m = m; + } + } + + regmap_update_bits(priv->phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, + SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK, + SUN8I_HDMI_PHY_PLL_CFG2_PREDIV(best_m)); + + return 0; +} + +static const struct clk_ops sun8i_phy_clk_ops = { + .determine_rate = sun8i_phy_clk_determine_rate, + .recalc_rate = sun8i_phy_clk_recalc_rate, + .set_rate = sun8i_phy_clk_set_rate, +}; + +int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev) +{ + struct clk_init_data init; + struct sun8i_phy_clk *priv; + const char *parents[1]; + + parents[0] = __clk_get_name(phy->clk_pll0); + if (!parents[0]) + return -ENODEV; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + init.name = "hdmi-phy-clk"; + init.ops = &sun8i_phy_clk_ops; + init.parent_names = parents; + init.num_parents = 1; + init.flags = CLK_SET_RATE_PARENT; + + priv->phy = phy; + priv->hw.init = &init; + + phy->clk_phy = devm_clk_register(dev, &priv->hw); + if (IS_ERR(phy->clk_phy)) + return PTR_ERR(phy->clk_phy); + + return 0; +} -- cgit v1.2.3 From 9ffef62f226ceefe8a8415462a797ae688a6251e Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 1 Mar 2018 22:34:39 +0100 Subject: drm/sun4i: Allow building on arm64 64-bit ARM SoCs from Allwinner have DE2/TCON/HDMI periphery which is compatible to 32-bit SoCs, so allow building DRM driver for arm64 architecture. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180301213442.16677-14-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig index 7327da3bc94f..eee6bc0eaf97 100644 --- a/drivers/gpu/drm/sun4i/Kconfig +++ b/drivers/gpu/drm/sun4i/Kconfig @@ -1,6 +1,6 @@ config DRM_SUN4I tristate "DRM Support for Allwinner A10 Display Engine" - depends on DRM && ARM && COMMON_CLK + depends on DRM && (ARM || ARM64) && COMMON_CLK depends on ARCH_SUNXI || COMPILE_TEST select DRM_GEM_CMA_HELPER select DRM_KMS_HELPER -- cgit v1.2.3 From 7f8ae00f63725e835b5ed8a97bc18bf1c950acb2 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Wed, 27 Dec 2017 15:21:18 +0200 Subject: iwlwifi: Cancel and set MARKER_CMD timer during suspend-resume While entering to D3 mode there is a gap between the time the driver handles the D3_CONFIG_CMD response to the time the host is going to sleep. In between there might be cases which MARKER_CMD can tailgate. Also during resume flow the MARKER_CMD might get sent while D0I3_CMD is being handled in the FW. Cancel MARKER_CMD timer and set it again properly during suspend resume flows to prevent this command from being sent accidentlly. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/debugfs.h | 18 ++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/init.c | 12 ++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 4 ++++ drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 8 ++++++++ 4 files changed, 42 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h index e57ff92a68ae..3da468d2cc92 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h @@ -75,6 +75,20 @@ static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) cancel_delayed_work_sync(&fwrt->timestamp.wk); } +static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) +{ + cancel_delayed_work_sync(&fwrt->timestamp.wk); +} + +static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) +{ + if (!fwrt->timestamp.delay) + return; + + schedule_delayed_work(&fwrt->timestamp.wk, + round_jiffies_relative(fwrt->timestamp.delay)); +} + #else static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, struct dentry *dbgfs_dir) @@ -84,4 +98,8 @@ static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) {} +static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) {} + +static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {} + #endif /* CONFIG_IWLWIFI_DEBUGFS */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/init.c b/drivers/net/wireless/intel/iwlwifi/fw/init.c index 45f21acbd842..2efac307909e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/init.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/init.c @@ -76,3 +76,15 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, iwl_fwrt_dbgfs_register(fwrt, dbgfs_dir); } IWL_EXPORT_SYMBOL(iwl_fw_runtime_init); + +void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt) +{ + iwl_fw_suspend_timestamp(fwrt); +} +IWL_EXPORT_SYMBOL(iwl_fw_runtime_suspend); + +void iwl_fw_runtime_resume(struct iwl_fw_runtime *fwrt) +{ + iwl_fw_resume_timestamp(fwrt); +} +IWL_EXPORT_SYMBOL(iwl_fw_runtime_resume); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index e25c049f980f..f3197f7c13b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -150,6 +150,10 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, void iwl_fw_runtime_exit(struct iwl_fw_runtime *fwrt); +void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt); + +void iwl_fw_runtime_resume(struct iwl_fw_runtime *fwrt); + static inline void iwl_fw_set_current_image(struct iwl_fw_runtime *fwrt, enum iwl_ucode_type cur_fw_img) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 0e6cf39285f4..2efe9b099556 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1098,6 +1098,8 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) /* make sure the d0i3 exit work is not pending */ flush_work(&mvm->d0i3_exit_work); + iwl_fw_runtime_suspend(&mvm->fwrt); + ret = iwl_trans_suspend(trans); if (ret) return ret; @@ -2012,6 +2014,8 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; + iwl_fw_runtime_resume(&mvm->fwrt); + return ret; } @@ -2038,6 +2042,8 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file) mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3; + iwl_fw_runtime_suspend(&mvm->fwrt); + /* start pseudo D3 */ rtnl_lock(); err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true); @@ -2098,6 +2104,8 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) __iwl_mvm_resume(mvm, true); rtnl_unlock(); + iwl_fw_runtime_resume(&mvm->fwrt); + mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; iwl_abort_notification_waits(&mvm->notif_wait); -- cgit v1.2.3 From de04d4fbf87b769ab18c480e4f020c53e74bbdd2 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 2 Jan 2018 11:40:15 +0200 Subject: iwlwifi: mvm: fix TX of CCMP 256 We don't have enough room in the TX command for a CCMP 256 key, and need to use key from table. Fixes: 3264bf032bd9 ("[BUGFIX] iwlwifi: mvm: Fix CCMP IV setting") Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index dda77b327c98..57ad6019ffad 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -419,11 +419,11 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, { struct ieee80211_key_conf *keyconf = info->control.hw_key; u8 *crypto_hdr = skb_frag->data + hdrlen; + enum iwl_tx_cmd_sec_ctrl type = TX_CMD_SEC_CCM; u64 pn; switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_CCMP_256: iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd); iwl_mvm_set_tx_cmd_pn(info, crypto_hdr); break; @@ -447,13 +447,16 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, break; case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: + type = TX_CMD_SEC_GCMP; + /* Fall through */ + case WLAN_CIPHER_SUITE_CCMP_256: /* TODO: Taking the key from the table might introduce a race * when PTK rekeying is done, having an old packets with a PN * based on the old key but the message encrypted with a new * one. * Need to handle this. */ - tx_cmd->sec_ctl |= TX_CMD_SEC_GCMP | TX_CMD_SEC_KEY_FROM_TABLE; + tx_cmd->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE; tx_cmd->key[0] = keyconf->hw_key_idx; iwl_mvm_set_tx_cmd_pn(info, crypto_hdr); break; -- cgit v1.2.3 From 40d53f4a60c9eb10d4fa58066c23ba1af8a59e39 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Thu, 4 Jan 2018 17:39:08 +0200 Subject: iwlwifi: mvm: Fix channel switch for count 0 and 1 It was assumed that apply_time==0 implies immediate scheduling, which is wrong. Instead, the fw expects the START_IMMEDIATELY flag to be set. Otherwise, this resulted in 0x3063 assert. Fix that. While at it rename the T2_V2_START_IMMEDIATELY to TE_V2_START_IMMEDIATELY. Fixes: f5d8f50f271d ("iwlwifi: mvm: Fix channel switch in case of count <= 1") Signed-off-by: Andrei Otcheretianski Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h index 3721a3ed358b..f824bebceb06 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -211,7 +211,7 @@ enum { * @TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end * @TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use. * @TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. - * @T2_V2_START_IMMEDIATELY: start time event immediately + * @TE_V2_START_IMMEDIATELY: start time event immediately * @TE_V2_DEP_OTHER: depends on another time event * @TE_V2_DEP_TSF: depends on a specific time * @TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC @@ -230,7 +230,7 @@ enum iwl_time_event_policy { TE_V2_NOTIF_HOST_FRAG_END = BIT(5), TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6), TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), - T2_V2_START_IMMEDIATELY = BIT(11), + TE_V2_START_IMMEDIATELY = BIT(11), /* placement characteristics */ TE_V2_DEP_OTHER = BIT(TE_V2_PLACEMENT_POS), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 200ab50ec86b..acb217e666db 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -616,7 +616,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, time_cmd.repeat = 1; time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | TE_V2_NOTIF_HOST_EVENT_END | - T2_V2_START_IMMEDIATELY); + TE_V2_START_IMMEDIATELY); if (!wait_for_notif) { iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); @@ -803,7 +803,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, time_cmd.repeat = 1; time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | TE_V2_NOTIF_HOST_EVENT_END | - T2_V2_START_IMMEDIATELY); + TE_V2_START_IMMEDIATELY); return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } @@ -913,6 +913,8 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, time_cmd.interval = cpu_to_le32(1); time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | TE_V2_ABSENCE); + if (!apply_time) + time_cmd.policy |= cpu_to_le16(TE_V2_START_IMMEDIATELY); return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } -- cgit v1.2.3 From 63dd5d022f4766e6b05ee611124afcc7cbfbb953 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 7 Jan 2018 14:30:49 +0200 Subject: iwlwifi: mvm: fix assert 0x2B00 on older FWs We should add the multicast station before adding the broadcast station. However, in older FW, the firmware will start beaconing when we add the multicast station, and since the broadcast station is not added at this point so the transmission of the beacon will fail on assert 0x2b00. This is fixed in later firmware, so make the order of addition depend on the TLV. Fixes: 26d6c16bed53 ("iwlwifi: mvm: add multicast station") Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 45 ++++++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 08de822c3ef0..ebf511150f4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * 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 @@ -2106,15 +2107,40 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, if (ret) goto out_remove; - ret = iwl_mvm_add_mcast_sta(mvm, vif); - if (ret) - goto out_unbind; - - /* Send the bcast station. At this stage the TBTT and DTIM time events - * are added and applied to the scheduler */ - ret = iwl_mvm_send_add_bcast_sta(mvm, vif); - if (ret) - goto out_rm_mcast; + /* + * This is not very nice, but the simplest: + * For older FWs adding the mcast sta before the bcast station may + * cause assert 0x2b00. + * This is fixed in later FW so make the order of removal depend on + * the TLV + */ + if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) { + ret = iwl_mvm_add_mcast_sta(mvm, vif); + if (ret) + goto out_unbind; + /* + * Send the bcast station. At this stage the TBTT and DTIM time + * events are added and applied to the scheduler + */ + ret = iwl_mvm_send_add_bcast_sta(mvm, vif); + if (ret) { + iwl_mvm_rm_mcast_sta(mvm, vif); + goto out_unbind; + } + } else { + /* + * Send the bcast station. At this stage the TBTT and DTIM time + * events are added and applied to the scheduler + */ + iwl_mvm_send_add_bcast_sta(mvm, vif); + if (ret) + goto out_unbind; + iwl_mvm_add_mcast_sta(mvm, vif); + if (ret) { + iwl_mvm_send_rm_bcast_sta(mvm, vif); + goto out_unbind; + } + } /* must be set before quota calculations */ mvmvif->ap_ibss_active = true; @@ -2144,7 +2170,6 @@ out_quota_failed: iwl_mvm_power_update_mac(mvm); mvmvif->ap_ibss_active = false; iwl_mvm_send_rm_bcast_sta(mvm, vif); -out_rm_mcast: iwl_mvm_rm_mcast_sta(mvm, vif); out_unbind: iwl_mvm_binding_remove_vif(mvm, vif); -- cgit v1.2.3 From 8745f12a6600dd9d31122588621d4c8ddb332cd7 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 11 Jan 2018 16:18:46 +0200 Subject: iwlwifi: avoid collecting firmware dump if not loaded Trying to collect firmware debug data while firmware is not loaded causes various errors (e.g. failing NIC access). This causes even a bigger issue if at that time the HW radio is off. In that case, when later turning the radio on, the Driver fails to read the HW (registers contain garbage values). (It may be that the CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN bit is cleared on faulty NIC access - since the same behavior was seen in HW RFKILL toggling before setting that bit.) Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 13 +++++++++++-- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 3 +++ drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 5 ++--- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 8 ++++++++ 5 files changed, 27 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 67aefc8fc9ac..7bd704a3e640 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -8,6 +8,7 @@ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * 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 @@ -33,6 +34,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -942,7 +944,6 @@ dump_trans_data: out: iwl_fw_free_dump_desc(fwrt); - fwrt->dump.trig = NULL; clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status); IWL_DEBUG_INFO(fwrt, "WRT dump done\n"); } @@ -1112,6 +1113,14 @@ void iwl_fw_error_dump_wk(struct work_struct *work) fwrt->ops->dump_start(fwrt->ops_ctx)) return; + if (fwrt->ops && fwrt->ops->fw_running && + !fwrt->ops->fw_running(fwrt->ops_ctx)) { + IWL_ERR(fwrt, "Firmware not running - cannot dump error\n"); + iwl_fw_free_dump_desc(fwrt); + clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status); + goto out; + } + if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { /* stop recording */ iwl_fw_dbg_stop_recording(fwrt); @@ -1145,7 +1154,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work) iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, out_ctrl); } } - +out: if (fwrt->ops && fwrt->ops->dump_end) fwrt->ops->dump_end(fwrt->ops_ctx); } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 223fb77a3aa9..72259bff9922 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -8,6 +8,7 @@ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * 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 @@ -33,6 +34,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -91,6 +93,7 @@ static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt) if (fwrt->dump.desc != &iwl_dump_desc_assert) kfree(fwrt->dump.desc); fwrt->dump.desc = NULL; + fwrt->dump.trig = NULL; } void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index f3197f7c13b6..3fb940ebd74a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * 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 @@ -26,6 +27,7 @@ * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,6 +70,7 @@ struct iwl_fw_runtime_ops { int (*dump_start)(void *ctx); void (*dump_end)(void *ctx); + bool (*fw_running)(void *ctx); }; #define MAX_NUM_LMAC 2 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index a7892c1254a2..9c436d8d001d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * 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 @@ -35,6 +36,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1281,9 +1283,6 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, { int ret; - if (!iwl_mvm_firmware_running(mvm)) - return -EIO; - ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); if (ret) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 6bb347bf0d6e..ab7fb5aad984 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * 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 @@ -35,6 +36,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -552,9 +554,15 @@ static void iwl_mvm_fwrt_dump_end(void *ctx) iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT); } +static bool iwl_mvm_fwrt_fw_running(void *ctx) +{ + return iwl_mvm_firmware_running(ctx); +} + static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = { .dump_start = iwl_mvm_fwrt_dump_start, .dump_end = iwl_mvm_fwrt_dump_end, + .fw_running = iwl_mvm_fwrt_fw_running, }; static struct iwl_op_mode * -- cgit v1.2.3 From e4f13ad07823b24a1537518d2163bd164292fb10 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 15 Jan 2018 13:50:59 +0200 Subject: iwlwifi: mvm: fix "failed to remove key" message When the GTK is installed, we install it to HW with the station ID of the AP. Mac80211 will try to remove it only after the AP sta is removed, which will result in a failure to remove key since we do not have any station for it. This is a valid situation, but a previous commit removed the early return and added a return with error value, which resulted in an error message that is confusing to users. Remove the error return value. Fixes: 85aeb58cec1a ("iwlwifi: mvm: Enable security on new TX API") Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index dbd2ba2bb714..3739e42b34e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -3170,8 +3170,9 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, int ret, size; u32 status; + /* This is a valid situation for GTK removal */ if (sta_id == IWL_MVM_INVALID_STA) - return -EINVAL; + return 0; key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & STA_KEY_FLG_KEYID_MSK); -- cgit v1.2.3 From 7c305de2b9548ab6b65fce342c78618bbed5db73 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 22 Jan 2018 08:55:06 +0200 Subject: iwlwifi: mvm: Direct multicast frames to the correct station Multicast frames for NL80211_IFTYPE_AP and NL80211_IFTYPE_ADHOC were directed to the broadcast station, however, as the broadcast station did not have keys configured, these frames were sent unencrypted. Fix this by using the multicast station which is the station for which encryption keys are configured. Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 57ad6019ffad..af6dfceab6b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -648,7 +648,11 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE || info.control.vif->type == NL80211_IFTYPE_AP || info.control.vif->type == NL80211_IFTYPE_ADHOC) { - sta_id = mvmvif->bcast_sta.sta_id; + if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE) + sta_id = mvmvif->bcast_sta.sta_id; + else + sta_id = mvmvif->mcast_sta.sta_id; + queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, hdr->frame_control); if (queue < 0) -- cgit v1.2.3 From 6508de0305d560235b366cc2cc98f7bcfb029e92 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 25 Jan 2018 15:22:41 +0200 Subject: iwlwifi: mvm: Correctly set the tid for mcast queue In the scheduler config command, the meaning of tid == 0xf was intended to indicate the configuration is for management frames. However, tid == 0xf was also used for the multicast queue that was meant only for multicast data frames, which resulted with the FW not encrypting multicast data frames. As multicast frames do not have a QoS header, fix this by setting tid == 0, to indicate that this is a data queue and not management one. Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 3739e42b34e4..630e23cb0ffb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2039,7 +2039,7 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) struct iwl_trans_txq_scd_cfg cfg = { .fifo = IWL_MVM_TX_FIFO_MCAST, .sta_id = msta->sta_id, - .tid = IWL_MAX_TID_COUNT, + .tid = 0, .aggregate = false, .frame_limit = IWL_FRAME_LIMIT, }; @@ -2090,7 +2090,7 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (iwl_mvm_has_new_tx_api(mvm)) { int queue = iwl_mvm_tvqm_enable_txq(mvm, vif->cab_queue, msta->sta_id, - IWL_MAX_TID_COUNT, + 0, timeout); mvmvif->cab_queue = queue; } else if (!fw_has_api(&mvm->fw->ucode_capa, @@ -2115,7 +2115,7 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0); iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue, - IWL_MAX_TID_COUNT, 0); + 0, 0); ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id); if (ret) -- cgit v1.2.3 From de655fa8fb237d0eaf838e8833b464c1dec90070 Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Mon, 5 Feb 2018 02:21:30 +0100 Subject: iwlwifi: fix malformed CONFIG_IWLWIFI_PCIE_RTPM default 'default false' should be 'default n', though they happen to have the same effect here, due to undefined symbols ('false' in this case) evaluating to n in a tristate sense. Remove the default instead of changing it. bool and tristate symbols implicitly default to n. Discovered with the https://github.com/ulfalizer/Kconfiglib/blob/master/examples/list_undefined.py script. Signed-off-by: Ulf Magnusson Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig index c5f2ddf9b0fe..e5a2fc738ac3 100644 --- a/drivers/net/wireless/intel/iwlwifi/Kconfig +++ b/drivers/net/wireless/intel/iwlwifi/Kconfig @@ -91,7 +91,6 @@ config IWLWIFI_BCAST_FILTERING config IWLWIFI_PCIE_RTPM bool "Enable runtime power management mode for PCIe devices" depends on IWLMVM && PM && EXPERT - default false help Say Y here to enable runtime power management for PCIe devices. If enabled, the device will go into low power mode -- cgit v1.2.3 From 7c4246797b84e55e2dfaaf8a18033de9df7c18c1 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Tue, 27 Feb 2018 16:42:13 +0100 Subject: i2c: octeon: Prevent error message on bus error The error message: [Fri Feb 16 13:42:13 2018] i2c-thunderx 0000:01:09.4: unhandled state: 0 is mis-leading as state 0 (bus error) is not an unknown state. Return -EIO as before but avoid printing the message. Also rename STAT_ERROR to STATE_BUS_ERROR. Signed-off-by: Jan Glauber Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-octeon-core.c | 1 + drivers/i2c/busses/i2c-octeon-core.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c index 1d8775799056..d9607905dc2f 100644 --- a/drivers/i2c/busses/i2c-octeon-core.c +++ b/drivers/i2c/busses/i2c-octeon-core.c @@ -233,6 +233,7 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) return -EOPNOTSUPP; case STAT_TXDATA_NAK: + case STAT_BUS_ERROR: return -EIO; case STAT_TXADDR_NAK: case STAT_RXADDR_NAK: diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h index a7ef19855bb8..9bb9f64fdda0 100644 --- a/drivers/i2c/busses/i2c-octeon-core.h +++ b/drivers/i2c/busses/i2c-octeon-core.h @@ -43,7 +43,7 @@ #define TWSI_CTL_AAK 0x04 /* Assert ACK */ /* Status values */ -#define STAT_ERROR 0x00 +#define STAT_BUS_ERROR 0x00 #define STAT_START 0x08 #define STAT_REP_START 0x10 #define STAT_TXADDR_ACK 0x18 -- cgit v1.2.3 From 80f690e9e3a60f628de61748be4dd2fd6baf5cc8 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 19 Feb 2018 22:28:23 +0200 Subject: drm: Add optional COLOR_ENCODING and COLOR_RANGE properties to drm_plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a standard optional properties to support different non RGB color encodings in DRM planes. COLOR_ENCODING select the supported non RGB color encoding, for instance ITU-R BT.709 YCbCr. COLOR_RANGE selects the value ranges within the selected color encoding. The properties are stored to drm_plane object to allow different set of supported encoding for different planes on the device. v2: Add/fix kerneldocs, verify bitmasks (danvet) Cc: Harry Wentland Cc: Daniel Vetter Cc: Daniel Stone Cc: Russell King - ARM Linux Cc: Ilia Mirkin Cc: Hans Verkuil Cc: Uma Shankar Cc: Shashank Sharma Reviewed-by: Ville Syrjälä Signed-off-by: Jyri Sarha [vsyrjala v2: Add/fix kerneldocs, verify bitmasks] Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180219202823.10508-1-ville.syrjala@linux.intel.com Acked-by: Harry Wentland Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 8 +++ drivers/gpu/drm/drm_color_mgmt.c | 103 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 3a30ee715752..9e96a9a16b9e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -759,6 +759,10 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, state->rotation = val; } else if (property == plane->zpos_property) { state->zpos = val; + } else if (property == plane->color_encoding_property) { + state->color_encoding = val; + } else if (property == plane->color_range_property) { + state->color_range = val; } else if (plane->funcs->atomic_set_property) { return plane->funcs->atomic_set_property(plane, state, property, val); @@ -818,6 +822,10 @@ drm_atomic_plane_get_property(struct drm_plane *plane, *val = state->rotation; } else if (property == plane->zpos_property) { *val = state->zpos; + } else if (property == plane->color_encoding_property) { + *val = state->color_encoding; + } else if (property == plane->color_range_property) { + *val = state->color_range; } else if (plane->funcs->atomic_get_property) { return plane->funcs->atomic_get_property(plane, state, property, val); } else { diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index 0d002b045bd2..4b83e078d3e9 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -88,6 +88,20 @@ * drm_mode_crtc_set_gamma_size(). Drivers which support both should use * drm_atomic_helper_legacy_gamma_set() to alias the legacy gamma ramp with the * "GAMMA_LUT" property above. + * + * Support for different non RGB color encodings is controlled through + * &drm_plane specific COLOR_ENCODING and COLOR_RANGE properties. They + * are set up by calling drm_plane_create_color_properties(). + * + * "COLOR_ENCODING" + * Optional plane enum property to support different non RGB + * color encodings. The driver can provide a subset of standard + * enum values supported by the DRM plane. + * + * "COLOR_RANGE" + * Optional plane enum property to support different non RGB + * color parameter ranges. The driver can provide a subset of + * standard enum values supported by the DRM plane. */ /** @@ -339,3 +353,92 @@ out: drm_modeset_unlock(&crtc->mutex); return ret; } + +static const char * const color_encoding_name[] = { + [DRM_COLOR_YCBCR_BT601] = "ITU-R BT.601 YCbCr", + [DRM_COLOR_YCBCR_BT709] = "ITU-R BT.709 YCbCr", + [DRM_COLOR_YCBCR_BT2020] = "ITU-R BT.2020 YCbCr", +}; + +static const char * const color_range_name[] = { + [DRM_COLOR_YCBCR_FULL_RANGE] = "YCbCr full range", + [DRM_COLOR_YCBCR_LIMITED_RANGE] = "YCbCr limited range", +}; + +/** + * drm_plane_create_color_properties - color encoding related plane properties + * @plane: plane object + * @supported_encodings: bitfield indicating supported color encodings + * @supported_ranges: bitfileld indicating supported color ranges + * @default_encoding: default color encoding + * @default_range: default color range + * + * Create and attach plane specific COLOR_ENCODING and COLOR_RANGE + * properties to @plane. The supported encodings and ranges should + * be provided in supported_encodings and supported_ranges bitmasks. + * Each bit set in the bitmask indicates that its number as enum + * value is supported. + */ +int drm_plane_create_color_properties(struct drm_plane *plane, + u32 supported_encodings, + u32 supported_ranges, + enum drm_color_encoding default_encoding, + enum drm_color_range default_range) +{ + struct drm_device *dev = plane->dev; + struct drm_property *prop; + struct drm_prop_enum_list enum_list[max(DRM_COLOR_ENCODING_MAX, + DRM_COLOR_RANGE_MAX)]; + int i, len; + + if (WARN_ON(supported_encodings == 0 || + (supported_encodings & -BIT(DRM_COLOR_ENCODING_MAX)) != 0 || + (supported_encodings & BIT(default_encoding)) == 0)) + return -EINVAL; + + if (WARN_ON(supported_ranges == 0 || + (supported_ranges & -BIT(DRM_COLOR_RANGE_MAX)) != 0 || + (supported_ranges & BIT(default_range)) == 0)) + return -EINVAL; + + len = 0; + for (i = 0; i < DRM_COLOR_ENCODING_MAX; i++) { + if ((supported_encodings & BIT(i)) == 0) + continue; + + enum_list[len].type = i; + enum_list[len].name = color_encoding_name[i]; + len++; + } + + prop = drm_property_create_enum(dev, 0, "COLOR_ENCODING", + enum_list, len); + if (!prop) + return -ENOMEM; + plane->color_encoding_property = prop; + drm_object_attach_property(&plane->base, prop, default_encoding); + if (plane->state) + plane->state->color_encoding = default_encoding; + + len = 0; + for (i = 0; i < DRM_COLOR_RANGE_MAX; i++) { + if ((supported_ranges & BIT(i)) == 0) + continue; + + enum_list[len].type = i; + enum_list[len].name = color_range_name[i]; + len++; + } + + prop = drm_property_create_enum(dev, 0, "COLOR_RANGE", + enum_list, len); + if (!prop) + return -ENOMEM; + plane->color_range_property = prop; + drm_object_attach_property(&plane->base, prop, default_range); + if (plane->state) + plane->state->color_range = default_range; + + return 0; +} +EXPORT_SYMBOL(drm_plane_create_color_properties); -- cgit v1.2.3 From 56dbbaff0fc739c573ccd351028c49066e938363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 19 Feb 2018 22:28:46 +0200 Subject: drm/atomic: Include color encoding/range in plane state dump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Include color_enconding and color_range in the plane state dump. v2: Add kerneldoc (danvet) Cc: Harry Wentland Cc: Daniel Vetter Cc: Daniel Stone Cc: Russell King - ARM Linux Cc: Ilia Mirkin Cc: Hans Verkuil Cc: Uma Shankar Cc: Shashank Sharma Cc: Jyri Sarha Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180219202846.10628-1-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter Acked-by: Harry Wentland --- drivers/gpu/drm/drm_atomic.c | 4 ++++ drivers/gpu/drm/drm_color_mgmt.c | 30 ++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc_internal.h | 2 ++ 3 files changed, 36 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 9e96a9a16b9e..34b7d420e555 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -954,6 +954,10 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src)); drm_printf(p, "\trotation=%x\n", state->rotation); + drm_printf(p, "\tcolor-encoding=%s\n", + drm_get_color_encoding_name(state->color_encoding)); + drm_printf(p, "\tcolor-range=%s\n", + drm_get_color_range_name(state->color_range)); if (plane->funcs->atomic_print_state) plane->funcs->atomic_print_state(p, state); diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index 4b83e078d3e9..4ff064623836 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -365,6 +365,36 @@ static const char * const color_range_name[] = { [DRM_COLOR_YCBCR_LIMITED_RANGE] = "YCbCr limited range", }; +/** + * drm_get_color_encoding_name - return a string for color encoding + * @encoding: color encoding to compute name of + * + * In contrast to the other drm_get_*_name functions this one here returns a + * const pointer and hence is threadsafe. + */ +const char *drm_get_color_encoding_name(enum drm_color_encoding encoding) +{ + if (WARN_ON(encoding >= ARRAY_SIZE(color_encoding_name))) + return "unknown"; + + return color_encoding_name[encoding]; +} + +/** + * drm_get_color_range_name - return a string for color range + * @range: color range to compute name of + * + * In contrast to the other drm_get_*_name functions this one here returns a + * const pointer and hence is threadsafe. + */ +const char *drm_get_color_range_name(enum drm_color_range range) +{ + if (WARN_ON(range >= ARRAY_SIZE(color_range_name))) + return "unknown"; + + return color_range_name[range]; +} + /** * drm_plane_create_color_properties - color encoding related plane properties * @plane: plane object diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 860968a64ae7..3c2b82865ad2 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -71,6 +71,8 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); /* drm_color_mgmt.c */ +const char *drm_get_color_encoding_name(enum drm_color_encoding encoding); +const char *drm_get_color_range_name(enum drm_color_range range); /* IOCTLs */ int drm_mode_gamma_get_ioctl(struct drm_device *dev, -- cgit v1.2.3 From 5deae9191130db6b617c94fb261804597cf9b508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 14 Feb 2018 21:23:23 +0200 Subject: drm/i915: Correctly handle limited range YCbCr data on VLV/CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turns out the VLV/CHV fixed function sprite CSC expects full range data as input. We've been feeding it limited range data to it all along. To expand the data out to full range we'll use the color correction registers (brightness, contrast, and saturation). On CHV pipe B we were actually doing the right thing already because we progammed the custom CSC matrix to do expect limited range input. Now that well pre-expand the data out with the color correction unit, we need to change the CSC matrix to operate with full range input instead. This should make the sprite output of the other pipes match the sprite output of pipe B reasonably well. Looking at the resulting pipe CRCs, there can be a slight difference in the output, but as I don't know the formula used by the fixed function CSC of the other pipes, I don't think it's worth the effort to try to match the output exactly. It might not even be possible due to difference in internal precision etc. One slight caveat here is that the color correction registers are single bufferred, so we should really be updating them during vblank, but we still don't have a mechanism for that, so just toss in another FIXME. v2: Rebase v3: s/bri/brightness/ s/con/contrast/ (Shashank) v4: Clarify the constants and math (Shashank) Cc: Harry Wentland Cc: Daniel Vetter Cc: Daniel Stone Cc: Russell King - ARM Linux Cc: Ilia Mirkin Cc: Hans Verkuil Cc: Shashank Sharma Cc: Uma Shankar Cc: Jyri Sarha Cc: "Tang, Jun" Reported-by: "Tang, Jun" Cc: stable@vger.kernel.org Fixes: 7f1f3851feb0 ("drm/i915: sprite support for ValleyView v4") Reviewed-by: Shashank Sharma Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180214192327.3250-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_reg.h | 10 +++++ drivers/gpu/drm/i915/intel_sprite.c | 81 ++++++++++++++++++++++++++++--------- 2 files changed, 73 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e9c79b560823..aaed94f074f5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6278,6 +6278,12 @@ enum { #define _SPATILEOFF (VLV_DISPLAY_BASE + 0x721a4) #define _SPACONSTALPHA (VLV_DISPLAY_BASE + 0x721a8) #define SP_CONST_ALPHA_ENABLE (1<<31) +#define _SPACLRC0 (VLV_DISPLAY_BASE + 0x721d0) +#define SP_CONTRAST(x) ((x) << 18) /* u3.6 */ +#define SP_BRIGHTNESS(x) ((x) & 0xff) /* s8 */ +#define _SPACLRC1 (VLV_DISPLAY_BASE + 0x721d4) +#define SP_SH_SIN(x) (((x) & 0x7ff) << 16) /* s4.7 */ +#define SP_SH_COS(x) (x) /* u3.7 */ #define _SPAGAMC (VLV_DISPLAY_BASE + 0x721f4) #define _SPBCNTR (VLV_DISPLAY_BASE + 0x72280) @@ -6291,6 +6297,8 @@ enum { #define _SPBKEYMAXVAL (VLV_DISPLAY_BASE + 0x722a0) #define _SPBTILEOFF (VLV_DISPLAY_BASE + 0x722a4) #define _SPBCONSTALPHA (VLV_DISPLAY_BASE + 0x722a8) +#define _SPBCLRC0 (VLV_DISPLAY_BASE + 0x722d0) +#define _SPBCLRC1 (VLV_DISPLAY_BASE + 0x722d4) #define _SPBGAMC (VLV_DISPLAY_BASE + 0x722f4) #define _MMIO_VLV_SPR(pipe, plane_id, reg_a, reg_b) \ @@ -6307,6 +6315,8 @@ enum { #define SPKEYMAXVAL(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPAKEYMAXVAL, _SPBKEYMAXVAL) #define SPTILEOFF(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPATILEOFF, _SPBTILEOFF) #define SPCONSTALPHA(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPACONSTALPHA, _SPBCONSTALPHA) +#define SPCLRC0(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPACLRC0, _SPBCLRC0) +#define SPCLRC1(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPACLRC1, _SPBCLRC1) #define SPGAMC(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPAGAMC, _SPBGAMC) /* diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 3be22c0fcfb5..9b7171f20549 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -346,44 +346,87 @@ skl_plane_get_hw_state(struct intel_plane *plane) } static void -chv_update_csc(struct intel_plane *plane, uint32_t format) +chv_update_csc(const struct intel_plane_state *plane_state) { + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->base.fb; enum plane_id plane_id = plane->id; /* Seems RGB data bypasses the CSC always */ - if (!format_is_yuv(format)) + if (!format_is_yuv(fb->format->format)) return; /* - * BT.601 limited range YCbCr -> full range RGB + * BT.601 full range YCbCr -> full range RGB * - * |r| | 6537 4769 0| |cr | - * |g| = |-3330 4769 -1605| x |y-64| - * |b| | 0 4769 8263| |cb | + * |r| | 5743 4096 0| |cr| + * |g| = |-2925 4096 -1410| x |y | + * |b| | 0 4096 7258| |cb| * - * Cb and Cr apparently come in as signed already, so no - * need for any offset. For Y we need to remove the offset. + * Cb and Cr apparently come in as signed already, + * and we get full range data in on account of CLRC0/1 */ - I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(-64)); + I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); I915_WRITE_FW(SPCSCCBOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); I915_WRITE_FW(SPCSCCROFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); - I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(4769) | SPCSC_C0(6537)); - I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(-3330) | SPCSC_C0(0)); - I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(-1605) | SPCSC_C0(4769)); - I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(4769) | SPCSC_C0(0)); - I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(8263)); + I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(4096) | SPCSC_C0(5743)); + I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(-2925) | SPCSC_C0(0)); + I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(-1410) | SPCSC_C0(4096)); + I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(4096) | SPCSC_C0(0)); + I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(7258)); - I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(940) | SPCSC_IMIN(64)); - I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); - I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); + I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(1023) | SPCSC_IMIN(0)); + I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512)); + I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512)); I915_WRITE_FW(SPCSCYGOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); I915_WRITE_FW(SPCSCCBOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); I915_WRITE_FW(SPCSCCROCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); } +#define SIN_0 0 +#define COS_0 1 + +static void +vlv_update_clrc(const struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->base.fb; + enum pipe pipe = plane->pipe; + enum plane_id plane_id = plane->id; + int contrast, brightness, sh_scale, sh_sin, sh_cos; + + if (format_is_yuv(fb->format->format)) { + /* + * Expand limited range to full range: + * Contrast is applied first and is used to expand Y range. + * Brightness is applied second and is used to remove the + * offset from Y. Saturation/hue is used to expand CbCr range. + */ + contrast = DIV_ROUND_CLOSEST(255 << 6, 235 - 16); + brightness = -DIV_ROUND_CLOSEST(16 * 255, 235 - 16); + sh_scale = DIV_ROUND_CLOSEST(128 << 7, 240 - 128); + sh_sin = SIN_0 * sh_scale; + sh_cos = COS_0 * sh_scale; + } else { + /* Pass-through everything. */ + contrast = 1 << 6; + brightness = 0; + sh_scale = 1 << 7; + sh_sin = SIN_0 * sh_scale; + sh_cos = COS_0 * sh_scale; + } + + /* FIXME these register are single buffered :( */ + I915_WRITE_FW(SPCLRC0(pipe, plane_id), + SP_CONTRAST(contrast) | SP_BRIGHTNESS(brightness)); + I915_WRITE_FW(SPCLRC1(pipe, plane_id), + SP_SH_SIN(sh_sin) | SP_SH_COS(sh_cos)); +} + static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { @@ -477,8 +520,10 @@ vlv_update_plane(struct intel_plane *plane, spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + vlv_update_clrc(plane_state); + if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) - chv_update_csc(plane, fb->format->format); + chv_update_csc(plane_state); if (key->flags) { I915_WRITE_FW(SPKEYMINVAL(pipe, plane_id), key->min_value); -- cgit v1.2.3 From 38f24f21ae9bb0f2b7ebb42e828f7f8fe5190d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 14 Feb 2018 21:23:24 +0200 Subject: drm/i915: Fix plane YCbCr->RGB conversion for GLK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On GLK the plane CSC controls moved into the COLOR_CTL register. Update the code to progam the YCbCr->RGB CSC mode correctly when faced with an YCbCr framebuffer. The spec is rather confusing as it calls the mode "YUV601 to RGB709". I'm going to assume that just means it's going to use the YCbCr->RGB matrix as specified in BT.601 and doesn't actually change the gamut. Cc: Harry Wentland Cc: Daniel Vetter Cc: Daniel Stone Cc: Russell King - ARM Linux Cc: Ilia Mirkin Cc: Hans Verkuil Cc: Uma Shankar Cc: Shashank Sharma Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180214192327.3250-6-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/i915_reg.h | 5 +++++ drivers/gpu/drm/i915/intel_display.c | 3 +++ drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_sprite.c | 10 +++++----- 4 files changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index aaed94f074f5..98b5c41cc15f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6436,6 +6436,11 @@ enum { #define _PLANE_COLOR_CTL_3_A 0x703CC /* GLK+ */ #define PLANE_COLOR_PIPE_GAMMA_ENABLE (1 << 30) #define PLANE_COLOR_PIPE_CSC_ENABLE (1 << 23) +#define PLANE_COLOR_CSC_MODE_BYPASS (0 << 17) +#define PLANE_COLOR_CSC_MODE_YUV601_TO_RGB709 (1 << 17) +#define PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709 (2 << 17) +#define PLANE_COLOR_CSC_MODE_YUV2020_TO_RGB2020 (3 << 17) +#define PLANE_COLOR_CSC_MODE_RGB709_TO_RGB2020 (4 << 17) #define PLANE_COLOR_PLANE_GAMMA_DISABLE (1 << 13) #define PLANE_COLOR_ALPHA_MASK (0x3 << 4) #define PLANE_COLOR_ALPHA_DISABLE (0 << 4) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3d2929c44804..ce13391cff63 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3565,6 +3565,9 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE; plane_color_ctl |= glk_plane_color_ctl_alpha(fb->format->format); + if (intel_format_is_yuv(fb->format->format)) + plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV601_TO_RGB709; + return plane_color_ctl; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 468ec1e90e16..2bc4e17baf4f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1589,6 +1589,7 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); +u32 glk_color_ctl(const struct intel_plane_state *plane_state); u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane, unsigned int rotation); int skl_check_plane_surface(const struct intel_crtc_state *crtc_state, @@ -2014,6 +2015,7 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, /* intel_sprite.c */ +bool intel_format_is_yuv(u32 format); int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, int usecs); struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 9b7171f20549..3025c609d688 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -41,8 +41,7 @@ #include #include "i915_drv.h" -static bool -format_is_yuv(uint32_t format) +bool intel_format_is_yuv(u32 format) { switch (format) { case DRM_FORMAT_YUYV: @@ -266,6 +265,7 @@ skl_update_plane(struct intel_plane *plane, if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) I915_WRITE_FW(PLANE_COLOR_CTL(pipe, plane_id), plane_state->color_ctl); + if (key->flags) { I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value); I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), key->max_value); @@ -354,7 +354,7 @@ chv_update_csc(const struct intel_plane_state *plane_state) enum plane_id plane_id = plane->id; /* Seems RGB data bypasses the CSC always */ - if (!format_is_yuv(fb->format->format)) + if (!intel_format_is_yuv(fb->format->format)) return; /* @@ -399,7 +399,7 @@ vlv_update_clrc(const struct intel_plane_state *plane_state) enum plane_id plane_id = plane->id; int contrast, brightness, sh_scale, sh_sin, sh_cos; - if (format_is_yuv(fb->format->format)) { + if (intel_format_is_yuv(fb->format->format)) { /* * Expand limited range to full range: * Contrast is applied first and is used to expand Y range. @@ -1024,7 +1024,7 @@ intel_check_sprite_plane(struct intel_plane *plane, src_y = src->y1 >> 16; src_h = drm_rect_height(src) >> 16; - if (format_is_yuv(fb->format->format)) { + if (intel_format_is_yuv(fb->format->format)) { src_x &= ~1; src_w &= ~1; -- cgit v1.2.3 From b0f5c0badc5b54cc6308f21a65f6ebf69087d557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 14 Feb 2018 21:23:25 +0200 Subject: drm/i915: Add support for the YCbCr COLOR_ENCODING property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the COLOR_ENCODING plane property which selects the matrix coefficients used for the YCbCr->RGB conversion. Our hardware can generally handle BT.601 and BT.709. CHV pipe B sprites have a fully programmable matrix, so in theory we could handle anything, but it doesn't seem all that useful to expose anything beyond BT.601 and BT.709 at this time. GLK can supposedly do BT.2020, but let's leave enabling that for the future as well. v2: Rename bit defines to match the spec more closely (Shashank) Cc: Harry Wentland Cc: Daniel Vetter Cc: Daniel Stone Cc: Russell King - ARM Linux Cc: Ilia Mirkin Cc: Hans Verkuil Cc: Uma Shankar Cc: Shashank Sharma Cc: Jyri Sarha Reviewed-by: Shashank Sharma Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180214192327.3250-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_reg.h | 5 ++- drivers/gpu/drm/i915/intel_display.c | 19 +++++++++-- drivers/gpu/drm/i915/intel_sprite.c | 61 +++++++++++++++++++++++++++--------- 3 files changed, 67 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 98b5c41cc15f..b54c837689f6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6113,6 +6113,7 @@ enum { #define DVS_PIPE_CSC_ENABLE (1<<24) #define DVS_SOURCE_KEY (1<<22) #define DVS_RGB_ORDER_XBGR (1<<20) +#define DVS_YUV_FORMAT_BT709 (1<<18) #define DVS_YUV_BYTE_ORDER_MASK (3<<16) #define DVS_YUV_ORDER_YUYV (0<<16) #define DVS_YUV_ORDER_UYVY (1<<16) @@ -6183,7 +6184,7 @@ enum { #define SPRITE_SOURCE_KEY (1<<22) #define SPRITE_RGB_ORDER_RGBX (1<<20) /* only for 888 and 161616 */ #define SPRITE_YUV_TO_RGB_CSC_DISABLE (1<<19) -#define SPRITE_YUV_CSC_FORMAT_BT709 (1<<18) /* 0 is BT601 */ +#define SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709 (1<<18) /* 0 is BT601 */ #define SPRITE_YUV_BYTE_ORDER_MASK (3<<16) #define SPRITE_YUV_ORDER_YUYV (0<<16) #define SPRITE_YUV_ORDER_UYVY (1<<16) @@ -6259,6 +6260,7 @@ enum { #define SP_FORMAT_RGBA8888 (0xf<<26) #define SP_ALPHA_PREMULTIPLY (1<<23) /* CHV pipe B */ #define SP_SOURCE_KEY (1<<22) +#define SP_YUV_FORMAT_BT709 (1<<18) #define SP_YUV_BYTE_ORDER_MASK (3<<16) #define SP_YUV_ORDER_YUYV (0<<16) #define SP_YUV_ORDER_UYVY (1<<16) @@ -6383,6 +6385,7 @@ enum { #define PLANE_CTL_KEY_ENABLE_DESTINATION ( 2 << 21) #define PLANE_CTL_ORDER_BGRX (0 << 20) #define PLANE_CTL_ORDER_RGBX (1 << 20) +#define PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709 (1 << 18) #define PLANE_CTL_YUV422_ORDER_MASK (0x3 << 16) #define PLANE_CTL_YUV422_YUYV ( 0 << 16) #define PLANE_CTL_YUV422_UYVY ( 1 << 16) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ce13391cff63..8149079d01f1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3536,6 +3536,9 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, PLANE_CTL_PIPE_GAMMA_ENABLE | PLANE_CTL_PIPE_CSC_ENABLE | PLANE_CTL_PLANE_GAMMA_DISABLE; + + if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) + plane_ctl |= PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709; } plane_ctl |= skl_plane_ctl_format(fb->format->format); @@ -3565,8 +3568,12 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE; plane_color_ctl |= glk_plane_color_ctl_alpha(fb->format->format); - if (intel_format_is_yuv(fb->format->format)) - plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV601_TO_RGB709; + if (intel_format_is_yuv(fb->format->format)) { + if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) + plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; + else + plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV601_TO_RGB709; + } return plane_color_ctl; } @@ -13289,6 +13296,14 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) DRM_MODE_ROTATE_0, supported_rotations); + if (INTEL_GEN(dev_priv) >= 9) + drm_plane_create_color_properties(&primary->base, + BIT(DRM_COLOR_YCBCR_BT601) | + BIT(DRM_COLOR_YCBCR_BT709), + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), + DRM_COLOR_YCBCR_BT601, + DRM_COLOR_YCBCR_LIMITED_RANGE); + drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs); return primary; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 3025c609d688..36798ca1b8bb 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -352,30 +352,45 @@ chv_update_csc(const struct intel_plane_state *plane_state) struct drm_i915_private *dev_priv = to_i915(plane->base.dev); const struct drm_framebuffer *fb = plane_state->base.fb; enum plane_id plane_id = plane->id; + /* + * |r| | c0 c1 c2 | |cr| + * |g| = | c3 c4 c5 | x |y | + * |b| | c6 c7 c8 | |cb| + * + * Coefficients are s3.12. + * + * Cb and Cr apparently come in as signed already, and + * we always get full range data in on account of CLRC0/1. + */ + static const s16 csc_matrix[][9] = { + /* BT.601 full range YCbCr -> full range RGB */ + [DRM_COLOR_YCBCR_BT601] = { + 5743, 4096, 0, + -2925, 4096, -1410, + 0, 4096, 7258, + }, + /* BT.709 full range YCbCr -> full range RGB */ + [DRM_COLOR_YCBCR_BT709] = { + 6450, 4096, 0, + -1917, 4096, -767, + 0, 4096, 7601, + }, + }; + const s16 *csc = csc_matrix[plane_state->base.color_encoding]; /* Seems RGB data bypasses the CSC always */ if (!intel_format_is_yuv(fb->format->format)) return; - /* - * BT.601 full range YCbCr -> full range RGB - * - * |r| | 5743 4096 0| |cr| - * |g| = |-2925 4096 -1410| x |y | - * |b| | 0 4096 7258| |cb| - * - * Cb and Cr apparently come in as signed already, - * and we get full range data in on account of CLRC0/1 - */ I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); I915_WRITE_FW(SPCSCCBOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); I915_WRITE_FW(SPCSCCROFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); - I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(4096) | SPCSC_C0(5743)); - I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(-2925) | SPCSC_C0(0)); - I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(-1410) | SPCSC_C0(4096)); - I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(4096) | SPCSC_C0(0)); - I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(7258)); + I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(csc[1]) | SPCSC_C0(csc[0])); + I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(csc[3]) | SPCSC_C0(csc[2])); + I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(csc[5]) | SPCSC_C0(csc[4])); + I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(csc[7]) | SPCSC_C0(csc[6])); + I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(csc[8])); I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(1023) | SPCSC_IMIN(0)); I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512)); @@ -476,6 +491,9 @@ static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state, return 0; } + if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) + sprctl |= SP_YUV_FORMAT_BT709; + if (fb->modifier == I915_FORMAT_MOD_X_TILED) sprctl |= SP_TILED; @@ -629,6 +647,9 @@ static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state, return 0; } + if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) + sprctl |= SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709; + if (fb->modifier == I915_FORMAT_MOD_X_TILED) sprctl |= SPRITE_TILED; @@ -785,6 +806,9 @@ static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state, return 0; } + if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) + dvscntr |= DVS_YUV_FORMAT_BT709; + if (fb->modifier == I915_FORMAT_MOD_X_TILED) dvscntr |= DVS_TILED; @@ -1501,6 +1525,13 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, DRM_MODE_ROTATE_0, supported_rotations); + drm_plane_create_color_properties(&intel_plane->base, + BIT(DRM_COLOR_YCBCR_BT601) | + BIT(DRM_COLOR_YCBCR_BT709), + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), + DRM_COLOR_YCBCR_BT601, + DRM_COLOR_YCBCR_LIMITED_RANGE); + drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); return intel_plane; -- cgit v1.2.3 From 23b280890a140b0cf1e8f61c252936c2fb77f718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 14 Feb 2018 21:23:26 +0200 Subject: drm/i915: Change the COLOR_ENCODING prop default value to BT.709 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bring us forward from the stone age and switch our default YCbCr->RGB conversion matrix to BT.709 from BT.601. I would expect most matrial to be BT.709 these days. Cc: Harry Wentland Cc: Daniel Vetter Cc: Daniel Stone Cc: Russell King - ARM Linux Cc: Ilia Mirkin Cc: Hans Verkuil Cc: Uma Shankar Cc: Shashank Sharma Cc: Jyri Sarha Acked-by: Shashank Sharma Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180214192327.3250-8-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_sprite.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8149079d01f1..2584b9fb2473 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13301,7 +13301,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709), BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), - DRM_COLOR_YCBCR_BT601, + DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE); drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 36798ca1b8bb..84640f92ac2e 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1529,7 +1529,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709), BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), - DRM_COLOR_YCBCR_BT601, + DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE); drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); -- cgit v1.2.3 From c8624ede3ed3b9f46364f5239c402393ec853e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 14 Feb 2018 21:23:27 +0200 Subject: drm/i915: Add support for the YCbCr COLOR_RANGE property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the COLOR_RANGE property on planes. This property selects whether the input YCbCr data is to treated as limited range or full range. On most platforms this is a matter of setting the "YUV range correction disable" bit, and on VLV/CHV we'll just have to program the color correction logic to pass the data through unmodified. v2: Rebase Cc: Harry Wentland Cc: Daniel Vetter Cc: Daniel Stone Cc: Russell King - ARM Linux Cc: Ilia Mirkin Cc: Hans Verkuil Cc: Uma Shankar Cc: Shashank Sharma Cc: Jyri Sarha Reviewed-by: Shashank Sharma Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180214192327.3250-9-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_display.c | 9 ++++++++- drivers/gpu/drm/i915/intel_sprite.c | 12 ++++++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b54c837689f6..b576b6ba32a4 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6105,6 +6105,7 @@ enum { #define _DVSACNTR 0x72180 #define DVS_ENABLE (1<<31) #define DVS_GAMMA_ENABLE (1<<30) +#define DVS_YUV_RANGE_CORRECTION_DISABLE (1<<27) #define DVS_PIXFORMAT_MASK (3<<25) #define DVS_FORMAT_YUV422 (0<<25) #define DVS_FORMAT_RGBX101010 (1<<25) @@ -6173,6 +6174,7 @@ enum { #define _SPRA_CTL 0x70280 #define SPRITE_ENABLE (1<<31) #define SPRITE_GAMMA_ENABLE (1<<30) +#define SPRITE_YUV_RANGE_CORRECTION_DISABLE (1<<28) #define SPRITE_PIXFORMAT_MASK (7<<25) #define SPRITE_FORMAT_YUV422 (0<<25) #define SPRITE_FORMAT_RGBX101010 (1<<25) @@ -6364,6 +6366,7 @@ enum { #define _PLANE_CTL_3_A 0x70380 #define PLANE_CTL_ENABLE (1 << 31) #define PLANE_CTL_PIPE_GAMMA_ENABLE (1 << 30) /* Pre-GLK */ +#define PLANE_CTL_YUV_RANGE_CORRECTION_DISABLE (1 << 28) /* * ICL+ uses the same PLANE_CTL_FORMAT bits, but the field definition * expanded to include bit 23 as well. However, the shift-24 based values @@ -6438,6 +6441,7 @@ enum { #define _PLANE_COLOR_CTL_2_A 0x702CC /* GLK+ */ #define _PLANE_COLOR_CTL_3_A 0x703CC /* GLK+ */ #define PLANE_COLOR_PIPE_GAMMA_ENABLE (1 << 30) +#define PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE (1 << 28) #define PLANE_COLOR_PIPE_CSC_ENABLE (1 << 23) #define PLANE_COLOR_CSC_MODE_BYPASS (0 << 17) #define PLANE_COLOR_CSC_MODE_YUV601_TO_RGB709 (1 << 17) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2584b9fb2473..2dceb4cc5f30 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3539,6 +3539,9 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) plane_ctl |= PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709; + + if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE) + plane_ctl |= PLANE_CTL_YUV_RANGE_CORRECTION_DISABLE; } plane_ctl |= skl_plane_ctl_format(fb->format->format); @@ -3573,6 +3576,9 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; else plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV601_TO_RGB709; + + if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE) + plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; } return plane_color_ctl; @@ -13300,7 +13306,8 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) drm_plane_create_color_properties(&primary->base, BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709), - BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | + BIT(DRM_COLOR_YCBCR_FULL_RANGE), DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 84640f92ac2e..3714836879b2 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -414,7 +414,8 @@ vlv_update_clrc(const struct intel_plane_state *plane_state) enum plane_id plane_id = plane->id; int contrast, brightness, sh_scale, sh_sin, sh_cos; - if (intel_format_is_yuv(fb->format->format)) { + if (intel_format_is_yuv(fb->format->format) && + plane_state->base.color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) { /* * Expand limited range to full range: * Contrast is applied first and is used to expand Y range. @@ -650,6 +651,9 @@ static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state, if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) sprctl |= SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709; + if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE) + sprctl |= SPRITE_YUV_RANGE_CORRECTION_DISABLE; + if (fb->modifier == I915_FORMAT_MOD_X_TILED) sprctl |= SPRITE_TILED; @@ -809,6 +813,9 @@ static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state, if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) dvscntr |= DVS_YUV_FORMAT_BT709; + if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE) + dvscntr |= DVS_YUV_RANGE_CORRECTION_DISABLE; + if (fb->modifier == I915_FORMAT_MOD_X_TILED) dvscntr |= DVS_TILED; @@ -1528,7 +1535,8 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, drm_plane_create_color_properties(&intel_plane->base, BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709), - BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | + BIT(DRM_COLOR_YCBCR_FULL_RANGE), DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE); -- cgit v1.2.3 From c39bbb903ce337a3f6a7fe0ac8d30e0876699fc2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 1 Mar 2018 22:02:30 +0200 Subject: drm: omapdrm: displays: panel-dsi-cm: Fix field access before set The driver accesses the ddata->in field before it gets set in the dsicm_connect() function. Use the local in pointer variable instead. Fixes: 7877632b4cd0 ("drm: omapdrm: displays: Get panel source at connect time") Signed-off-by: Laurent Pinchart Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index f960e55d64ea..428de90fced1 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -778,13 +778,13 @@ static int dsicm_connect(struct omap_dss_device *dssdev) goto err_connect; } - r = in->ops.dsi->request_vc(ddata->in, &ddata->channel); + r = in->ops.dsi->request_vc(in, &ddata->channel); if (r) { dev_err(dev, "failed to get virtual channel\n"); goto err_req_vc; } - r = in->ops.dsi->set_vc_id(ddata->in, ddata->channel, TCH); + r = in->ops.dsi->set_vc_id(in, ddata->channel, TCH); if (r) { dev_err(dev, "failed to set VC_ID\n"); goto err_vc_id; @@ -794,7 +794,7 @@ static int dsicm_connect(struct omap_dss_device *dssdev) return 0; err_vc_id: - in->ops.dsi->release_vc(ddata->in, ddata->channel); + in->ops.dsi->release_vc(in, ddata->channel); err_req_vc: in->ops.dsi->disconnect(in, dssdev); err_connect: -- cgit v1.2.3 From 94db151dc89262bfa82922c44e8320cea2334667 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 4 Feb 2018 10:34:02 -0800 Subject: vfio: disable filesystem-dax page pinning Filesystem-DAX is incompatible with 'longterm' page pinning. Without page cache indirection a DAX mapping maps filesystem blocks directly. This means that the filesystem must not modify a file's block map while any page in a mapping is pinned. In order to prevent the situation of userspace holding of filesystem operations indefinitely, disallow 'longterm' Filesystem-DAX mappings. RDMA has the same conflict and the plan there is to add a 'with lease' mechanism to allow the kernel to notify userspace that the mapping is being torn down for block-map maintenance. Perhaps something similar can be put in place for vfio. Note that xfs and ext4 still report: "DAX enabled. Warning: EXPERIMENTAL, use at your own risk" ...at mount time, and resolving the dax-dma-vs-truncate problem is one of the last hurdles to remove that designation. Acked-by: Alex Williamson Cc: Michal Hocko Cc: kvm@vger.kernel.org Cc: Reported-by: Haozhong Zhang Tested-by: Haozhong Zhang Fixes: d475c6346a38 ("dax,ext2: replace XIP read and write with DAX I/O") Reviewed-by: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/vfio/vfio_iommu_type1.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index e30e29ae4819..45657e2b1ff7 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -338,11 +338,12 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, { struct page *page[1]; struct vm_area_struct *vma; + struct vm_area_struct *vmas[1]; int ret; if (mm == current->mm) { - ret = get_user_pages_fast(vaddr, 1, !!(prot & IOMMU_WRITE), - page); + ret = get_user_pages_longterm(vaddr, 1, !!(prot & IOMMU_WRITE), + page, vmas); } else { unsigned int flags = 0; @@ -351,7 +352,18 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, down_read(&mm->mmap_sem); ret = get_user_pages_remote(NULL, mm, vaddr, 1, flags, page, - NULL, NULL); + vmas, NULL); + /* + * The lifetime of a vaddr_get_pfn() page pin is + * userspace-controlled. In the fs-dax case this could + * lead to indefinite stalls in filesystem operations. + * Disallow attempts to pin fs-dax pages via this + * interface. + */ + if (ret > 0 && vma_is_fsdax(vmas[0])) { + ret = -EOPNOTSUPP; + put_page(page[0]); + } up_read(&mm->mmap_sem); } -- cgit v1.2.3 From 5fdf8e5ba5666fe153bd61f851a40078a6347822 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 2 Mar 2018 19:31:40 -0800 Subject: libnvdimm: re-enable deep flush for pmem devices via fsync() Re-enable deep flush so that users always have a way to be sure that a write makes it all the way out to media. Writes from the PMEM driver always arrive at the NVDIMM since movnt is used to bypass the cache, and the driver relies on the ADR (Asynchronous DRAM Refresh) mechanism to flush write buffers on power failure. The Deep Flush mechanism is there to explicitly write buffers to protect against (rare) ADR failure. This change prevents a regression in deep flush behavior so that applications can continue to depend on fsync() as a mechanism to trigger deep flush in the filesystem-DAX case. Fixes: 06e8ccdab15f4 ("acpi: nfit: Add support for detect platform CPU cache...") Reviewed-by: Jeff Moyer Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/nvdimm/pmem.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 10041ac4032c..06f8dcc52ca6 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -335,8 +335,7 @@ static int pmem_attach_disk(struct device *dev, dev_warn(dev, "unable to guarantee persistence of writes\n"); fua = 0; } - wbc = nvdimm_has_cache(nd_region) && - !test_bit(ND_REGION_PERSIST_CACHE, &nd_region->flags); + wbc = nvdimm_has_cache(nd_region); if (!devm_request_mem_region(dev, res->start, resource_size(res), dev_name(&ndns->dev))) { -- cgit v1.2.3 From 7bd3e7b743956afbec30fb525bc3c5e22e3d475c Mon Sep 17 00:00:00 2001 From: Igor Pylypiv Date: Wed, 28 Feb 2018 00:59:12 -0800 Subject: watchdog: f71808e_wdt: Fix magic close handling Watchdog close is "expected" when any byte is 'V' not just the last one. Writing "V" to the device fails because the last byte is the end of string. $ echo V > /dev/watchdog f71808e_wdt: Unexpected close, not stopping watchdog! Signed-off-by: Igor Pylypiv Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/f71808e_wdt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index e0678c14480f..3a33c5344bd5 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -566,7 +566,8 @@ static ssize_t watchdog_write(struct file *file, const char __user *buf, char c; if (get_user(c, buf + i)) return -EFAULT; - expect_close = (c == 'V'); + if (c == 'V') + expect_close = true; } /* Properly order writes across fork()ed processes */ -- cgit v1.2.3 From 93ac3deb7c220cbcec032a967220a1f109d58431 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Wed, 28 Feb 2018 02:52:20 -0800 Subject: watchdog: sbsa: use 32-bit read for WCV According to SBSA spec v3.1 section 5.3: All registers are 32 bits in size and should be accessed using 32-bit reads and writes. If an access size other than 32 bits is used then the results are IMPLEMENTATION DEFINED. [...] The Generic Watchdog is little-endian The current code uses readq to read the watchdog compare register which does a 64-bit access. This fails on ThunderX2 which does not implement 64-bit access to this register. Fix this by using lo_hi_readq() that does two 32-bit reads. Signed-off-by: Jayachandran C Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/sbsa_gwdt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c index 316c2eb122d2..e8bd9887c566 100644 --- a/drivers/watchdog/sbsa_gwdt.c +++ b/drivers/watchdog/sbsa_gwdt.c @@ -50,6 +50,7 @@ */ #include +#include #include #include #include @@ -159,7 +160,7 @@ static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd) !(readl(gwdt->control_base + SBSA_GWDT_WCS) & SBSA_GWDT_WCS_WS0)) timeleft += readl(gwdt->control_base + SBSA_GWDT_WOR); - timeleft += readq(gwdt->control_base + SBSA_GWDT_WCV) - + timeleft += lo_hi_readq(gwdt->control_base + SBSA_GWDT_WCV) - arch_counter_get_cntvct(); do_div(timeleft, gwdt->clk); -- cgit v1.2.3 From 2b3d89b402b085b08498e896c65267a145bed486 Mon Sep 17 00:00:00 2001 From: Jerry Hoemann Date: Sun, 25 Feb 2018 20:22:20 -0700 Subject: watchdog: hpwdt: Remove legacy NMI sourcing. Gen8 and prior Proliant systems supported the "CRU" interface to firmware. This interfaces allows linux to "call back" into firmware to source the cause of an NMI. This feature isn't fully utilized as the actual source of the NMI isn't printed, the driver only indicates that the source couldn't be determined when the call fails. With the advent of Gen9, iCRU replaces the CRU. The call back feature is no longer available in firmware. To be compatible and not attempt to call back into firmware on system not supporting CRU, the SMBIOS table is consulted to determine if it is safe to make the call back or not. This results in about half of the driver code being devoted to either making CRU calls or determing if it is safe to make CRU calls. As noted, the driver isn't really using the results of the CRU calls. Furthermore, as a consequence of the Spectre security issue, the BIOS/EFI calls are being wrapped into Spectre-disabling section. Removing the call back in hpwdt_pretimeout assists in this effort. As the CRU sourcing of the NMI isn't required for handling the NMI and there are security concerns with making the call back, remove the legacy (pre Gen9) NMI sourcing and the DMI code to determine if the system had the CRU interface. Signed-off-by: Jerry Hoemann Acked-by: Ingo Molnar Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 501 +---------------------------------------------- 1 file changed, 9 insertions(+), 492 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index f1f00dfc0e68..b0a158073abd 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -28,16 +28,7 @@ #include #include #include -#ifdef CONFIG_HPWDT_NMI_DECODING -#include -#include -#include -#include -#include -#include -#endif /* CONFIG_HPWDT_NMI_DECODING */ #include -#include #define HPWDT_VERSION "1.4.0" #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) @@ -48,6 +39,9 @@ static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */ static unsigned int reload; /* the computed soft_margin */ static bool nowayout = WATCHDOG_NOWAYOUT; +#ifdef CONFIG_HPWDT_NMI_DECODING +static unsigned int allow_kdump = 1; +#endif static char expect_release; static unsigned long hpwdt_is_open; @@ -63,373 +57,6 @@ static const struct pci_device_id hpwdt_devices[] = { }; MODULE_DEVICE_TABLE(pci, hpwdt_devices); -#ifdef CONFIG_HPWDT_NMI_DECODING -#define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ -#define CRU_BIOS_SIGNATURE_VALUE 0x55524324 -#define PCI_BIOS32_PARAGRAPH_LEN 16 -#define PCI_ROM_BASE1 0x000F0000 -#define ROM_SIZE 0x10000 - -struct bios32_service_dir { - u32 signature; - u32 entry_point; - u8 revision; - u8 length; - u8 checksum; - u8 reserved[5]; -}; - -/* type 212 */ -struct smbios_cru64_info { - u8 type; - u8 byte_length; - u16 handle; - u32 signature; - u64 physical_address; - u32 double_length; - u32 double_offset; -}; -#define SMBIOS_CRU64_INFORMATION 212 - -/* type 219 */ -struct smbios_proliant_info { - u8 type; - u8 byte_length; - u16 handle; - u32 power_features; - u32 omega_features; - u32 reserved; - u32 misc_features; -}; -#define SMBIOS_ICRU_INFORMATION 219 - - -struct cmn_registers { - union { - struct { - u8 ral; - u8 rah; - u16 rea2; - }; - u32 reax; - } u1; - union { - struct { - u8 rbl; - u8 rbh; - u8 reb2l; - u8 reb2h; - }; - u32 rebx; - } u2; - union { - struct { - u8 rcl; - u8 rch; - u16 rec2; - }; - u32 recx; - } u3; - union { - struct { - u8 rdl; - u8 rdh; - u16 red2; - }; - u32 redx; - } u4; - - u32 resi; - u32 redi; - u16 rds; - u16 res; - u32 reflags; -} __attribute__((packed)); - -static unsigned int hpwdt_nmi_decoding; -static unsigned int allow_kdump = 1; -static unsigned int is_icru; -static unsigned int is_uefi; -static DEFINE_SPINLOCK(rom_lock); -static void *cru_rom_addr; -static struct cmn_registers cmn_regs; - -extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs, - unsigned long *pRomEntry); - -#ifdef CONFIG_X86_32 -/* --32 Bit Bios------------------------------------------------------------ */ - -#define HPWDT_ARCH 32 - -asm(".text \n\t" - ".align 4 \n\t" - ".globl asminline_call \n" - "asminline_call: \n\t" - "pushl %ebp \n\t" - "movl %esp, %ebp \n\t" - "pusha \n\t" - "pushf \n\t" - "push %es \n\t" - "push %ds \n\t" - "pop %es \n\t" - "movl 8(%ebp),%eax \n\t" - "movl 4(%eax),%ebx \n\t" - "movl 8(%eax),%ecx \n\t" - "movl 12(%eax),%edx \n\t" - "movl 16(%eax),%esi \n\t" - "movl 20(%eax),%edi \n\t" - "movl (%eax),%eax \n\t" - "push %cs \n\t" - "call *12(%ebp) \n\t" - "pushf \n\t" - "pushl %eax \n\t" - "movl 8(%ebp),%eax \n\t" - "movl %ebx,4(%eax) \n\t" - "movl %ecx,8(%eax) \n\t" - "movl %edx,12(%eax) \n\t" - "movl %esi,16(%eax) \n\t" - "movl %edi,20(%eax) \n\t" - "movw %ds,24(%eax) \n\t" - "movw %es,26(%eax) \n\t" - "popl %ebx \n\t" - "movl %ebx,(%eax) \n\t" - "popl %ebx \n\t" - "movl %ebx,28(%eax) \n\t" - "pop %es \n\t" - "popf \n\t" - "popa \n\t" - "leave \n\t" - "ret \n\t" - ".previous"); - - -/* - * cru_detect - * - * Routine Description: - * This function uses the 32-bit BIOS Service Directory record to - * search for a $CRU record. - * - * Return Value: - * 0 : SUCCESS - * <0 : FAILURE - */ -static int cru_detect(unsigned long map_entry, - unsigned long map_offset) -{ - void *bios32_map; - unsigned long *bios32_entrypoint; - unsigned long cru_physical_address; - unsigned long cru_length; - unsigned long physical_bios_base = 0; - unsigned long physical_bios_offset = 0; - int retval = -ENODEV; - - bios32_map = ioremap(map_entry, (2 * PAGE_SIZE)); - - if (bios32_map == NULL) - return -ENODEV; - - bios32_entrypoint = bios32_map + map_offset; - - cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE; - - set_memory_x((unsigned long)bios32_map, 2); - asminline_call(&cmn_regs, bios32_entrypoint); - - if (cmn_regs.u1.ral != 0) { - pr_warn("Call succeeded but with an error: 0x%x\n", - cmn_regs.u1.ral); - } else { - physical_bios_base = cmn_regs.u2.rebx; - physical_bios_offset = cmn_regs.u4.redx; - cru_length = cmn_regs.u3.recx; - cru_physical_address = - physical_bios_base + physical_bios_offset; - - /* If the values look OK, then map it in. */ - if ((physical_bios_base + physical_bios_offset)) { - cru_rom_addr = - ioremap(cru_physical_address, cru_length); - if (cru_rom_addr) { - set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, - (cru_length + PAGE_SIZE - 1) >> PAGE_SHIFT); - retval = 0; - } - } - - pr_debug("CRU Base Address: 0x%lx\n", physical_bios_base); - pr_debug("CRU Offset Address: 0x%lx\n", physical_bios_offset); - pr_debug("CRU Length: 0x%lx\n", cru_length); - pr_debug("CRU Mapped Address: %p\n", &cru_rom_addr); - } - iounmap(bios32_map); - return retval; -} - -/* - * bios_checksum - */ -static int bios_checksum(const char __iomem *ptr, int len) -{ - char sum = 0; - int i; - - /* - * calculate checksum of size bytes. This should add up - * to zero if we have a valid header. - */ - for (i = 0; i < len; i++) - sum += ptr[i]; - - return ((sum == 0) && (len > 0)); -} - -/* - * bios32_present - * - * Routine Description: - * This function finds the 32-bit BIOS Service Directory - * - * Return Value: - * 0 : SUCCESS - * <0 : FAILURE - */ -static int bios32_present(const char __iomem *p) -{ - struct bios32_service_dir *bios_32_ptr; - int length; - unsigned long map_entry, map_offset; - - bios_32_ptr = (struct bios32_service_dir *) p; - - /* - * Search for signature by checking equal to the swizzled value - * instead of calling another routine to perform a strcmp. - */ - if (bios_32_ptr->signature == PCI_BIOS32_SD_VALUE) { - length = bios_32_ptr->length * PCI_BIOS32_PARAGRAPH_LEN; - if (bios_checksum(p, length)) { - /* - * According to the spec, we're looking for the - * first 4KB-aligned address below the entrypoint - * listed in the header. The Service Directory code - * is guaranteed to occupy no more than 2 4KB pages. - */ - map_entry = bios_32_ptr->entry_point & ~(PAGE_SIZE - 1); - map_offset = bios_32_ptr->entry_point - map_entry; - - return cru_detect(map_entry, map_offset); - } - } - return -ENODEV; -} - -static int detect_cru_service(void) -{ - char __iomem *p, *q; - int rc = -1; - - /* - * Search from 0x0f0000 through 0x0fffff, inclusive. - */ - p = ioremap(PCI_ROM_BASE1, ROM_SIZE); - if (p == NULL) - return -ENOMEM; - - for (q = p; q < p + ROM_SIZE; q += 16) { - rc = bios32_present(q); - if (!rc) - break; - } - iounmap(p); - return rc; -} -/* ------------------------------------------------------------------------- */ -#endif /* CONFIG_X86_32 */ -#ifdef CONFIG_X86_64 -/* --64 Bit Bios------------------------------------------------------------ */ - -#define HPWDT_ARCH 64 - -asm(".text \n\t" - ".align 4 \n\t" - ".globl asminline_call \n\t" - ".type asminline_call, @function \n\t" - "asminline_call: \n\t" - FRAME_BEGIN - "pushq %rax \n\t" - "pushq %rbx \n\t" - "pushq %rdx \n\t" - "pushq %r12 \n\t" - "pushq %r9 \n\t" - "movq %rsi, %r12 \n\t" - "movq %rdi, %r9 \n\t" - "movl 4(%r9),%ebx \n\t" - "movl 8(%r9),%ecx \n\t" - "movl 12(%r9),%edx \n\t" - "movl 16(%r9),%esi \n\t" - "movl 20(%r9),%edi \n\t" - "movl (%r9),%eax \n\t" - "call *%r12 \n\t" - "pushfq \n\t" - "popq %r12 \n\t" - "movl %eax, (%r9) \n\t" - "movl %ebx, 4(%r9) \n\t" - "movl %ecx, 8(%r9) \n\t" - "movl %edx, 12(%r9) \n\t" - "movl %esi, 16(%r9) \n\t" - "movl %edi, 20(%r9) \n\t" - "movq %r12, %rax \n\t" - "movl %eax, 28(%r9) \n\t" - "popq %r9 \n\t" - "popq %r12 \n\t" - "popq %rdx \n\t" - "popq %rbx \n\t" - "popq %rax \n\t" - FRAME_END - "ret \n\t" - ".previous"); - -/* - * dmi_find_cru - * - * Routine Description: - * This function checks whether or not a SMBIOS/DMI record is - * the 64bit CRU info or not - */ -static void dmi_find_cru(const struct dmi_header *dm, void *dummy) -{ - struct smbios_cru64_info *smbios_cru64_ptr; - unsigned long cru_physical_address; - - if (dm->type == SMBIOS_CRU64_INFORMATION) { - smbios_cru64_ptr = (struct smbios_cru64_info *) dm; - if (smbios_cru64_ptr->signature == CRU_BIOS_SIGNATURE_VALUE) { - cru_physical_address = - smbios_cru64_ptr->physical_address + - smbios_cru64_ptr->double_offset; - cru_rom_addr = ioremap(cru_physical_address, - smbios_cru64_ptr->double_length); - set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, - smbios_cru64_ptr->double_length >> PAGE_SHIFT); - } - } -} - -static int detect_cru_service(void) -{ - cru_rom_addr = NULL; - - dmi_walk(dmi_find_cru, NULL); - - /* if cru_rom_addr has been set then we found a CRU service */ - return ((cru_rom_addr != NULL) ? 0 : -ENODEV); -} -/* ------------------------------------------------------------------------- */ -#endif /* CONFIG_X86_64 */ -#endif /* CONFIG_HPWDT_NMI_DECODING */ /* * Watchdog operations @@ -486,30 +113,12 @@ static int hpwdt_my_nmi(void) */ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) { - unsigned long rom_pl; - static int die_nmi_called; - - if (!hpwdt_nmi_decoding) - return NMI_DONE; - if ((ulReason == NMI_UNKNOWN) && !hpwdt_my_nmi()) return NMI_DONE; - spin_lock_irqsave(&rom_lock, rom_pl); - if (!die_nmi_called && !is_icru && !is_uefi) - asminline_call(&cmn_regs, cru_rom_addr); - die_nmi_called = 1; - spin_unlock_irqrestore(&rom_lock, rom_pl); - if (allow_kdump) hpwdt_stop(); - if (!is_icru && !is_uefi) { - if (cmn_regs.u1.ral == 0) { - nmi_panic(regs, "An NMI occurred, but unable to determine source.\n"); - return NMI_HANDLED; - } - } nmi_panic(regs, "An NMI occurred. Depending on your system the reason " "for the NMI is logged in any one of the following " "resources:\n" @@ -675,84 +284,11 @@ static struct miscdevice hpwdt_miscdev = { * Init & Exit */ -#ifdef CONFIG_HPWDT_NMI_DECODING -#ifdef CONFIG_X86_LOCAL_APIC -static void hpwdt_check_nmi_decoding(struct pci_dev *dev) -{ - /* - * If nmi_watchdog is turned off then we can turn on - * our nmi decoding capability. - */ - hpwdt_nmi_decoding = 1; -} -#else -static void hpwdt_check_nmi_decoding(struct pci_dev *dev) -{ - dev_warn(&dev->dev, "NMI decoding is disabled. " - "Your kernel does not support a NMI Watchdog.\n"); -} -#endif /* CONFIG_X86_LOCAL_APIC */ - -/* - * dmi_find_icru - * - * Routine Description: - * This function checks whether or not we are on an iCRU-based server. - * This check is independent of architecture and needs to be made for - * any ProLiant system. - */ -static void dmi_find_icru(const struct dmi_header *dm, void *dummy) -{ - struct smbios_proliant_info *smbios_proliant_ptr; - - if (dm->type == SMBIOS_ICRU_INFORMATION) { - smbios_proliant_ptr = (struct smbios_proliant_info *) dm; - if (smbios_proliant_ptr->misc_features & 0x01) - is_icru = 1; - if (smbios_proliant_ptr->misc_features & 0x1400) - is_uefi = 1; - } -} static int hpwdt_init_nmi_decoding(struct pci_dev *dev) { +#ifdef CONFIG_HPWDT_NMI_DECODING int retval; - - /* - * On typical CRU-based systems we need to map that service in - * the BIOS. For 32 bit Operating Systems we need to go through - * the 32 Bit BIOS Service Directory. For 64 bit Operating - * Systems we get that service through SMBIOS. - * - * On systems that support the new iCRU service all we need to - * do is call dmi_walk to get the supported flag value and skip - * the old cru detect code. - */ - dmi_walk(dmi_find_icru, NULL); - if (!is_icru && !is_uefi) { - - /* - * We need to map the ROM to get the CRU service. - * For 32 bit Operating Systems we need to go through the 32 Bit - * BIOS Service Directory - * For 64 bit Operating Systems we get that service through SMBIOS. - */ - retval = detect_cru_service(); - if (retval < 0) { - dev_warn(&dev->dev, - "Unable to detect the %d Bit CRU Service.\n", - HPWDT_ARCH); - return retval; - } - - /* - * We know this is the only CRU call we need to make so lets keep as - * few instructions as possible once the NMI comes in. - */ - cmn_regs.u1.rah = 0x0D; - cmn_regs.u1.ral = 0x02; - } - /* * Only one function can register for NMI_UNKNOWN */ @@ -780,44 +316,25 @@ error: dev_warn(&dev->dev, "Unable to register a die notifier (err=%d).\n", retval); - if (cru_rom_addr) - iounmap(cru_rom_addr); return retval; +#endif /* CONFIG_HPWDT_NMI_DECODING */ + return 0; } static void hpwdt_exit_nmi_decoding(void) { +#ifdef CONFIG_HPWDT_NMI_DECODING unregister_nmi_handler(NMI_UNKNOWN, "hpwdt"); unregister_nmi_handler(NMI_SERR, "hpwdt"); unregister_nmi_handler(NMI_IO_CHECK, "hpwdt"); - if (cru_rom_addr) - iounmap(cru_rom_addr); -} -#else /* !CONFIG_HPWDT_NMI_DECODING */ -static void hpwdt_check_nmi_decoding(struct pci_dev *dev) -{ -} - -static int hpwdt_init_nmi_decoding(struct pci_dev *dev) -{ - return 0; +#endif } -static void hpwdt_exit_nmi_decoding(void) -{ -} -#endif /* CONFIG_HPWDT_NMI_DECODING */ - static int hpwdt_init_one(struct pci_dev *dev, const struct pci_device_id *ent) { int retval; - /* - * Check if we can do NMI decoding or not - */ - hpwdt_check_nmi_decoding(dev); - /* * First let's find out if we are on an iLO2+ server. We will * not run on a legacy ASM box. @@ -922,6 +439,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" #ifdef CONFIG_HPWDT_NMI_DECODING module_param(allow_kdump, int, 0); MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs"); -#endif /* !CONFIG_HPWDT_NMI_DECODING */ +#endif /* CONFIG_HPWDT_NMI_DECODING */ module_pci_driver(hpwdt_driver); -- cgit v1.2.3 From 39a751a4cb7e4798f0ce1169ec92de4a1aae39e3 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Mon, 12 Feb 2018 00:19:42 -0800 Subject: of: change overlay apply input data from unflattened to FDT Move duplicating and unflattening of an overlay flattened devicetree (FDT) into the overlay application code. To accomplish this, of_overlay_apply() is replaced by of_overlay_fdt_apply(). The copy of the FDT (aka "duplicate FDT") now belongs to devicetree code, which is thus responsible for freeing the duplicate FDT. The caller of of_overlay_fdt_apply() remains responsible for freeing the original FDT. The unflattened devicetree now belongs to devicetree code, which is thus responsible for freeing the unflattened devicetree. These ownership changes prevent early freeing of the duplicated FDT or the unflattened devicetree, which could result in use after free errors. of_overlay_fdt_apply() is a private function for the anticipated overlay loader. Update unittest.c to use of_overlay_fdt_apply() instead of of_overlay_apply(). Move overlay fragments from artificial locations in drivers/of/unittest-data/tests-overlay.dtsi into one devicetree source file per overlay. This led to changes in drivers/of/unitest-data/Makefile and drivers/of/unitest.c. - Add overlay directives to the overlay devicetree source files so that dtc will compile them as true overlays into one FDT data chunk per overlay. - Set CFLAGS for drivers/of/unittest-data/testcases.dts so that symbols will be generated for overlay resolution of overlays that are no longer artificially contained in testcases.dts - Unflatten and apply each unittest overlay FDT using of_overlay_fdt_apply(). - Enable the of_resolve_phandles() check for whether the unflattened overlay is detached. This check was previously disabled because the overlays from tests-overlay.dtsi were not unflattened into detached trees. - Other changes to unittest.c infrastructure to manage multiple test FDTs built into the kernel image (access by name instead of arbitrary number). - of_unittest_overlay_high_level(): previously unused code to add properties from the overlay_base devicetree to the live tree was triggered by the restructuring of tests-overlay.dtsi and thus testcases.dts. This exposed two bugs: (1) the need to dup a property before adding it, and (2) property 'name' is auto-generated in the unflatten code and thus will be a duplicate in the __symbols__ node - do not treat this duplicate as an error. Signed-off-by: Frank Rowand --- drivers/of/Kconfig | 1 + drivers/of/overlay.c | 112 ++++++++++- drivers/of/resolver.c | 6 - drivers/of/unittest-data/Makefile | 28 ++- drivers/of/unittest-data/overlay_0.dts | 14 ++ drivers/of/unittest-data/overlay_1.dts | 14 ++ drivers/of/unittest-data/overlay_10.dts | 34 ++++ drivers/of/unittest-data/overlay_11.dts | 34 ++++ drivers/of/unittest-data/overlay_12.dts | 14 ++ drivers/of/unittest-data/overlay_13.dts | 14 ++ drivers/of/unittest-data/overlay_15.dts | 35 ++++ drivers/of/unittest-data/overlay_2.dts | 14 ++ drivers/of/unittest-data/overlay_3.dts | 14 ++ drivers/of/unittest-data/overlay_4.dts | 23 +++ drivers/of/unittest-data/overlay_5.dts | 14 ++ drivers/of/unittest-data/overlay_6.dts | 15 ++ drivers/of/unittest-data/overlay_7.dts | 15 ++ drivers/of/unittest-data/overlay_8.dts | 15 ++ drivers/of/unittest-data/overlay_9.dts | 15 ++ drivers/of/unittest-data/tests-overlay.dtsi | 213 -------------------- drivers/of/unittest.c | 300 ++++++++++++++-------------- 21 files changed, 559 insertions(+), 385 deletions(-) create mode 100644 drivers/of/unittest-data/overlay_0.dts create mode 100644 drivers/of/unittest-data/overlay_1.dts create mode 100644 drivers/of/unittest-data/overlay_10.dts create mode 100644 drivers/of/unittest-data/overlay_11.dts create mode 100644 drivers/of/unittest-data/overlay_12.dts create mode 100644 drivers/of/unittest-data/overlay_13.dts create mode 100644 drivers/of/unittest-data/overlay_15.dts create mode 100644 drivers/of/unittest-data/overlay_2.dts create mode 100644 drivers/of/unittest-data/overlay_3.dts create mode 100644 drivers/of/unittest-data/overlay_4.dts create mode 100644 drivers/of/unittest-data/overlay_5.dts create mode 100644 drivers/of/unittest-data/overlay_6.dts create mode 100644 drivers/of/unittest-data/overlay_7.dts create mode 100644 drivers/of/unittest-data/overlay_8.dts create mode 100644 drivers/of/unittest-data/overlay_9.dts (limited to 'drivers') diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 783e0870bd22..ad3fcad4d75b 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -92,6 +92,7 @@ config OF_RESOLVE config OF_OVERLAY bool "Device Tree overlays" select OF_DYNAMIC + select OF_FLATTREE select OF_RESOLVE help Overlays are a method to dynamically modify part of the kernel's diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index 3397d7642958..e3d7f69a8333 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -12,10 +12,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -33,7 +35,9 @@ struct fragment { /** * struct overlay_changeset + * @id: changeset identifier * @ovcs_list: list on which we are located + * @fdt: FDT that was unflattened to create @overlay_tree * @overlay_tree: expanded device tree that contains the fragment nodes * @count: count of fragment structures * @fragments: fragment nodes in the overlay expanded device tree @@ -43,6 +47,7 @@ struct fragment { struct overlay_changeset { int id; struct list_head ovcs_list; + const void *fdt; struct device_node *overlay_tree; int count; struct fragment *fragments; @@ -503,7 +508,8 @@ static struct device_node *find_target_node(struct device_node *info_node) /** * init_overlay_changeset() - initialize overlay changeset from overlay tree - * @ovcs Overlay changeset to build + * @ovcs: Overlay changeset to build + * @fdt: the FDT that was unflattened to create @tree * @tree: Contains all the overlay fragments and overlay fixup nodes * * Initialize @ovcs. Populate @ovcs->fragments with node information from @@ -514,7 +520,7 @@ static struct device_node *find_target_node(struct device_node *info_node) * detected in @tree, or -ENOSPC if idr_alloc() error. */ static int init_overlay_changeset(struct overlay_changeset *ovcs, - struct device_node *tree) + const void *fdt, struct device_node *tree) { struct device_node *node, *overlay_node; struct fragment *fragment; @@ -535,6 +541,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs, pr_debug("%s() tree is not root\n", __func__); ovcs->overlay_tree = tree; + ovcs->fdt = fdt; INIT_LIST_HEAD(&ovcs->ovcs_list); @@ -606,6 +613,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs, } if (!cnt) { + pr_err("no fragments or symbols in overlay\n"); ret = -EINVAL; goto err_free_fragments; } @@ -642,11 +650,24 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs) } kfree(ovcs->fragments); + /* + * TODO + * + * would like to: kfree(ovcs->overlay_tree); + * but can not since drivers may have pointers into this data + * + * would like to: kfree(ovcs->fdt); + * but can not since drivers may have pointers into this data + */ + kfree(ovcs); } -/** +/* + * internal documentation + * * of_overlay_apply() - Create and apply an overlay changeset + * @fdt: the FDT that was unflattened to create @tree * @tree: Expanded overlay device tree * @ovcs_id: Pointer to overlay changeset id * @@ -685,21 +706,29 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs) * id is returned to *ovcs_id. */ -int of_overlay_apply(struct device_node *tree, int *ovcs_id) +static int of_overlay_apply(const void *fdt, struct device_node *tree, + int *ovcs_id) { struct overlay_changeset *ovcs; int ret = 0, ret_revert, ret_tmp; - *ovcs_id = 0; + /* + * As of this point, fdt and tree belong to the overlay changeset. + * overlay changeset code is responsible for freeing them. + */ if (devicetree_corrupt()) { pr_err("devicetree state suspect, refuse to apply overlay\n"); + kfree(fdt); + kfree(tree); ret = -EBUSY; goto out; } ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL); if (!ovcs) { + kfree(fdt); + kfree(tree); ret = -ENOMEM; goto out; } @@ -709,12 +738,17 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id) ret = of_resolve_phandles(tree); if (ret) - goto err_free_overlay_changeset; + goto err_free_tree; - ret = init_overlay_changeset(ovcs, tree); + ret = init_overlay_changeset(ovcs, fdt, tree); if (ret) - goto err_free_overlay_changeset; + goto err_free_tree; + /* + * after overlay_notify(), ovcs->overlay_tree related pointers may have + * leaked to drivers, so can not kfree() tree, aka ovcs->overlay_tree; + * and can not free fdt, aka ovcs->fdt + */ ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY); if (ret) { pr_err("overlay changeset pre-apply notify error %d\n", ret); @@ -754,6 +788,10 @@ int of_overlay_apply(struct device_node *tree, int *ovcs_id) goto out_unlock; +err_free_tree: + kfree(fdt); + kfree(tree); + err_free_overlay_changeset: free_overlay_changeset(ovcs); @@ -766,7 +804,63 @@ out: return ret; } -EXPORT_SYMBOL_GPL(of_overlay_apply); + +int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size, + int *ovcs_id) +{ + const void *new_fdt; + int ret; + u32 size; + struct device_node *overlay_root; + + *ovcs_id = 0; + ret = 0; + + if (overlay_fdt_size < sizeof(struct fdt_header) || + fdt_check_header(overlay_fdt)) { + pr_err("Invalid overlay_fdt header\n"); + return -EINVAL; + } + + size = fdt_totalsize(overlay_fdt); + if (overlay_fdt_size < size) + return -EINVAL; + + /* + * Must create permanent copy of FDT because of_fdt_unflatten_tree() + * will create pointers to the passed in FDT in the unflattened tree. + */ + new_fdt = kmemdup(overlay_fdt, size, GFP_KERNEL); + if (!new_fdt) + return -ENOMEM; + + of_fdt_unflatten_tree(new_fdt, NULL, &overlay_root); + if (!overlay_root) { + pr_err("unable to unflatten overlay_fdt\n"); + ret = -EINVAL; + goto out_free_new_fdt; + } + + ret = of_overlay_apply(new_fdt, overlay_root, ovcs_id); + if (ret < 0) { + /* + * new_fdt and overlay_root now belong to the overlay + * changeset. + * overlay changeset code is responsible for freeing them. + */ + goto out; + } + + return 0; + + +out_free_new_fdt: + kfree(new_fdt); + +out: + return ret; +} +EXPORT_SYMBOL_GPL(of_overlay_fdt_apply); /* * Find @np in @tree. diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 740d19bde601..b2f645187213 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -269,17 +269,11 @@ int of_resolve_phandles(struct device_node *overlay) goto out; } -#if 0 - Temporarily disable check so that old style overlay unittests - do not fail when of_resolve_phandles() is moved into - of_overlay_apply(). - if (!of_node_check_flag(overlay, OF_DETACHED)) { pr_err("overlay not detached\n"); err = -EINVAL; goto out; } -#endif phandle_delta = live_tree_max_phandle() + 1; adjust_overlay_phandles(overlay, phandle_delta); diff --git a/drivers/of/unittest-data/Makefile b/drivers/of/unittest-data/Makefile index df697976740a..8fd0ea4b92b0 100644 --- a/drivers/of/unittest-data/Makefile +++ b/drivers/of/unittest-data/Makefile @@ -1,8 +1,22 @@ # SPDX-License-Identifier: GPL-2.0 -DTC_FLAGS_testcases := -Wno-interrupts_property obj-y += testcases.dtb.o obj-$(CONFIG_OF_OVERLAY) += overlay.dtb.o \ + overlay_0.dtb.o \ + overlay_1.dtb.o \ + overlay_2.dtb.o \ + overlay_3.dtb.o \ + overlay_4.dtb.o \ + overlay_5.dtb.o \ + overlay_6.dtb.o \ + overlay_7.dtb.o \ + overlay_8.dtb.o \ + overlay_9.dtb.o \ + overlay_10.dtb.o \ + overlay_11.dtb.o \ + overlay_12.dtb.o \ + overlay_13.dtb.o \ + overlay_15.dtb.o \ overlay_bad_phandle.dtb.o \ overlay_bad_symbol.dtb.o \ overlay_base.dtb.o @@ -10,10 +24,14 @@ obj-$(CONFIG_OF_OVERLAY) += overlay.dtb.o \ targets += $(foreach suffix, dtb dtb.S, $(patsubst %.dtb.o,%.$(suffix),$(obj-y))) # enable creation of __symbols__ node -DTC_FLAGS_overlay := -@ -DTC_FLAGS_overlay_bad_phandle := -@ -DTC_FLAGS_overlay_bad_symbol := -@ -DTC_FLAGS_overlay_base := -@ +DTC_FLAGS_overlay += -@ +DTC_FLAGS_overlay_bad_phandle += -@ +DTC_FLAGS_overlay_bad_symbol += -@ +DTC_FLAGS_overlay_base += -@ +DTC_FLAGS_testcases += -@ + +# suppress warnings about intentional errors +DTC_FLAGS_testcases += -Wno-interrupts_property .PRECIOUS: \ $(obj)/%.dtb.S \ diff --git a/drivers/of/unittest-data/overlay_0.dts b/drivers/of/unittest-data/overlay_0.dts new file mode 100644 index 000000000000..ac0f9e0fe65f --- /dev/null +++ b/drivers/of/unittest-data/overlay_0.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_0 - enable using absolute target path */ + + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-unittest0"; + __overlay__ { + status = "okay"; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_1.dts b/drivers/of/unittest-data/overlay_1.dts new file mode 100644 index 000000000000..e92a626e2948 --- /dev/null +++ b/drivers/of/unittest-data/overlay_1.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_1 - disable using absolute target path */ + + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-unittest1"; + __overlay__ { + status = "disabled"; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_10.dts b/drivers/of/unittest-data/overlay_10.dts new file mode 100644 index 000000000000..445925a10cd3 --- /dev/null +++ b/drivers/of/unittest-data/overlay_10.dts @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_10 */ + /* overlays 8, 9, 10, 11 application and removal in bad sequence */ + + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus"; + __overlay__ { + + /* suppress DTC warning */ + #address-cells = <1>; + #size-cells = <0>; + + test-unittest10 { + compatible = "unittest"; + status = "okay"; + reg = <10>; + + #address-cells = <1>; + #size-cells = <0>; + + test-unittest101 { + compatible = "unittest"; + status = "okay"; + reg = <1>; + }; + + }; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_11.dts b/drivers/of/unittest-data/overlay_11.dts new file mode 100644 index 000000000000..c1d14f34359e --- /dev/null +++ b/drivers/of/unittest-data/overlay_11.dts @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_11 */ + /* overlays 8, 9, 10, 11 application and removal in bad sequence */ + + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus"; + __overlay__ { + + /* suppress DTC warning */ + #address-cells = <1>; + #size-cells = <0>; + + test-unittest11 { + compatible = "unittest"; + status = "okay"; + reg = <11>; + + #address-cells = <1>; + #size-cells = <0>; + + test-unittest111 { + compatible = "unittest"; + status = "okay"; + reg = <1>; + }; + + }; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_12.dts b/drivers/of/unittest-data/overlay_12.dts new file mode 100644 index 000000000000..ca3441e2cbec --- /dev/null +++ b/drivers/of/unittest-data/overlay_12.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_12 - enable using absolute target path (i2c) */ + + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest12"; + __overlay__ { + status = "okay"; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_13.dts b/drivers/of/unittest-data/overlay_13.dts new file mode 100644 index 000000000000..3c30dec63894 --- /dev/null +++ b/drivers/of/unittest-data/overlay_13.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_13 - disable using absolute target path (i2c) */ + + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest13"; + __overlay__ { + status = "disabled"; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_15.dts b/drivers/of/unittest-data/overlay_15.dts new file mode 100644 index 000000000000..44e44c62b739 --- /dev/null +++ b/drivers/of/unittest-data/overlay_15.dts @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_15 - mux overlay */ + + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus"; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + test-unittest15 { + reg = <11>; + compatible = "unittest-i2c-mux"; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + test-mux-dev { + reg = <32>; + compatible = "unittest-i2c-dev"; + status = "okay"; + }; + }; + }; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_2.dts b/drivers/of/unittest-data/overlay_2.dts new file mode 100644 index 000000000000..cf1e4245b7ce --- /dev/null +++ b/drivers/of/unittest-data/overlay_2.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_2 - enable using label */ + + fragment@0 { + target = <&unittest2>; + __overlay__ { + status = "okay"; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_3.dts b/drivers/of/unittest-data/overlay_3.dts new file mode 100644 index 000000000000..158dc44fc20a --- /dev/null +++ b/drivers/of/unittest-data/overlay_3.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_3 - disable using label */ + + fragment@0 { + target = <&unittest3>; + __overlay__ { + status = "disabled"; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_4.dts b/drivers/of/unittest-data/overlay_4.dts new file mode 100644 index 000000000000..b4a2e6c6b016 --- /dev/null +++ b/drivers/of/unittest-data/overlay_4.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_4 - test insertion of a full node */ + + fragment@0 { + target = <&unittestbus>; + __overlay__ { + + /* suppress DTC warning */ + #address-cells = <1>; + #size-cells = <0>; + + test-unittest4 { + compatible = "unittest"; + status = "okay"; + reg = <4>; + }; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_5.dts b/drivers/of/unittest-data/overlay_5.dts new file mode 100644 index 000000000000..02ad25c1f19c --- /dev/null +++ b/drivers/of/unittest-data/overlay_5.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_5 - test overlay apply revert */ + + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-unittest5"; + __overlay__ { + status = "okay"; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_6.dts b/drivers/of/unittest-data/overlay_6.dts new file mode 100644 index 000000000000..a14e965f5497 --- /dev/null +++ b/drivers/of/unittest-data/overlay_6.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_6 */ + /* overlays 6, 7 application and removal in sequence */ + + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-unittest6"; + __overlay__ { + status = "okay"; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_7.dts b/drivers/of/unittest-data/overlay_7.dts new file mode 100644 index 000000000000..4bd7e423209c --- /dev/null +++ b/drivers/of/unittest-data/overlay_7.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_7 */ + /* overlays 6, 7 application and removal in sequence */ + + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-unittest7"; + __overlay__ { + status = "okay"; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_8.dts b/drivers/of/unittest-data/overlay_8.dts new file mode 100644 index 000000000000..5b21c53945a9 --- /dev/null +++ b/drivers/of/unittest-data/overlay_8.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_8 */ + /* overlays 8, 9, 10, 11 application and removal in bad sequence */ + + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-unittest8"; + __overlay__ { + status = "okay"; + }; + }; +}; diff --git a/drivers/of/unittest-data/overlay_9.dts b/drivers/of/unittest-data/overlay_9.dts new file mode 100644 index 000000000000..20ff055a5349 --- /dev/null +++ b/drivers/of/unittest-data/overlay_9.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/ { + /* overlay_9 */ + /* overlays 8, 9, 10, 11 application and removal in bad sequence */ + + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/test-unittest8"; + __overlay__ { + property-foo = "bar"; + }; + }; +}; diff --git a/drivers/of/unittest-data/tests-overlay.dtsi b/drivers/of/unittest-data/tests-overlay.dtsi index 7b8001ab9f3a..fa2fb43bccac 100644 --- a/drivers/of/unittest-data/tests-overlay.dtsi +++ b/drivers/of/unittest-data/tests-overlay.dtsi @@ -113,218 +113,5 @@ }; }; }; - - /* test enable using absolute target path */ - overlay0 { - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/test-unittest0"; - __overlay__ { - status = "okay"; - }; - }; - }; - - /* test disable using absolute target path */ - overlay1 { - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/test-unittest1"; - __overlay__ { - status = "disabled"; - }; - }; - }; - - /* test enable using label */ - overlay2 { - fragment@0 { - target = <&unittest2>; - __overlay__ { - status = "okay"; - }; - }; - }; - - /* test disable using label */ - overlay3 { - fragment@0 { - target = <&unittest3>; - __overlay__ { - status = "disabled"; - }; - }; - }; - - /* test insertion of a full node */ - overlay4 { - fragment@0 { - target = <&unittestbus>; - __overlay__ { - - /* suppress DTC warning */ - #address-cells = <1>; - #size-cells = <0>; - - test-unittest4 { - compatible = "unittest"; - status = "okay"; - reg = <4>; - }; - }; - }; - }; - - /* test overlay apply revert */ - overlay5 { - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/test-unittest5"; - __overlay__ { - status = "okay"; - }; - }; - }; - - /* test overlays application and removal in sequence */ - overlay6 { - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/test-unittest6"; - __overlay__ { - status = "okay"; - }; - }; - }; - overlay7 { - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/test-unittest7"; - __overlay__ { - status = "okay"; - }; - }; - }; - - /* test overlays application and removal in bad sequence */ - overlay8 { - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/test-unittest8"; - __overlay__ { - status = "okay"; - }; - }; - }; - overlay9 { - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/test-unittest8"; - __overlay__ { - property-foo = "bar"; - }; - }; - }; - - overlay10 { - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus"; - __overlay__ { - - /* suppress DTC warning */ - #address-cells = <1>; - #size-cells = <0>; - - test-unittest10 { - compatible = "unittest"; - status = "okay"; - reg = <10>; - - #address-cells = <1>; - #size-cells = <0>; - - test-unittest101 { - compatible = "unittest"; - status = "okay"; - reg = <1>; - }; - - }; - }; - }; - }; - - overlay11 { - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus"; - __overlay__ { - - /* suppress DTC warning */ - #address-cells = <1>; - #size-cells = <0>; - - test-unittest11 { - compatible = "unittest"; - status = "okay"; - reg = <11>; - - #address-cells = <1>; - #size-cells = <0>; - - test-unittest111 { - compatible = "unittest"; - status = "okay"; - reg = <1>; - }; - - }; - }; - }; - }; - - /* test enable using absolute target path (i2c) */ - overlay12 { - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest12"; - __overlay__ { - status = "okay"; - }; - }; - }; - - /* test disable using absolute target path (i2c) */ - overlay13 { - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest13"; - __overlay__ { - status = "disabled"; - }; - }; - }; - - /* test mux overlay */ - overlay15 { - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus"; - __overlay__ { - #address-cells = <1>; - #size-cells = <0>; - test-unittest15 { - reg = <11>; - compatible = "unittest-i2c-mux"; - status = "okay"; - - #address-cells = <1>; - #size-cells = <0>; - - i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - - test-mux-dev { - reg = <32>; - compatible = "unittest-i2c-dev"; - status = "okay"; - }; - }; - }; - }; - }; - }; - }; }; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 7a9abaae874d..a23b54780c7d 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -45,6 +45,8 @@ static struct unittest_results { failed; \ }) +static int __init overlay_data_apply(const char *overlay_name, int *overlay_id); + static void __init of_unittest_find_node_by_name(void) { struct device_node *np; @@ -997,8 +999,7 @@ static int __init unittest_data_add(void) } /* - * This lock normally encloses of_overlay_apply() as well as - * of_resolve_phandles(). + * This lock normally encloses of_resolve_phandles() */ of_overlay_mutex_lock(); @@ -1191,12 +1192,12 @@ static int of_unittest_device_exists(int unittest_nr, enum overlay_type ovtype) return 0; } -static const char *overlay_path(int nr) +static const char *overlay_name_from_nr(int nr) { static char buf[256]; snprintf(buf, sizeof(buf) - 1, - "/testcase-data/overlay%d", nr); + "overlay_%d", nr); buf[sizeof(buf) - 1] = '\0'; return buf; @@ -1263,25 +1264,19 @@ static void of_unittest_destroy_tracked_overlays(void) } while (defers > 0); } -static int of_unittest_apply_overlay(int overlay_nr, int unittest_nr, +static int __init of_unittest_apply_overlay(int overlay_nr, int unittest_nr, int *overlay_id) { struct device_node *np = NULL; + const char *overlay_name; int ret; - np = of_find_node_by_path(overlay_path(overlay_nr)); - if (np == NULL) { - unittest(0, "could not find overlay node @\"%s\"\n", - overlay_path(overlay_nr)); - ret = -EINVAL; - goto out; - } + overlay_name = overlay_name_from_nr(overlay_nr); - *overlay_id = 0; - ret = of_overlay_apply(np, overlay_id); - if (ret < 0) { - unittest(0, "could not create overlay from \"%s\"\n", - overlay_path(overlay_nr)); + ret = overlay_data_apply(overlay_name, overlay_id); + if (!ret) { + unittest(0, "could not apply overlay \"%s\"\n", + overlay_name); goto out; } of_unittest_track_overlay(*overlay_id); @@ -1295,15 +1290,16 @@ out: } /* apply an overlay while checking before and after states */ -static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr, - int before, int after, enum overlay_type ovtype) +static int __init of_unittest_apply_overlay_check(int overlay_nr, + int unittest_nr, int before, int after, + enum overlay_type ovtype) { int ret, ovcs_id; /* unittest device must not be in before state */ if (of_unittest_device_exists(unittest_nr, ovtype) != before) { - unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n", - overlay_path(overlay_nr), + unittest(0, "%s with device @\"%s\" %s\n", + overlay_name_from_nr(overlay_nr), unittest_path(unittest_nr, ovtype), !before ? "enabled" : "disabled"); return -EINVAL; @@ -1318,8 +1314,8 @@ static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr, /* unittest device must be to set to after state */ if (of_unittest_device_exists(unittest_nr, ovtype) != after) { - unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n", - overlay_path(overlay_nr), + unittest(0, "%s failed to create @\"%s\" %s\n", + overlay_name_from_nr(overlay_nr), unittest_path(unittest_nr, ovtype), !after ? "enabled" : "disabled"); return -EINVAL; @@ -1329,7 +1325,7 @@ static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr, } /* apply an overlay and then revert it while checking before, after states */ -static int of_unittest_apply_revert_overlay_check(int overlay_nr, +static int __init of_unittest_apply_revert_overlay_check(int overlay_nr, int unittest_nr, int before, int after, enum overlay_type ovtype) { @@ -1337,8 +1333,8 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr, /* unittest device must be in before state */ if (of_unittest_device_exists(unittest_nr, ovtype) != before) { - unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n", - overlay_path(overlay_nr), + unittest(0, "%s with device @\"%s\" %s\n", + overlay_name_from_nr(overlay_nr), unittest_path(unittest_nr, ovtype), !before ? "enabled" : "disabled"); return -EINVAL; @@ -1354,8 +1350,8 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr, /* unittest device must be in after state */ if (of_unittest_device_exists(unittest_nr, ovtype) != after) { - unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n", - overlay_path(overlay_nr), + unittest(0, "%s failed to create @\"%s\" %s\n", + overlay_name_from_nr(overlay_nr), unittest_path(unittest_nr, ovtype), !after ? "enabled" : "disabled"); return -EINVAL; @@ -1363,16 +1359,16 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr, ret = of_overlay_remove(&ovcs_id); if (ret != 0) { - unittest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n", - overlay_path(overlay_nr), + unittest(0, "%s failed to be destroyed @\"%s\"\n", + overlay_name_from_nr(overlay_nr), unittest_path(unittest_nr, ovtype)); return ret; } /* unittest device must be again in before state */ if (of_unittest_device_exists(unittest_nr, PDEV_OVERLAY) != before) { - unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n", - overlay_path(overlay_nr), + unittest(0, "%s with device @\"%s\" %s\n", + overlay_name_from_nr(overlay_nr), unittest_path(unittest_nr, ovtype), !before ? "enabled" : "disabled"); return -EINVAL; @@ -1382,7 +1378,7 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr, } /* test activation of device */ -static void of_unittest_overlay_0(void) +static void __init of_unittest_overlay_0(void) { int ret; @@ -1395,7 +1391,7 @@ static void of_unittest_overlay_0(void) } /* test deactivation of device */ -static void of_unittest_overlay_1(void) +static void __init of_unittest_overlay_1(void) { int ret; @@ -1408,7 +1404,7 @@ static void of_unittest_overlay_1(void) } /* test activation of device */ -static void of_unittest_overlay_2(void) +static void __init of_unittest_overlay_2(void) { int ret; @@ -1421,7 +1417,7 @@ static void of_unittest_overlay_2(void) } /* test deactivation of device */ -static void of_unittest_overlay_3(void) +static void __init of_unittest_overlay_3(void) { int ret; @@ -1434,7 +1430,7 @@ static void of_unittest_overlay_3(void) } /* test activation of a full device node */ -static void of_unittest_overlay_4(void) +static void __init of_unittest_overlay_4(void) { int ret; @@ -1447,7 +1443,7 @@ static void of_unittest_overlay_4(void) } /* test overlay apply/revert sequence */ -static void of_unittest_overlay_5(void) +static void __init of_unittest_overlay_5(void) { int ret; @@ -1460,19 +1456,19 @@ static void of_unittest_overlay_5(void) } /* test overlay application in sequence */ -static void of_unittest_overlay_6(void) +static void __init of_unittest_overlay_6(void) { - struct device_node *np; int ret, i, ov_id[2], ovcs_id; int overlay_nr = 6, unittest_nr = 6; int before = 0, after = 1; + const char *overlay_name; /* unittest device must be in before state */ for (i = 0; i < 2; i++) { if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY) != before) { - unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n", - overlay_path(overlay_nr + i), + unittest(0, "%s with device @\"%s\" %s\n", + overlay_name_from_nr(overlay_nr + i), unittest_path(unittest_nr + i, PDEV_OVERLAY), !before ? "enabled" : "disabled"); @@ -1483,18 +1479,12 @@ static void of_unittest_overlay_6(void) /* apply the overlays */ for (i = 0; i < 2; i++) { - np = of_find_node_by_path(overlay_path(overlay_nr + i)); - if (np == NULL) { - unittest(0, "could not find overlay node @\"%s\"\n", - overlay_path(overlay_nr + i)); - return; - } + overlay_name = overlay_name_from_nr(overlay_nr + i); - ovcs_id = 0; - ret = of_overlay_apply(np, &ovcs_id); - if (ret < 0) { - unittest(0, "could not create overlay from \"%s\"\n", - overlay_path(overlay_nr + i)); + ret = overlay_data_apply(overlay_name, &ovcs_id); + if (!ret) { + unittest(0, "could not apply overlay \"%s\"\n", + overlay_name); return; } ov_id[i] = ovcs_id; @@ -1506,7 +1496,7 @@ static void of_unittest_overlay_6(void) if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY) != after) { unittest(0, "overlay @\"%s\" failed @\"%s\" %s\n", - overlay_path(overlay_nr + i), + overlay_name_from_nr(overlay_nr + i), unittest_path(unittest_nr + i, PDEV_OVERLAY), !after ? "enabled" : "disabled"); @@ -1518,8 +1508,8 @@ static void of_unittest_overlay_6(void) ovcs_id = ov_id[i]; ret = of_overlay_remove(&ovcs_id); if (ret != 0) { - unittest(0, "overlay @\"%s\" failed destroy @\"%s\"\n", - overlay_path(overlay_nr + i), + unittest(0, "%s failed destroy @\"%s\"\n", + overlay_name_from_nr(overlay_nr + i), unittest_path(unittest_nr + i, PDEV_OVERLAY)); return; @@ -1531,8 +1521,8 @@ static void of_unittest_overlay_6(void) /* unittest device must be again in before state */ if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY) != before) { - unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n", - overlay_path(overlay_nr + i), + unittest(0, "%s with device @\"%s\" %s\n", + overlay_name_from_nr(overlay_nr + i), unittest_path(unittest_nr + i, PDEV_OVERLAY), !before ? "enabled" : "disabled"); @@ -1544,29 +1534,23 @@ static void of_unittest_overlay_6(void) } /* test overlay application in sequence */ -static void of_unittest_overlay_8(void) +static void __init of_unittest_overlay_8(void) { - struct device_node *np; int ret, i, ov_id[2], ovcs_id; int overlay_nr = 8, unittest_nr = 8; + const char *overlay_name; /* we don't care about device state in this test */ /* apply the overlays */ for (i = 0; i < 2; i++) { - np = of_find_node_by_path(overlay_path(overlay_nr + i)); - if (np == NULL) { - unittest(0, "could not find overlay node @\"%s\"\n", - overlay_path(overlay_nr + i)); - return; - } + overlay_name = overlay_name_from_nr(overlay_nr + i); - ovcs_id = 0; - ret = of_overlay_apply(np, &ovcs_id); + ret = overlay_data_apply(overlay_name, &ovcs_id); if (ret < 0) { - unittest(0, "could not create overlay from \"%s\"\n", - overlay_path(overlay_nr + i)); + unittest(0, "could not apply overlay \"%s\"\n", + overlay_name); return; } ov_id[i] = ovcs_id; @@ -1577,8 +1561,8 @@ static void of_unittest_overlay_8(void) ovcs_id = ov_id[0]; ret = of_overlay_remove(&ovcs_id); if (ret == 0) { - unittest(0, "overlay @\"%s\" was destroyed @\"%s\"\n", - overlay_path(overlay_nr + 0), + unittest(0, "%s was destroyed @\"%s\"\n", + overlay_name_from_nr(overlay_nr + 0), unittest_path(unittest_nr, PDEV_OVERLAY)); return; @@ -1589,8 +1573,8 @@ static void of_unittest_overlay_8(void) ovcs_id = ov_id[i]; ret = of_overlay_remove(&ovcs_id); if (ret != 0) { - unittest(0, "overlay @\"%s\" not destroyed @\"%s\"\n", - overlay_path(overlay_nr + i), + unittest(0, "%s not destroyed @\"%s\"\n", + overlay_name_from_nr(overlay_nr + i), unittest_path(unittest_nr, PDEV_OVERLAY)); return; @@ -1602,7 +1586,7 @@ static void of_unittest_overlay_8(void) } /* test insertion of a bus with parent devices */ -static void of_unittest_overlay_10(void) +static void __init of_unittest_overlay_10(void) { int ret; char *child_path; @@ -1625,7 +1609,7 @@ static void of_unittest_overlay_10(void) } /* test insertion of a bus with parent devices (and revert) */ -static void of_unittest_overlay_11(void) +static void __init of_unittest_overlay_11(void) { int ret; @@ -1891,7 +1875,7 @@ static void of_unittest_overlay_i2c_cleanup(void) i2c_del_driver(&unittest_i2c_dev_driver); } -static void of_unittest_overlay_i2c_12(void) +static void __init of_unittest_overlay_i2c_12(void) { int ret; @@ -1904,7 +1888,7 @@ static void of_unittest_overlay_i2c_12(void) } /* test deactivation of device */ -static void of_unittest_overlay_i2c_13(void) +static void __init of_unittest_overlay_i2c_13(void) { int ret; @@ -1921,7 +1905,7 @@ static void of_unittest_overlay_i2c_14(void) { } -static void of_unittest_overlay_i2c_15(void) +static void __init of_unittest_overlay_i2c_15(void) { int ret; @@ -2023,23 +2007,38 @@ static inline void __init of_unittest_overlay(void) { } extern uint8_t __dtb_##name##_begin[]; \ extern uint8_t __dtb_##name##_end[] -#define OVERLAY_INFO(name, expected) \ -{ .dtb_begin = __dtb_##name##_begin, \ - .dtb_end = __dtb_##name##_end, \ - .expected_result = expected, \ +#define OVERLAY_INFO(overlay_name, expected) \ +{ .dtb_begin = __dtb_##overlay_name##_begin, \ + .dtb_end = __dtb_##overlay_name##_end, \ + .expected_result = expected, \ + .name = #overlay_name, \ } struct overlay_info { - uint8_t *dtb_begin; - uint8_t *dtb_end; - void *data; - struct device_node *np_overlay; - int expected_result; - int overlay_id; + uint8_t *dtb_begin; + uint8_t *dtb_end; + int expected_result; + int overlay_id; + char *name; }; OVERLAY_INFO_EXTERN(overlay_base); OVERLAY_INFO_EXTERN(overlay); +OVERLAY_INFO_EXTERN(overlay_0); +OVERLAY_INFO_EXTERN(overlay_1); +OVERLAY_INFO_EXTERN(overlay_2); +OVERLAY_INFO_EXTERN(overlay_3); +OVERLAY_INFO_EXTERN(overlay_4); +OVERLAY_INFO_EXTERN(overlay_5); +OVERLAY_INFO_EXTERN(overlay_6); +OVERLAY_INFO_EXTERN(overlay_7); +OVERLAY_INFO_EXTERN(overlay_8); +OVERLAY_INFO_EXTERN(overlay_9); +OVERLAY_INFO_EXTERN(overlay_10); +OVERLAY_INFO_EXTERN(overlay_11); +OVERLAY_INFO_EXTERN(overlay_12); +OVERLAY_INFO_EXTERN(overlay_13); +OVERLAY_INFO_EXTERN(overlay_15); OVERLAY_INFO_EXTERN(overlay_bad_phandle); OVERLAY_INFO_EXTERN(overlay_bad_symbol); @@ -2047,6 +2046,21 @@ OVERLAY_INFO_EXTERN(overlay_bad_symbol); static struct overlay_info overlays[] = { OVERLAY_INFO(overlay_base, -9999), OVERLAY_INFO(overlay, 0), + OVERLAY_INFO(overlay_0, 0), + OVERLAY_INFO(overlay_1, 0), + OVERLAY_INFO(overlay_2, 0), + OVERLAY_INFO(overlay_3, 0), + OVERLAY_INFO(overlay_4, 0), + OVERLAY_INFO(overlay_5, 0), + OVERLAY_INFO(overlay_6, 0), + OVERLAY_INFO(overlay_7, 0), + OVERLAY_INFO(overlay_8, 0), + OVERLAY_INFO(overlay_9, 0), + OVERLAY_INFO(overlay_10, 0), + OVERLAY_INFO(overlay_11, 0), + OVERLAY_INFO(overlay_12, 0), + OVERLAY_INFO(overlay_13, 0), + OVERLAY_INFO(overlay_15, 0), OVERLAY_INFO(overlay_bad_phandle, -EINVAL), OVERLAY_INFO(overlay_bad_symbol, -EINVAL), {} @@ -2077,6 +2091,7 @@ void __init unittest_unflatten_overlay_base(void) { struct overlay_info *info; u32 data_size; + void *new_fdt; u32 size; info = &overlays[0]; @@ -2098,17 +2113,16 @@ void __init unittest_unflatten_overlay_base(void) return; } - info->data = dt_alloc_memory(size, roundup_pow_of_two(FDT_V17_SIZE)); - if (!info->data) { + new_fdt = dt_alloc_memory(size, roundup_pow_of_two(FDT_V17_SIZE)); + if (!new_fdt) { pr_err("alloc for dtb 'overlay_base' failed"); return; } - memcpy(info->data, info->dtb_begin, size); + memcpy(new_fdt, info->dtb_begin, size); - __unflatten_device_tree(info->data, NULL, &info->np_overlay, + __unflatten_device_tree(new_fdt, NULL, &overlay_base_root, dt_alloc_memory, true); - overlay_base_root = info->np_overlay; } /* @@ -2122,73 +2136,44 @@ void __init unittest_unflatten_overlay_base(void) * * Return 0 on unexpected error. */ -static int __init overlay_data_add(int onum) +static int __init overlay_data_apply(const char *overlay_name, int *overlay_id) { struct overlay_info *info; + int found = 0; int k; int ret; u32 size; - u32 size_from_header; - for (k = 0, info = overlays; info; info++, k++) { - if (k == onum) + for (k = 0, info = overlays; info && info->name; info++, k++) { + if (!strcmp(overlay_name, info->name)) { + found = 1; break; + } } - if (onum > k) + if (!found) { + pr_err("no overlay data for %s\n", overlay_name); return 0; + } size = info->dtb_end - info->dtb_begin; if (!size) { - pr_err("no overlay to attach, %d\n", onum); + pr_err("no overlay data for %s\n", overlay_name); ret = 0; } - size_from_header = fdt_totalsize(info->dtb_begin); - if (size_from_header != size) { - pr_err("overlay header totalsize != actual size, %d", onum); - return 0; - } - - /* - * Must create permanent copy of FDT because of_fdt_unflatten_tree() - * will create pointers to the passed in FDT in the EDT. - */ - info->data = kmemdup(info->dtb_begin, size, GFP_KERNEL); - if (!info->data) { - pr_err("unable to allocate memory for data, %d\n", onum); - return 0; - } - - of_fdt_unflatten_tree(info->data, NULL, &info->np_overlay); - if (!info->np_overlay) { - pr_err("unable to unflatten overlay, %d\n", onum); - ret = 0; - goto out_free_data; - } - - info->overlay_id = 0; - ret = of_overlay_apply(info->np_overlay, &info->overlay_id); - if (ret < 0) { - pr_err("of_overlay_apply() (ret=%d), %d\n", ret, onum); - goto out_free_np_overlay; - } - - pr_debug("__dtb_overlay_begin applied, overlay id %d\n", ret); - - goto out; - -out_free_np_overlay: - /* - * info->np_overlay is the unflattened device tree - * It has not been spliced into the live tree. - */ - - /* todo: function to free unflattened device tree */ + ret = of_overlay_fdt_apply(info->dtb_begin, size, &info->overlay_id); + if (overlay_id) + *overlay_id = info->overlay_id; + if (ret < 0) + goto out; -out_free_data: - kfree(info->data); + pr_debug("%s applied\n", overlay_name); out: + if (ret != info->expected_result) + pr_err("of_overlay_fdt_apply() expected %d, ret=%d, %s\n", + info->expected_result, ret, overlay_name); + return (ret == info->expected_result); } @@ -2290,18 +2275,29 @@ static __init void of_unittest_overlay_high_level(void) __of_attach_node_sysfs(np); if (of_symbols) { + struct property *new_prop; for_each_property_of_node(overlay_base_symbols, prop) { - ret = __of_add_property(of_symbols, prop); + + new_prop = __of_prop_dup(prop, GFP_KERNEL); + if (!new_prop) { + unittest(0, "__of_prop_dup() of '%s' from overlay_base node __symbols__", + prop->name); + goto err_unlock; + } + ret = __of_add_property(of_symbols, new_prop); if (ret) { - unittest(0, - "duplicate property '%s' in overlay_base node __symbols__", + if (!strcmp(new_prop->name, "name")) { + /* auto-generated by unflatten */ + ret = 0; + continue; + } + unittest(0, "duplicate property '%s' in overlay_base node __symbols__", prop->name); goto err_unlock; } - ret = __of_add_property_sysfs(of_symbols, prop); + ret = __of_add_property_sysfs(of_symbols, new_prop); if (ret) { - unittest(0, - "unable to add property '%s' in overlay_base node __symbols__ to sysfs", + unittest(0, "unable to add property '%s' in overlay_base node __symbols__ to sysfs", prop->name); goto err_unlock; } @@ -2313,13 +2309,13 @@ static __init void of_unittest_overlay_high_level(void) /* now do the normal overlay usage test */ - unittest(overlay_data_add(1), + unittest(overlay_data_apply("overlay", NULL), "Adding overlay 'overlay' failed\n"); - unittest(overlay_data_add(2), + unittest(overlay_data_apply("overlay_bad_phandle", NULL), "Adding overlay 'overlay_bad_phandle' failed\n"); - unittest(overlay_data_add(3), + unittest(overlay_data_apply("overlay_bad_symbol", NULL), "Adding overlay 'overlay_bad_symbol' failed\n"); return; -- cgit v1.2.3 From db2f3762d609318ebef601dcaf8630032587c13a Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Mon, 12 Feb 2018 00:23:45 -0800 Subject: of: convert unittest overlay devicetree source to sugar syntax The unittest-data overlays have been pulled into proper overlay devicetree source files without changing their format. The next step is to convert them to use sugar syntax instead of hand coding overlay fragments structure. A few of the overlays can not be converted because they test absolute target paths in the overlay fragment. dtc does not generate this type of target: overlay_0.dts overlay_1.dts overlay_12.dts overlay_13.dts Two pre-existing unittest overlay devicetree source files are also converted: overlay_bad_phandle.dts overlay_bad_symbol.dts Signed-off-by: Frank Rowand --- drivers/of/unittest-data/overlay.dts | 101 ++++++++++------------- drivers/of/unittest-data/overlay_10.dts | 39 ++++----- drivers/of/unittest-data/overlay_11.dts | 40 ++++----- drivers/of/unittest-data/overlay_15.dts | 41 ++++----- drivers/of/unittest-data/overlay_2.dts | 11 +-- drivers/of/unittest-data/overlay_3.dts | 11 +-- drivers/of/unittest-data/overlay_4.dts | 23 ++---- drivers/of/unittest-data/overlay_5.dts | 11 +-- drivers/of/unittest-data/overlay_6.dts | 13 +-- drivers/of/unittest-data/overlay_7.dts | 13 +-- drivers/of/unittest-data/overlay_8.dts | 13 +-- drivers/of/unittest-data/overlay_9.dts | 13 +-- drivers/of/unittest-data/overlay_bad_phandle.dts | 23 ++---- drivers/of/unittest-data/overlay_bad_symbol.dts | 25 ++---- drivers/of/unittest-data/tests-overlay.dtsi | 4 +- 15 files changed, 148 insertions(+), 233 deletions(-) (limited to 'drivers') diff --git a/drivers/of/unittest-data/overlay.dts b/drivers/of/unittest-data/overlay.dts index ab5e89b5e27e..3bbc59e922fe 100644 --- a/drivers/of/unittest-data/overlay.dts +++ b/drivers/of/unittest-data/overlay.dts @@ -2,76 +2,63 @@ /dts-v1/; /plugin/; -/ { +&electric_1 { - fragment@0 { - target = <&electric_1>; + status = "okay"; - __overlay__ { - status = "okay"; - - hvac_2: hvac-large-1 { - compatible = "ot,hvac-large"; - heat-range = < 40 75 >; - cool-range = < 65 80 >; - }; - }; + hvac_2: hvac-large-1 { + compatible = "ot,hvac-large"; + heat-range = < 40 75 >; + cool-range = < 65 80 >; }; +}; - fragment@1 { - target = <&rides_1>; - - __overlay__ { - #address-cells = <1>; - #size-cells = <1>; - status = "okay"; - - ride@100 { - #address-cells = <1>; - #size-cells = <1>; - - track@30 { - incline-up = < 48 32 16 >; - }; +&rides_1 { - track@40 { - incline-up = < 47 31 15 >; - }; - }; + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; - ride_200: ride@200 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "ot,ferris-wheel"; - reg = < 0x00000200 0x100 >; - hvac-provider = < &hvac_2 >; - hvac-thermostat = < 27 32 > ; - hvac-zones = < 12 5 >; - hvac-zone-names = "operator", "snack-bar"; - spin-controller = < &spin_ctrl_1 3 >; - spin-rph = < 30 >; - gondolas = < 16 >; - gondola-capacity = < 6 >; + ride@100 { + #address-cells = <1>; + #size-cells = <1>; - ride_200_left: track@10 { - reg = < 0x00000010 0x10 >; - }; + track@30 { + incline-up = < 48 32 16 >; + }; - ride_200_right: track@20 { - reg = < 0x00000020 0x10 >; - }; - }; + track@40 { + incline-up = < 47 31 15 >; }; }; - fragment@2 { - target = <&lights_2>; + ride_200: ride@200 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "ot,ferris-wheel"; + reg = < 0x00000200 0x100 >; + hvac-provider = < &hvac_2 >; + hvac-thermostat = < 27 32 > ; + hvac-zones = < 12 5 >; + hvac-zone-names = "operator", "snack-bar"; + spin-controller = < &spin_ctrl_1 3 >; + spin-rph = < 30 >; + gondolas = < 16 >; + gondola-capacity = < 6 >; + + ride_200_left: track@10 { + reg = < 0x00000010 0x10 >; + }; - __overlay__ { - status = "okay"; - color = "purple", "white", "red", "green"; - rate = < 3 256 >; + ride_200_right: track@20 { + reg = < 0x00000020 0x10 >; }; }; +}; + +&lights_2 { + status = "okay"; + color = "purple", "white", "red", "green"; + rate = < 3 256 >; }; diff --git a/drivers/of/unittest-data/overlay_10.dts b/drivers/of/unittest-data/overlay_10.dts index 445925a10cd3..73993bf23bf8 100644 --- a/drivers/of/unittest-data/overlay_10.dts +++ b/drivers/of/unittest-data/overlay_10.dts @@ -2,33 +2,26 @@ /dts-v1/; /plugin/; -/ { - /* overlay_10 */ - /* overlays 8, 9, 10, 11 application and removal in bad sequence */ +/* overlay_10 */ +/* overlays 8, 9, 10, 11 application and removal in bad sequence */ - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus"; - __overlay__ { +&unittest_test_bus { + /* suppress DTC warning */ + #address-cells = <1>; + #size-cells = <0>; - /* suppress DTC warning */ - #address-cells = <1>; - #size-cells = <0>; + test-unittest10 { + compatible = "unittest"; + status = "okay"; + reg = <10>; - test-unittest10 { - compatible = "unittest"; - status = "okay"; - reg = <10>; + #address-cells = <1>; + #size-cells = <0>; - #address-cells = <1>; - #size-cells = <0>; - - test-unittest101 { - compatible = "unittest"; - status = "okay"; - reg = <1>; - }; - - }; + test-unittest101 { + compatible = "unittest"; + status = "okay"; + reg = <1>; }; }; }; diff --git a/drivers/of/unittest-data/overlay_11.dts b/drivers/of/unittest-data/overlay_11.dts index c1d14f34359e..9a79b253a809 100644 --- a/drivers/of/unittest-data/overlay_11.dts +++ b/drivers/of/unittest-data/overlay_11.dts @@ -2,33 +2,27 @@ /dts-v1/; /plugin/; -/ { - /* overlay_11 */ - /* overlays 8, 9, 10, 11 application and removal in bad sequence */ +/* overlay_11 */ +/* overlays 8, 9, 10, 11 application and removal in bad sequence */ - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus"; - __overlay__ { +&unittest_test_bus { + /* suppress DTC warning */ + #address-cells = <1>; + #size-cells = <0>; - /* suppress DTC warning */ - #address-cells = <1>; - #size-cells = <0>; + test-unittest11 { + compatible = "unittest"; + status = "okay"; + reg = <11>; - test-unittest11 { - compatible = "unittest"; - status = "okay"; - reg = <11>; + #address-cells = <1>; + #size-cells = <0>; - #address-cells = <1>; - #size-cells = <0>; - - test-unittest111 { - compatible = "unittest"; - status = "okay"; - reg = <1>; - }; - - }; + test-unittest111 { + compatible = "unittest"; + status = "okay"; + reg = <1>; }; + }; }; diff --git a/drivers/of/unittest-data/overlay_15.dts b/drivers/of/unittest-data/overlay_15.dts index 44e44c62b739..b98f2514df4b 100644 --- a/drivers/of/unittest-data/overlay_15.dts +++ b/drivers/of/unittest-data/overlay_15.dts @@ -2,33 +2,28 @@ /dts-v1/; /plugin/; -/ { - /* overlay_15 - mux overlay */ +/* overlay_15 - mux overlay */ - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus"; - __overlay__ { - #address-cells = <1>; - #size-cells = <0>; - test-unittest15 { - reg = <11>; - compatible = "unittest-i2c-mux"; - status = "okay"; +&unittest_i2c_test_bus { + #address-cells = <1>; + #size-cells = <0>; + test-unittest15 { + reg = <11>; + compatible = "unittest-i2c-mux"; + status = "okay"; - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; - i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; - test-mux-dev { - reg = <32>; - compatible = "unittest-i2c-dev"; - status = "okay"; - }; - }; + test-mux-dev { + reg = <32>; + compatible = "unittest-i2c-dev"; + status = "okay"; }; }; }; diff --git a/drivers/of/unittest-data/overlay_2.dts b/drivers/of/unittest-data/overlay_2.dts index cf1e4245b7ce..db8684ba89d9 100644 --- a/drivers/of/unittest-data/overlay_2.dts +++ b/drivers/of/unittest-data/overlay_2.dts @@ -2,13 +2,8 @@ /dts-v1/; /plugin/; -/ { - /* overlay_2 - enable using label */ +/* overlay_2 - enable using label */ - fragment@0 { - target = <&unittest2>; - __overlay__ { - status = "okay"; - }; - }; +&unittest2 { + status = "okay"; }; diff --git a/drivers/of/unittest-data/overlay_3.dts b/drivers/of/unittest-data/overlay_3.dts index 158dc44fc20a..40f289e7c237 100644 --- a/drivers/of/unittest-data/overlay_3.dts +++ b/drivers/of/unittest-data/overlay_3.dts @@ -2,13 +2,8 @@ /dts-v1/; /plugin/; -/ { - /* overlay_3 - disable using label */ +/* overlay_3 - disable using label */ - fragment@0 { - target = <&unittest3>; - __overlay__ { - status = "disabled"; - }; - }; +&unittest3 { + status = "disabled"; }; diff --git a/drivers/of/unittest-data/overlay_4.dts b/drivers/of/unittest-data/overlay_4.dts index b4a2e6c6b016..a8a77ddf9abe 100644 --- a/drivers/of/unittest-data/overlay_4.dts +++ b/drivers/of/unittest-data/overlay_4.dts @@ -2,22 +2,17 @@ /dts-v1/; /plugin/; -/ { - /* overlay_4 - test insertion of a full node */ +/* overlay_4 - test insertion of a full node */ - fragment@0 { - target = <&unittestbus>; - __overlay__ { +&unittest_test_bus { - /* suppress DTC warning */ - #address-cells = <1>; - #size-cells = <0>; + /* suppress DTC warning */ + #address-cells = <1>; + #size-cells = <0>; - test-unittest4 { - compatible = "unittest"; - status = "okay"; - reg = <4>; - }; - }; + test-unittest4 { + compatible = "unittest"; + status = "okay"; + reg = <4>; }; }; diff --git a/drivers/of/unittest-data/overlay_5.dts b/drivers/of/unittest-data/overlay_5.dts index 02ad25c1f19c..706f5f1b737c 100644 --- a/drivers/of/unittest-data/overlay_5.dts +++ b/drivers/of/unittest-data/overlay_5.dts @@ -2,13 +2,8 @@ /dts-v1/; /plugin/; -/ { - /* overlay_5 - test overlay apply revert */ +/* overlay_5 - test overlay apply revert */ - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/test-unittest5"; - __overlay__ { - status = "okay"; - }; - }; +&unittest5 { + status = "okay"; }; diff --git a/drivers/of/unittest-data/overlay_6.dts b/drivers/of/unittest-data/overlay_6.dts index a14e965f5497..21a7fa4ca45e 100644 --- a/drivers/of/unittest-data/overlay_6.dts +++ b/drivers/of/unittest-data/overlay_6.dts @@ -2,14 +2,9 @@ /dts-v1/; /plugin/; -/ { - /* overlay_6 */ - /* overlays 6, 7 application and removal in sequence */ +/* overlay_6 */ +/* overlays 6, 7 application and removal in sequence */ - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/test-unittest6"; - __overlay__ { - status = "okay"; - }; - }; +&unittest6 { + status = "okay"; }; diff --git a/drivers/of/unittest-data/overlay_7.dts b/drivers/of/unittest-data/overlay_7.dts index 4bd7e423209c..58ba1bb51b50 100644 --- a/drivers/of/unittest-data/overlay_7.dts +++ b/drivers/of/unittest-data/overlay_7.dts @@ -2,14 +2,9 @@ /dts-v1/; /plugin/; -/ { - /* overlay_7 */ - /* overlays 6, 7 application and removal in sequence */ +/* overlay_7 */ +/* overlays 6, 7 application and removal in sequence */ - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/test-unittest7"; - __overlay__ { - status = "okay"; - }; - }; +&unittest7 { + status = "okay"; }; diff --git a/drivers/of/unittest-data/overlay_8.dts b/drivers/of/unittest-data/overlay_8.dts index 5b21c53945a9..e9718d118e38 100644 --- a/drivers/of/unittest-data/overlay_8.dts +++ b/drivers/of/unittest-data/overlay_8.dts @@ -2,14 +2,9 @@ /dts-v1/; /plugin/; -/ { - /* overlay_8 */ - /* overlays 8, 9, 10, 11 application and removal in bad sequence */ +/* overlay_8 */ +/* overlays 8, 9, 10, 11 application and removal in bad sequence */ - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/test-unittest8"; - __overlay__ { - status = "okay"; - }; - }; +&unittest8 { + status = "okay"; }; diff --git a/drivers/of/unittest-data/overlay_9.dts b/drivers/of/unittest-data/overlay_9.dts index 20ff055a5349..b35e23edae50 100644 --- a/drivers/of/unittest-data/overlay_9.dts +++ b/drivers/of/unittest-data/overlay_9.dts @@ -2,14 +2,9 @@ /dts-v1/; /plugin/; -/ { - /* overlay_9 */ - /* overlays 8, 9, 10, 11 application and removal in bad sequence */ +/* overlay_9 */ +/* overlays 8, 9, 10, 11 application and removal in bad sequence */ - fragment@0 { - target-path = "/testcase-data/overlay-node/test-bus/test-unittest8"; - __overlay__ { - property-foo = "bar"; - }; - }; +&unittest8 { + property-foo = "bar"; }; diff --git a/drivers/of/unittest-data/overlay_bad_phandle.dts b/drivers/of/unittest-data/overlay_bad_phandle.dts index 4d5b99723bad..83b797360318 100644 --- a/drivers/of/unittest-data/overlay_bad_phandle.dts +++ b/drivers/of/unittest-data/overlay_bad_phandle.dts @@ -2,20 +2,13 @@ /dts-v1/; /plugin/; -/ { - - fragment@0 { - target = <&electric_1>; - - __overlay__ { - - // This label should cause an error when the overlay - // is applied. There is already a phandle value - // in the base tree for motor-1. - spin_ctrl_1_conflict: motor-1 { - accelerate = < 3 >; - decelerate = < 5 >; - }; - }; +&electric_1 { + + // This label should cause an error when the overlay + // is applied. There is already a phandle value + // in the base tree for motor-1. + spin_ctrl_1_conflict: motor-1 { + accelerate = < 3 >; + decelerate = < 5 >; }; }; diff --git a/drivers/of/unittest-data/overlay_bad_symbol.dts b/drivers/of/unittest-data/overlay_bad_symbol.dts index 135052ee1517..98c6d1de144a 100644 --- a/drivers/of/unittest-data/overlay_bad_symbol.dts +++ b/drivers/of/unittest-data/overlay_bad_symbol.dts @@ -2,22 +2,15 @@ /dts-v1/; /plugin/; -/ { +&electric_1 { - fragment@0 { - target = <&electric_1>; - - __overlay__ { - - // This label should cause an error when the overlay - // is applied. There is already a symbol hvac_1 - // in the base tree - hvac_1: hvac-medium-2 { - compatible = "ot,hvac-medium"; - heat-range = < 50 75 >; - cool-range = < 60 80 >; - }; - - }; + // This label should cause an error when the overlay + // is applied. There is already a symbol hvac_1 + // in the base tree + hvac_1: hvac-medium-2 { + compatible = "ot,hvac-medium"; + heat-range = < 50 75 >; + cool-range = < 60 80 >; }; + }; diff --git a/drivers/of/unittest-data/tests-overlay.dtsi b/drivers/of/unittest-data/tests-overlay.dtsi index fa2fb43bccac..25cf397b8f6b 100644 --- a/drivers/of/unittest-data/tests-overlay.dtsi +++ b/drivers/of/unittest-data/tests-overlay.dtsi @@ -5,7 +5,7 @@ overlay-node { /* test bus */ - unittestbus: test-bus { + unittest_test_bus: test-bus { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <0>; @@ -70,7 +70,7 @@ reg = <8>; }; - i2c-test-bus { + unittest_i2c_test_bus: i2c-test-bus { compatible = "unittest-i2c-bus"; status = "okay"; reg = <50>; -- cgit v1.2.3 From e547c0031697a0cb5ff7f4a66754fb3e082754ff Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Mon, 12 Feb 2018 00:25:04 -0800 Subject: of: improve reporting invalid overlay target path Errors while developing the patch to create of_overlay_fdt_apply() exposed inadequate error messages to debug problems when overlay devicetree fragment nodes contain an invalid target path. Improve the messages in find_target_node() to remedy this. Signed-off-by: Frank Rowand --- drivers/of/overlay.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index e3d7f69a8333..b930e05d1215 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -488,20 +488,30 @@ static int build_changeset(struct overlay_changeset *ovcs) */ static struct device_node *find_target_node(struct device_node *info_node) { + struct device_node *node; const char *path; u32 val; int ret; ret = of_property_read_u32(info_node, "target", &val); - if (!ret) - return of_find_node_by_phandle(val); + if (!ret) { + node = of_find_node_by_phandle(val); + if (!node) + pr_err("find target, node: %pOF, phandle 0x%x not found\n", + info_node, val); + return node; + } ret = of_property_read_string(info_node, "target-path", &path); - if (!ret) - return of_find_node_by_path(path); + if (!ret) { + node = of_find_node_by_path(path); + if (!node) + pr_err("find target, node: %pOF, path '%s' not found\n", + info_node, path); + return node; + } - pr_err("Failed to find target for node %p (%s)\n", - info_node, info_node->name); + pr_err("find target, node: %pOF, no target property\n", info_node); return NULL; } -- cgit v1.2.3 From 28b2182dad43f6f8fcbd167539a26714fd12bd64 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Mar 2018 11:36:32 +0100 Subject: ahci: Add PCI-id for the Highpoint Rocketraid 644L card Like the Highpoint Rocketraid 642L and cards using a Marvel 88SE9235 controller in general, this RAID card also supports AHCI mode and short of a custom driver, this is the only way to make it work under Linux. Note that even though the card is called to 644L, it has a product-id of 0x0645. Cc: stable@vger.kernel.org BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1534106 Signed-off-by: Hans de Goede Signed-off-by: Tejun Heo Acked-by: Bjorn Helgaas --- drivers/ata/ahci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 355a95a83a34..1ff17799769d 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -550,7 +550,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { .driver_data = board_ahci_yes_fbs }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230), .driver_data = board_ahci_yes_fbs }, - { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642), + { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642), /* highpoint rocketraid 642L */ + .driver_data = board_ahci_yes_fbs }, + { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0645), /* highpoint rocketraid 644L */ .driver_data = board_ahci_yes_fbs }, /* Promise */ -- cgit v1.2.3 From 1903be8222b7c278ca897c129ce477c1dd6403a8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Mar 2018 11:36:33 +0100 Subject: PCI: Add function 1 DMA alias quirk for Highpoint RocketRAID 644L The Highpoint RocketRAID 644L uses a Marvel 88SE9235 controller, as with other Marvel controllers this needs a function 1 DMA alias quirk. Note the RocketRAID 642L uses the same Marvel 88SE9235 controller and already is listed with a function 1 DMA alias quirk. Cc: stable@vger.kernel.org BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1534106 Signed-off-by: Hans de Goede Acked-by: Bjorn Helgaas Signed-off-by: Tejun Heo --- drivers/pci/quirks.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index fc734014206f..b1a3a36073b4 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3901,6 +3901,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9230, quirk_dma_func1_alias); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TTI, 0x0642, quirk_dma_func1_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TTI, 0x0645, + quirk_dma_func1_alias); /* https://bugs.gentoo.org/show_bug.cgi?id=497630 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB388_ESD, -- cgit v1.2.3 From 0a8a1bf17e3af34f1f8d2368916a6327f8b3bfd5 Mon Sep 17 00:00:00 2001 From: Shalom Toledo Date: Thu, 1 Mar 2018 11:37:05 +0100 Subject: mlxsw: spectrum_switchdev: Check success of FDB add operation Until now, we assumed that in case of error when adding FDB entries, the write operation will fail, but this is not the case. Instead, we need to check that the number of entries reported in the response is equal to the number of entries specified in the request. Fixes: 56ade8fe3fe1 ("mlxsw: spectrum: Add initial support for Spectrum ASIC") Reported-by: Ido Schimmel Signed-off-by: Shalom Toledo Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 29 ++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 593ad31be749..161bcdc012f0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -1203,6 +1203,7 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, bool dynamic) { char *sfd_pl; + u8 num_rec; int err; sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); @@ -1212,9 +1213,16 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0); mlxsw_reg_sfd_uc_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic), mac, fid, action, local_port); + num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); - kfree(sfd_pl); + if (err) + goto out; + + if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) + err = -EBUSY; +out: + kfree(sfd_pl); return err; } @@ -1239,6 +1247,7 @@ static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id, bool adding, bool dynamic) { char *sfd_pl; + u8 num_rec; int err; sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); @@ -1249,9 +1258,16 @@ static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id, mlxsw_reg_sfd_uc_lag_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic), mac, fid, MLXSW_REG_SFD_REC_ACTION_NOP, lag_vid, lag_id); + num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); - kfree(sfd_pl); + if (err) + goto out; + + if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) + err = -EBUSY; +out: + kfree(sfd_pl); return err; } @@ -1296,6 +1312,7 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr, u16 fid, u16 mid_idx, bool adding) { char *sfd_pl; + u8 num_rec; int err; sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); @@ -1305,7 +1322,15 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr, mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0); mlxsw_reg_sfd_mc_pack(sfd_pl, 0, addr, fid, MLXSW_REG_SFD_REC_ACTION_NOP, mid_idx); + num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); + if (err) + goto out; + + if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) + err = -EBUSY; + +out: kfree(sfd_pl); return err; } -- cgit v1.2.3 From 77f840e3e5f09c6d7d727e85e6e08276dd813d11 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Fri, 2 Mar 2018 18:41:16 +0100 Subject: ppp: prevent unregistered channels from connecting to PPP units PPP units don't hold any reference on the channels connected to it. It is the channel's responsibility to ensure that it disconnects from its unit before being destroyed. In practice, this is ensured by ppp_unregister_channel() disconnecting the channel from the unit before dropping a reference on the channel. However, it is possible for an unregistered channel to connect to a PPP unit: register a channel with ppp_register_net_channel(), attach a /dev/ppp file to it with ioctl(PPPIOCATTCHAN), unregister the channel with ppp_unregister_channel() and finally connect the /dev/ppp file to a PPP unit with ioctl(PPPIOCCONNECT). Once in this situation, the channel is only held by the /dev/ppp file, which can be released at anytime and free the channel without letting the parent PPP unit know. Then the ppp structure ends up with dangling pointers in its ->channels list. Prevent this scenario by forbidding unregistered channels from connecting to PPP units. This maintains the code logic by keeping ppp_unregister_channel() responsible from disconnecting the channel if necessary and avoids modification on the reference counting mechanism. This issue seems to predate git history (successfully reproduced on Linux 2.6.26 and earlier PPP commits are unrelated). Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller --- drivers/net/ppp/ppp_generic.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 255a5def56e9..fa2a9bdd1866 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -3161,6 +3161,15 @@ ppp_connect_channel(struct channel *pch, int unit) goto outl; ppp_lock(ppp); + spin_lock_bh(&pch->downl); + if (!pch->chan) { + /* Don't connect unregistered channels */ + spin_unlock_bh(&pch->downl); + ppp_unlock(ppp); + ret = -ENOTCONN; + goto outl; + } + spin_unlock_bh(&pch->downl); if (pch->file.hdrlen > ppp->file.hdrlen) ppp->file.hdrlen = pch->file.hdrlen; hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ -- cgit v1.2.3 From 3cc81a9aac43829d86ebf775c388b42d770bc0ac Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 2 Mar 2018 17:29:14 +0800 Subject: virtio-net: re enable XDP_REDIRECT for mergeable buffer XDP_REDIRECT support for mergeable buffer was removed since commit 7324f5399b06 ("virtio_net: disable XDP_REDIRECT in receive_mergeable() case"). This is because we don't reserve enough tailroom for struct skb_shared_info which breaks XDP assumption. So this patch fixes this by reserving enough tailroom and using fixed size of rx buffer. Signed-off-by: Jason Wang Acked-by: Jesper Dangaard Brouer Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 54 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 2d5412317672..23374603e4d9 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -504,6 +504,7 @@ static struct page *xdp_linearize_page(struct receive_queue *rq, page_off += *len; while (--*num_buf) { + int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); unsigned int buflen; void *buf; int off; @@ -518,7 +519,7 @@ static struct page *xdp_linearize_page(struct receive_queue *rq, /* guard against a misconfigured or uncooperative backend that * is sending packet larger than the MTU. */ - if ((page_off + buflen) > PAGE_SIZE) { + if ((page_off + buflen + tailroom) > PAGE_SIZE) { put_page(p); goto err_buf; } @@ -690,6 +691,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, unsigned int truesize; unsigned int headroom = mergeable_ctx_to_headroom(ctx); bool sent; + int err; head_skb = NULL; @@ -701,7 +703,12 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, void *data; u32 act; - /* This happens when rx buffer size is underestimated */ + /* This happens when rx buffer size is underestimated + * or headroom is not enough because of the buffer + * was refilled before XDP is set. This should only + * happen for the first several packets, so we don't + * care much about its performance. + */ if (unlikely(num_buf > 1 || headroom < virtnet_get_headroom(vi))) { /* linearize data for XDP */ @@ -736,9 +743,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, act = bpf_prog_run_xdp(xdp_prog, &xdp); - if (act != XDP_PASS) - ewma_pkt_len_add(&rq->mrg_avg_pkt_len, len); - switch (act) { case XDP_PASS: /* recalculate offset to account for any header @@ -770,6 +774,18 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, goto err_xdp; rcu_read_unlock(); goto xdp_xmit; + case XDP_REDIRECT: + err = xdp_do_redirect(dev, &xdp, xdp_prog); + if (err) { + if (unlikely(xdp_page != page)) + put_page(xdp_page); + goto err_xdp; + } + *xdp_xmit = true; + if (unlikely(xdp_page != page)) + goto err_xdp; + rcu_read_unlock(); + goto xdp_xmit; default: bpf_warn_invalid_xdp_action(act); case XDP_ABORTED: @@ -1013,13 +1029,18 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq, } static unsigned int get_mergeable_buf_len(struct receive_queue *rq, - struct ewma_pkt_len *avg_pkt_len) + struct ewma_pkt_len *avg_pkt_len, + unsigned int room) { const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); unsigned int len; - len = hdr_len + clamp_t(unsigned int, ewma_pkt_len_read(avg_pkt_len), + if (room) + return PAGE_SIZE - room; + + len = hdr_len + clamp_t(unsigned int, ewma_pkt_len_read(avg_pkt_len), rq->min_buf_len, PAGE_SIZE - hdr_len); + return ALIGN(len, L1_CACHE_BYTES); } @@ -1028,21 +1049,27 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, { struct page_frag *alloc_frag = &rq->alloc_frag; unsigned int headroom = virtnet_get_headroom(vi); + unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0; + unsigned int room = SKB_DATA_ALIGN(headroom + tailroom); char *buf; void *ctx; int err; unsigned int len, hole; - len = get_mergeable_buf_len(rq, &rq->mrg_avg_pkt_len); - if (unlikely(!skb_page_frag_refill(len + headroom, alloc_frag, gfp))) + /* Extra tailroom is needed to satisfy XDP's assumption. This + * means rx frags coalescing won't work, but consider we've + * disabled GSO for XDP, it won't be a big issue. + */ + len = get_mergeable_buf_len(rq, &rq->mrg_avg_pkt_len, room); + if (unlikely(!skb_page_frag_refill(len + room, alloc_frag, gfp))) return -ENOMEM; buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset; buf += headroom; /* advance address leaving hole at front of pkt */ get_page(alloc_frag->page); - alloc_frag->offset += len + headroom; + alloc_frag->offset += len + room; hole = alloc_frag->size - alloc_frag->offset; - if (hole < len + headroom) { + if (hole < len + room) { /* To avoid internal fragmentation, if there is very likely not * enough space for another buffer, add the remaining space to * the current buffer. @@ -2578,12 +2605,15 @@ static ssize_t mergeable_rx_buffer_size_show(struct netdev_rx_queue *queue, { struct virtnet_info *vi = netdev_priv(queue->dev); unsigned int queue_index = get_netdev_rx_queue_index(queue); + unsigned int headroom = virtnet_get_headroom(vi); + unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0; struct ewma_pkt_len *avg; BUG_ON(queue_index >= vi->max_queue_pairs); avg = &vi->rq[queue_index].mrg_avg_pkt_len; return sprintf(buf, "%u\n", - get_mergeable_buf_len(&vi->rq[queue_index], avg)); + get_mergeable_buf_len(&vi->rq[queue_index], avg, + SKB_DATA_ALIGN(headroom + tailroom))); } static struct rx_queue_attribute mergeable_rx_buffer_size_attribute = -- cgit v1.2.3 From 12f69661a49446840d742d8feb593ace022d9f66 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 2 Mar 2018 13:49:01 -0800 Subject: hv_netvsc: avoid retry on send during shutdown Change the initialization order so that the device is ready to transmit (ie connect vsp is completed) before setting the internal reference to the device with RCU. This avoids any races on initialization and prevents retry issues on shutdown. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 17e529af79dc..686900d61374 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -852,13 +852,6 @@ int netvsc_send(struct net_device *ndev, if (unlikely(!net_device || net_device->destroy)) return -ENODEV; - /* We may race with netvsc_connect_vsp()/netvsc_init_buf() and get - * here before the negotiation with the host is finished and - * send_section_map may not be allocated yet. - */ - if (unlikely(!net_device->send_section_map)) - return -EAGAIN; - nvchan = &net_device->chan_table[packet->q_idx]; packet->send_buf_index = NETVSC_INVALID_INDEX; packet->cp_partial = false; @@ -866,10 +859,8 @@ int netvsc_send(struct net_device *ndev, /* Send control message directly without accessing msd (Multi-Send * Data) field which may be changed during data packet processing. */ - if (!skb) { - cur_send = packet; - goto send_now; - } + if (!skb) + return netvsc_send_pkt(device, packet, net_device, pb, skb); /* batch packets in send buffer if possible */ msdp = &nvchan->msd; @@ -953,7 +944,6 @@ int netvsc_send(struct net_device *ndev, } } -send_now: if (cur_send) ret = netvsc_send_pkt(device, cur_send, net_device, pb, skb); @@ -1306,11 +1296,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, napi_enable(&net_device->chan_table[0].napi); - /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is - * populated. - */ - rcu_assign_pointer(net_device_ctx->nvdev, net_device); - /* Connect with the NetVsp */ ret = netvsc_connect_vsp(device, net_device, device_info); if (ret != 0) { @@ -1319,6 +1304,11 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, goto close; } + /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is + * populated. + */ + rcu_assign_pointer(net_device_ctx->nvdev, net_device); + return net_device; close: -- cgit v1.2.3 From f4950e4586dfc957e0a28226eeb992ddc049b5a2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 2 Mar 2018 13:49:02 -0800 Subject: hv_netvsc: only wake transmit queue if link is up Don't wake transmit queues if link is not up yet. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index c5584c2d440e..fa6cf18e7719 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -91,12 +91,11 @@ static int netvsc_open(struct net_device *net) return ret; } - netif_tx_wake_all_queues(net); - rdev = nvdev->extension; - - if (!rdev->link_state) + if (!rdev->link_state) { netif_carrier_on(net); + netif_tx_wake_all_queues(net); + } if (vf_netdev) { /* Setting synthetic device up transparently sets -- cgit v1.2.3 From fcfb4a00d1e514e8313277a01ef919de1113025b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 2 Mar 2018 13:49:03 -0800 Subject: hv_netvsc: fix error unwind handling if vmbus_open fails Need to delete NAPI association if vmbus_open fails. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 686900d61374..ff97a85b2e9d 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -1286,7 +1286,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, netvsc_channel_cb, net_device->chan_table); if (ret != 0) { - netif_napi_del(&net_device->chan_table[0].napi); netdev_err(ndev, "unable to open channel: %d\n", ret); goto cleanup; } @@ -1319,6 +1318,7 @@ close: vmbus_close(device->channel); cleanup: + netif_napi_del(&net_device->chan_table[0].napi); free_netvsc_device(&net_device->rcu); return ERR_PTR(ret); -- cgit v1.2.3 From a7483ec0267c69b34e818738da60b392623da94b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 2 Mar 2018 13:49:04 -0800 Subject: hv_netvsc: cancel subchannel setup before halting device Block setup of multiple channels earlier in the teardown process. This avoids possible races between halt and subchannel initialization. Suggested-by: Haiyang Zhang Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/rndis_filter.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index c3ca191fea7f..1cba767c6453 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1340,6 +1340,9 @@ void rndis_filter_device_remove(struct hv_device *dev, { struct rndis_device *rndis_dev = net_dev->extension; + /* Don't try and setup sub channels if about to halt */ + cancel_work_sync(&net_dev->subchan_work); + /* Halt and release the rndis device */ rndis_filter_halt_device(rndis_dev); -- cgit v1.2.3 From d64e38ae690e3337db0d38d9b149a193a1646c4b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 2 Mar 2018 13:49:05 -0800 Subject: hv_netvsc: fix race in napi poll when rescheduling There is a race between napi_reschedule and re-enabling interrupts which could lead to missed host interrrupts. This occurs when interrupts are re-enabled (hv_end_read) and vmbus irq callback (netvsc_channel_cb) has already scheduled NAPI. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index ff97a85b2e9d..4237cedc4f08 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -1207,9 +1207,10 @@ int netvsc_poll(struct napi_struct *napi, int budget) if (send_recv_completions(ndev, net_device, nvchan) == 0 && work_done < budget && napi_complete_done(napi, work_done) && - hv_end_read(&channel->inbound)) { + hv_end_read(&channel->inbound) && + napi_schedule_prep(napi)) { hv_begin_read(&channel->inbound); - napi_reschedule(napi); + __napi_schedule(napi); } /* Driver may overshoot since multiple packets per descriptor */ -- cgit v1.2.3 From 68633edaef655ce94e51088ecef5dd4e1d2f6f34 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 2 Mar 2018 13:49:06 -0800 Subject: hv_netvsc: use napi_schedule_irqoff Since the netvsc_channel_cb is already called in interrupt context from vmbus, there is no need to do irqsave/restore. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 4237cedc4f08..0265d703eb03 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -1233,7 +1233,7 @@ void netvsc_channel_cb(void *context) /* disable interupts from host */ hv_begin_read(rbi); - __napi_schedule(&nvchan->napi); + __napi_schedule_irqoff(&nvchan->napi); } } -- cgit v1.2.3 From b3bf5666a51068ad5ddd89a76ed877101ef3bc16 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 2 Mar 2018 13:49:07 -0800 Subject: hv_netvsc: defer queue selection to VF When VF is used for accelerated networking it will likely have more queues (and different policy) than the synthetic NIC. This patch defers the queue policy to the VF so that all the queues can be used. This impacts workloads like local generate UDP. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index fa6cf18e7719..5299cfb16ce2 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -298,8 +298,19 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, rcu_read_lock(); vf_netdev = rcu_dereference(ndc->vf_netdev); if (vf_netdev) { - txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; - qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping; + const struct net_device_ops *vf_ops = vf_netdev->netdev_ops; + + if (vf_ops->ndo_select_queue) + txq = vf_ops->ndo_select_queue(vf_netdev, skb, + accel_priv, fallback); + else + txq = fallback(vf_netdev, skb); + + /* Record the queue selected by VF so that it can be + * used for common case where VF has more queues than + * the synthetic device. + */ + qdisc_skb_cb(skb)->slave_dev_queue_mapping = txq; } else { txq = netvsc_pick_tx(ndev, skb); } -- cgit v1.2.3 From 009f766ca2383d8788acd65c2c36c51bbfb19470 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 2 Mar 2018 13:49:08 -0800 Subject: hv_netvsc: filter multicast/broadcast The netvsc driver was always enabling all multicast and broadcast even if netdevice flag had not enabled it. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/rndis_filter.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 1cba767c6453..8927c483c217 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -854,15 +854,19 @@ static void rndis_set_multicast(struct work_struct *w) { struct rndis_device *rdev = container_of(w, struct rndis_device, mcast_work); + u32 filter = NDIS_PACKET_TYPE_DIRECTED; + unsigned int flags = rdev->ndev->flags; - if (rdev->ndev->flags & IFF_PROMISC) - rndis_filter_set_packet_filter(rdev, - NDIS_PACKET_TYPE_PROMISCUOUS); - else - rndis_filter_set_packet_filter(rdev, - NDIS_PACKET_TYPE_BROADCAST | - NDIS_PACKET_TYPE_ALL_MULTICAST | - NDIS_PACKET_TYPE_DIRECTED); + if (flags & IFF_PROMISC) { + filter = NDIS_PACKET_TYPE_PROMISCUOUS; + } else { + if (flags & IFF_ALLMULTI) + flags |= NDIS_PACKET_TYPE_ALL_MULTICAST; + if (flags & IFF_BROADCAST) + flags |= NDIS_PACKET_TYPE_BROADCAST; + } + + rndis_filter_set_packet_filter(rdev, filter); } void rndis_filter_update(struct netvsc_device *nvdev) -- cgit v1.2.3 From bee9d41b37ea6b1f860e5bc0989cf1cf1d7e6ab3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 2 Mar 2018 13:49:09 -0800 Subject: hv_netvsc: propagate rx filters to VF The netvsc device should propagate filters to the SR-IOV VF device (if present). The flags also need to be propagated to the VF device as well. This only really matters on local Hyper-V since Azure does not support multiple addresses. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 5299cfb16ce2..cdb78eefab67 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -66,10 +66,36 @@ static int debug = -1; module_param(debug, int, S_IRUGO); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); -static void netvsc_set_multicast_list(struct net_device *net) +static void netvsc_change_rx_flags(struct net_device *net, int change) { - struct net_device_context *net_device_ctx = netdev_priv(net); - struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); + struct net_device_context *ndev_ctx = netdev_priv(net); + struct net_device *vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); + int inc; + + if (!vf_netdev) + return; + + if (change & IFF_PROMISC) { + inc = (net->flags & IFF_PROMISC) ? 1 : -1; + dev_set_promiscuity(vf_netdev, inc); + } + + if (change & IFF_ALLMULTI) { + inc = (net->flags & IFF_ALLMULTI) ? 1 : -1; + dev_set_allmulti(vf_netdev, inc); + } +} + +static void netvsc_set_rx_mode(struct net_device *net) +{ + struct net_device_context *ndev_ctx = netdev_priv(net); + struct net_device *vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); + struct netvsc_device *nvdev = rtnl_dereference(ndev_ctx->nvdev); + + if (vf_netdev) { + dev_uc_sync(vf_netdev, net); + dev_mc_sync(vf_netdev, net); + } rndis_filter_update(nvdev); } @@ -1586,7 +1612,8 @@ static const struct net_device_ops device_ops = { .ndo_open = netvsc_open, .ndo_stop = netvsc_close, .ndo_start_xmit = netvsc_start_xmit, - .ndo_set_rx_mode = netvsc_set_multicast_list, + .ndo_change_rx_flags = netvsc_change_rx_flags, + .ndo_set_rx_mode = netvsc_set_rx_mode, .ndo_change_mtu = netvsc_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = netvsc_set_mac_addr, @@ -1817,6 +1844,11 @@ static void __netvsc_vf_setup(struct net_device *ndev, netdev_warn(vf_netdev, "unable to change mtu to %u\n", ndev->mtu); + /* set multicast etc flags on VF */ + dev_change_flags(vf_netdev, ndev->flags | IFF_SLAVE); + dev_uc_sync(vf_netdev, ndev); + dev_mc_sync(vf_netdev, ndev); + if (netif_running(ndev)) { ret = dev_open(vf_netdev); if (ret) -- cgit v1.2.3 From 9ac79ba9c77d8595157bbdc4327919f8ee062426 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 12 Feb 2018 14:55:13 +0100 Subject: gpio: rcar: Use wakeup_path i.s.o. explicit clock handling Since commit ab82fa7da4dce5c7 ("gpio: rcar: Prevent module clock disable when wake-up is enabled"), when a GPIO is used for wakeup, the GPIO block's module clock (if exists) is manually kept running during system suspend, to make sure the device stays active. However, this explicit clock handling is merely a workaround for a failure to properly communicate wakeup information to the device core. Instead, set the device's power.wakeup_path field, to indicate this device is part of the wakeup path. Depending on the PM Domain's active_wakeup configuration, the genpd core code will keep the device enabled (and the clock running) during system suspend when needed. This allows for the removal of all explicit clock handling code from the driver. Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rcar.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index e76de57dd617..ebaea8b1594b 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -14,7 +14,6 @@ * GNU General Public License for more details. */ -#include #include #include #include @@ -37,10 +36,9 @@ struct gpio_rcar_priv { struct platform_device *pdev; struct gpio_chip gpio_chip; struct irq_chip irq_chip; - struct clk *clk; unsigned int irq_parent; + atomic_t wakeup_path; bool has_both_edge_trigger; - bool needs_clk; }; #define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */ @@ -186,13 +184,10 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on) } } - if (!p->clk) - return 0; - if (on) - clk_enable(p->clk); + atomic_inc(&p->wakeup_path); else - clk_disable(p->clk); + atomic_dec(&p->wakeup_path); return 0; } @@ -330,17 +325,14 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset, struct gpio_rcar_info { bool has_both_edge_trigger; - bool needs_clk; }; static const struct gpio_rcar_info gpio_rcar_info_gen1 = { .has_both_edge_trigger = false, - .needs_clk = false, }; static const struct gpio_rcar_info gpio_rcar_info_gen2 = { .has_both_edge_trigger = true, - .needs_clk = true, }; static const struct of_device_id gpio_rcar_of_table[] = { @@ -403,7 +395,6 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins) ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args); *npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK; p->has_both_edge_trigger = info->has_both_edge_trigger; - p->needs_clk = info->needs_clk; if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) { dev_warn(&p->pdev->dev, @@ -440,16 +431,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) platform_set_drvdata(pdev, p); - p->clk = devm_clk_get(dev, NULL); - if (IS_ERR(p->clk)) { - if (p->needs_clk) { - dev_err(dev, "unable to get clock\n"); - ret = PTR_ERR(p->clk); - goto err0; - } - p->clk = NULL; - } - pm_runtime_enable(dev); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -531,11 +512,24 @@ static int gpio_rcar_remove(struct platform_device *pdev) return 0; } +static int __maybe_unused gpio_rcar_suspend(struct device *dev) +{ + struct gpio_rcar_priv *p = dev_get_drvdata(dev); + + if (atomic_read(&p->wakeup_path)) + device_set_wakeup_path(dev); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, NULL); + static struct platform_driver gpio_rcar_device_driver = { .probe = gpio_rcar_probe, .remove = gpio_rcar_remove, .driver = { .name = "gpio_rcar", + .pm = &gpio_rcar_pm_ops, .of_match_table = of_match_ptr(gpio_rcar_of_table), } }; -- cgit v1.2.3 From c7151602255a36ba07c84fe2baeef846fdb988b8 Mon Sep 17 00:00:00 2001 From: Evgeniy Didin Date: Wed, 28 Feb 2018 14:53:18 +0300 Subject: mmc: dw_mmc: Fix the DTO/CTO timeout overflow calculation for 32-bit systems The commit 9d9491a7da2a ("mmc: dw_mmc: Fix the DTO timeout calculation") and commit 4c2357f57dd5 ("mmc: dw_mmc: Fix the CTO timeout calculation") made changes, which cause multiply overflow for 32-bit systems. The broken timeout calculations leads to unexpected ETIMEDOUT errors and causes stacktrace splat (such as below) during normal data exchange with SD-card. | Running : 4M-check-reassembly-tcp-cmykw2-rotatew2.out -v0 -w1 | - Info: Finished target initialization. | mmcblk0: error -110 transferring data, sector 320544, nr 2048, cmd | response 0x900, card status 0x0 DIV_ROUND_UP_ULL helps to escape usage of __udivdi3() from libgcc and so code gets compiled on all 32-bit platforms as opposed to usage of DIV_ROUND_UP when we may only compile stuff on a very few arches. Lets cast this multiply to u64 type to prevent the overflow. Fixes: 9d9491a7da2a ("mmc: dw_mmc: Fix the DTO timeout calculation") Fixes: 4c2357f57dd5 ("mmc: dw_mmc: Fix the CTO timeout calculation") Tested-by: Vineet Gupta Reported-by: Vineet Gupta # ARC STAR 9001306872 HSDK, sdio: board crashes when copying big files Signed-off-by: Evgeniy Didin Cc: # 4.14 Reviewed-by: Andy Shevchenko Reviewed-by: Douglas Anderson Reviewed-by: Shawn Lin Reviewed-by: Jisheng Zhang Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index d9b4acefed31..545550591389 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -413,7 +413,9 @@ static inline void dw_mci_set_cto(struct dw_mci *host) cto_div = (mci_readl(host, CLKDIV) & 0xff) * 2; if (cto_div == 0) cto_div = 1; - cto_ms = DIV_ROUND_UP(MSEC_PER_SEC * cto_clks * cto_div, host->bus_hz); + + cto_ms = DIV_ROUND_UP_ULL((u64)MSEC_PER_SEC * cto_clks * cto_div, + host->bus_hz); /* add a bit spare time */ cto_ms += 10; @@ -1948,8 +1950,9 @@ static void dw_mci_set_drto(struct dw_mci *host) drto_div = (mci_readl(host, CLKDIV) & 0xff) * 2; if (drto_div == 0) drto_div = 1; - drto_ms = DIV_ROUND_UP(MSEC_PER_SEC * drto_clks * drto_div, - host->bus_hz); + + drto_ms = DIV_ROUND_UP_ULL((u64)MSEC_PER_SEC * drto_clks * drto_div, + host->bus_hz); /* add a bit spare time */ drto_ms += 10; -- cgit v1.2.3 From 1a087f032111a88e826877449dfb93ceb22b78b9 Mon Sep 17 00:00:00 2001 From: Xinyong Date: Fri, 2 Mar 2018 19:20:07 +0800 Subject: usb: gadget: f_fs: Fix use-after-free in ffs_fs_kill_sb() When I debug a kernel crash issue in funcitonfs, found ffs_data.ref overflowed, While functionfs is unmounting, ffs_data is put twice. Commit 43938613c6fd ("drivers, usb: convert ffs_data.ref from atomic_t to refcount_t") can avoid refcount overflow, but that is risk some situations. So no need put ffs data in ffs_fs_kill_sb, already put in ffs_data_closed. The issue can be reproduced in Mediatek mt6763 SoC, ffs for ADB device. KASAN enabled configuration reports use-after-free errro. BUG: KASAN: use-after-free in refcount_dec_and_test+0x14/0xe0 at addr ffffffc0579386a0 Read of size 4 by task umount/4650 ==================================================== BUG kmalloc-512 (Tainted: P W O ): kasan: bad access detected ----------------------------------------------------------------------------- INFO: Allocated in ffs_fs_mount+0x194/0x844 age=22856 cpu=2 pid=566 alloc_debug_processing+0x1ac/0x1e8 ___slab_alloc.constprop.63+0x640/0x648 __slab_alloc.isra.57.constprop.62+0x24/0x34 kmem_cache_alloc_trace+0x1a8/0x2bc ffs_fs_mount+0x194/0x844 mount_fs+0x6c/0x1d0 vfs_kern_mount+0x50/0x1b4 do_mount+0x258/0x1034 INFO: Freed in ffs_data_put+0x25c/0x320 age=0 cpu=3 pid=4650 free_debug_processing+0x22c/0x434 __slab_free+0x2d8/0x3a0 kfree+0x254/0x264 ffs_data_put+0x25c/0x320 ffs_data_closed+0x124/0x15c ffs_fs_kill_sb+0xb8/0x110 deactivate_locked_super+0x6c/0x98 deactivate_super+0xb0/0xbc INFO: Object 0xffffffc057938600 @offset=1536 fp=0x (null) ...... Call trace: [] dump_backtrace+0x0/0x250 [] show_stack+0x14/0x1c [] dump_stack+0xa0/0xc8 [] print_trailer+0x158/0x260 [] object_err+0x3c/0x40 [] kasan_report_error+0x2a8/0x754 [] kasan_report+0x5c/0x60 [] __asan_load4+0x70/0x88 [] refcount_dec_and_test+0x14/0xe0 [] ffs_data_put+0x80/0x320 [] ffs_fs_kill_sb+0xc8/0x110 [] deactivate_locked_super+0x6c/0x98 [] deactivate_super+0xb0/0xbc [] cleanup_mnt+0x64/0xec [] __cleanup_mnt+0x10/0x18 [] task_work_run+0xcc/0x124 [] do_notify_resume+0x60/0x70 [] work_pending+0x10/0x14 Cc: stable@vger.kernel.org Signed-off-by: Xinyong Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index c2592d883f67..d2428a9e8900 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1538,7 +1538,6 @@ ffs_fs_kill_sb(struct super_block *sb) if (sb->s_fs_info) { ffs_release_dev(sb->s_fs_info); ffs_data_closed(sb->s_fs_info); - ffs_data_put(sb->s_fs_info); } } -- cgit v1.2.3 From 1a149e3554e0324a3d551dfb327bdb67b150a320 Mon Sep 17 00:00:00 2001 From: Amelie Delaunay Date: Thu, 1 Mar 2018 11:05:35 +0100 Subject: usb: dwc2: fix STM32F7 USB OTG HS compatible This patch fixes compatible for STM32F7 USB OTG HS and consistently rename dw2_set_params function. The v2 former patch [1] had been acked by Paul Young, but v1 was merged. [1] https://patchwork.kernel.org/patch/9925573/ Fixes: d8fae8b93682 ("usb: dwc2: add support for STM32F7xx USB OTG HS") Signed-off-by: Amelie Delaunay Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/params.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 03fd20f0b496..c4a47496d2fb 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -137,7 +137,7 @@ static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg) p->activate_stm_fs_transceiver = true; } -static void dwc2_set_stm32f7xx_hsotg_params(struct dwc2_hsotg *hsotg) +static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg) { struct dwc2_core_params *p = &hsotg->params; @@ -164,8 +164,8 @@ const struct of_device_id dwc2_of_match_table[] = { { .compatible = "st,stm32f4x9-fsotg", .data = dwc2_set_stm32f4x9_fsotg_params }, { .compatible = "st,stm32f4x9-hsotg" }, - { .compatible = "st,stm32f7xx-hsotg", - .data = dwc2_set_stm32f7xx_hsotg_params }, + { .compatible = "st,stm32f7-hsotg", + .data = dwc2_set_stm32f7_hsotg_params }, {}, }; MODULE_DEVICE_TABLE(of, dwc2_of_match_table); -- cgit v1.2.3 From 5fcdc9d9816266c575ef21586327ba04d7db5c2c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 21 Feb 2018 16:23:31 +0100 Subject: drm/atomic: Call ww_acquire_done after drm_modeset_lock_all After we acquired all generic modeset locks in drm_modeset_lock_all, it's unsafe acquire any other so just mark acquisition as done. Atomic drivers shouldn't use drm_modeset_lock_all. Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20180221152331.9212-1-maarten.lankhorst@linux.intel.com Reviewed-by: Daniel Vetter Acked-by: Harry Wentland --- drivers/gpu/drm/drm_modeset_lock.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 963e23db0fe7..8a5100685875 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -113,6 +113,7 @@ retry: kfree(ctx); return; } + ww_acquire_done(&ctx->ww_ctx); WARN_ON(config->acquire_ctx); -- cgit v1.2.3 From e113d65ae417ae6d9be229649b81d404c47ade79 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 28 Feb 2018 05:47:07 -0500 Subject: media: tegra-cec: reset rx_buf_cnt when start bit detected If a start bit is detected, then reset the receive buffer counter to 0. This ensures that no stale data is in the buffer if a message is broken off midstream due to e.g. a Low Drive condition and then retransmitted. The only Rx interrupts we need to listen to are RX_REGISTER_FULL (i.e. a valid byte was received) and RX_START_BIT_DETECTED (i.e. a new message starts and we need to reset the counter). Signed-off-by: Hans Verkuil Cc: # for v4.15 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/tegra-cec/tegra_cec.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/tegra-cec/tegra_cec.c b/drivers/media/platform/tegra-cec/tegra_cec.c index 92f93a880015..aba488cd0e64 100644 --- a/drivers/media/platform/tegra-cec/tegra_cec.c +++ b/drivers/media/platform/tegra-cec/tegra_cec.c @@ -172,16 +172,13 @@ static irqreturn_t tegra_cec_irq_handler(int irq, void *data) } } - if (status & (TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN | - TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED | - TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED | - TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED)) { + if (status & TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED) { cec_write(cec, TEGRA_CEC_INT_STAT, - (TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN | - TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED | - TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED | - TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED)); - } else if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) { + TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED); + cec->rx_done = false; + cec->rx_buf_cnt = 0; + } + if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) { u32 v; cec_write(cec, TEGRA_CEC_INT_STAT, @@ -255,7 +252,7 @@ static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable) TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED | TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED | TEGRA_CEC_INT_MASK_RX_REGISTER_FULL | - TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN); + TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED); cec_write(cec, TEGRA_CEC_HW_CONTROL, TEGRA_CEC_HWCTRL_TX_RX_MODE); return 0; -- cgit v1.2.3 From 2c27476e398bfd9fa2572ff80a0de16f0becc900 Mon Sep 17 00:00:00 2001 From: Michael Ira Krufky Date: Tue, 16 Jan 2018 22:16:12 -0500 Subject: media: dvb: fix a Kconfig typo drivers/media/Kconfig: typo: replace `with` with `which` Signed-off-by: Michael Ira Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 372c074bb1b9..86c1a190d946 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -151,7 +151,7 @@ config DVB_MMAP select VIDEOBUF2_VMALLOC default n help - This option enables DVB experimental memory-mapped API, with + This option enables DVB experimental memory-mapped API, which reduces the number of context switches to read DVB buffers, as the buffers can use mmap() syscalls. -- cgit v1.2.3 From 669b710e5e30328bc41de88aaab5422913a39074 Mon Sep 17 00:00:00 2001 From: Philippe CORNU Date: Sun, 4 Feb 2018 22:36:24 +0100 Subject: drm/bridge/synopsys: dsi: readl_poll_timeout return value clean up The readl_poll_timeout() return value is 0 in case of success so it is better to detect errors without taking care of the return value sign. Signed-off-by: Philippe Cornu Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20180204213624.18288-1-philippe.cornu@st.com --- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 7bac101c285c..226171a3ece1 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -342,7 +342,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, val, !(val & GEN_CMD_FULL), 1000, CMD_PKT_STATUS_TIMEOUT_US); - if (ret < 0) { + if (ret) { dev_err(dsi->dev, "failed to get available command FIFO\n"); return ret; } @@ -353,7 +353,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, val, (val & mask) == mask, 1000, CMD_PKT_STATUS_TIMEOUT_US); - if (ret < 0) { + if (ret) { dev_err(dsi->dev, "failed to write command FIFO\n"); return ret; } @@ -385,7 +385,7 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, val, !(val & GEN_PLD_W_FULL), 1000, CMD_PKT_STATUS_TIMEOUT_US); - if (ret < 0) { + if (ret) { dev_err(dsi->dev, "failed to get available write payload FIFO\n"); return ret; @@ -721,13 +721,13 @@ static void dw_mipi_dsi_dphy_enable(struct dw_mipi_dsi *dsi) ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, val & PHY_LOCK, 1000, PHY_STATUS_TIMEOUT_US); - if (ret < 0) + if (ret) DRM_DEBUG_DRIVER("failed to wait phy lock state\n"); ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, val & PHY_STOP_STATE_CLK_LANE, 1000, PHY_STATUS_TIMEOUT_US); - if (ret < 0) + if (ret) DRM_DEBUG_DRIVER("failed to wait phy clk lane stop state\n"); } -- cgit v1.2.3 From 745d0bd3af99ccc8c5f5822f808cd133eadad6ac Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Wed, 31 Jan 2018 16:26:27 +0900 Subject: e1000e: Remove Other from EIAC It was reported that emulated e1000e devices in vmware esxi 6.5 Build 7526125 do not link up after commit 4aea7a5c5e94 ("e1000e: Avoid receiver overrun interrupt bursts", v4.15-rc1). Some tracing shows that after e1000e_trigger_lsc() is called, ICR reads out as 0x0 in e1000_msix_other() on emulated e1000e devices. In comparison, on real e1000e 82574 hardware, icr=0x80000004 (_INT_ASSERTED | _LSC) in the same situation. Some experimentation showed that this flaw in vmware e1000e emulation can be worked around by not setting Other in EIAC. This is how it was before 16ecba59bc33 ("e1000e: Do not read ICR in Other interrupt", v4.5-rc1). Fixes: 4aea7a5c5e94 ("e1000e: Avoid receiver overrun interrupt bursts") Signed-off-by: Benjamin Poirier Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 1298b69f990b..153ad406c65e 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1918,6 +1918,8 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data) bool enable = true; icr = er32(ICR); + ew32(ICR, E1000_ICR_OTHER); + if (icr & E1000_ICR_RXO) { ew32(ICR, E1000_ICR_RXO); enable = false; @@ -2040,7 +2042,6 @@ static void e1000_configure_msix(struct e1000_adapter *adapter) hw->hw_addr + E1000_EITR_82574(vector)); else writel(1, hw->hw_addr + E1000_EITR_82574(vector)); - adapter->eiac_mask |= E1000_IMS_OTHER; /* Cause Tx interrupts on every write back */ ivar |= BIT(31); @@ -2265,7 +2266,7 @@ static void e1000_irq_enable(struct e1000_adapter *adapter) if (adapter->msix_entries) { ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574); - ew32(IMS, adapter->eiac_mask | E1000_IMS_LSC); + ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC); } else if (hw->mac.type >= e1000_pch_lpt) { ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER); } else { -- cgit v1.2.3 From 1f0ea19722ef9dfa229a9540f70b8d1c34a98a6a Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Thu, 8 Feb 2018 15:47:12 +0900 Subject: Partial revert "e1000e: Avoid receiver overrun interrupt bursts" This partially reverts commit 4aea7a5c5e940c1723add439f4088844cd26196d. We keep the fix for the first part of the problem (1) described in the log of that commit, that is to read ICR in the other interrupt handler. We remove the fix for the second part of the problem (2), Other interrupt throttling. Bursts of "Other" interrupts may once again occur during rxo (receive overflow) traffic conditions. This is deemed acceptable in the interest of avoiding unforeseen fallout from changes that are not strictly necessary. As discussed, the e1000e driver should be in "maintenance mode". Link: https://www.spinics.net/lists/netdev/msg480675.html Signed-off-by: Benjamin Poirier Acked-by: Alexander Duyck Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 153ad406c65e..3b36efa6228d 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1915,21 +1915,10 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; u32 icr; - bool enable = true; icr = er32(ICR); ew32(ICR, E1000_ICR_OTHER); - if (icr & E1000_ICR_RXO) { - ew32(ICR, E1000_ICR_RXO); - enable = false; - /* napi poll will re-enable Other, make sure it runs */ - if (napi_schedule_prep(&adapter->napi)) { - adapter->total_rx_bytes = 0; - adapter->total_rx_packets = 0; - __napi_schedule(&adapter->napi); - } - } if (icr & E1000_ICR_LSC) { ew32(ICR, E1000_ICR_LSC); hw->mac.get_link_status = true; @@ -1938,7 +1927,7 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (enable && !test_bit(__E1000_DOWN, &adapter->state)) + if (!test_bit(__E1000_DOWN, &adapter->state)) ew32(IMS, E1000_IMS_OTHER); return IRQ_HANDLED; @@ -2708,8 +2697,7 @@ static int e1000e_poll(struct napi_struct *napi, int weight) napi_complete_done(napi, work_done); if (!test_bit(__E1000_DOWN, &adapter->state)) { if (adapter->msix_entries) - ew32(IMS, adapter->rx_ring->ims_val | - E1000_IMS_OTHER); + ew32(IMS, adapter->rx_ring->ims_val); else e1000_irq_enable(adapter); } -- cgit v1.2.3 From 361a954e6a7215de11a6179ad9bdc07d7e394b04 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Thu, 8 Feb 2018 15:47:13 +0900 Subject: e1000e: Fix queue interrupt re-raising in Other interrupt Restores the ICS write for Rx/Tx queue interrupts which was present before commit 16ecba59bc33 ("e1000e: Do not read ICR in Other interrupt", v4.5-rc1) but was not restored in commit 4aea7a5c5e94 ("e1000e: Avoid receiver overrun interrupt bursts", v4.15-rc1). This re-raises the queue interrupts in case the txq or rxq bits were set in ICR and the Other interrupt handler read and cleared ICR before the queue interrupt was raised. Fixes: 4aea7a5c5e94 ("e1000e: Avoid receiver overrun interrupt bursts") Signed-off-by: Benjamin Poirier Acked-by: Alexander Duyck Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 3b36efa6228d..2c9609bee2ae 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1919,6 +1919,9 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data) icr = er32(ICR); ew32(ICR, E1000_ICR_OTHER); + if (icr & adapter->eiac_mask) + ew32(ICS, (icr & adapter->eiac_mask)); + if (icr & E1000_ICR_LSC) { ew32(ICR, E1000_ICR_LSC); hw->mac.get_link_status = true; -- cgit v1.2.3 From 116f4a640b3197401bc93b8adc6c35040308ceff Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Thu, 8 Feb 2018 15:47:14 +0900 Subject: e1000e: Avoid missed interrupts following ICR read The 82574 specification update errata 12 states that interrupts may be missed if ICR is read while INT_ASSERTED is not set. Avoid that problem by setting all bits related to events that can trigger the Other interrupt in IMS. The Other interrupt is raised for such events regardless of whether or not they are set in IMS. However, only when they are set is the INT_ASSERTED bit also set in ICR. By doing this, we ensure that INT_ASSERTED is always set when we read ICR in e1000_msix_other() and steer clear of the errata. This also ensures that ICR will automatically be cleared on read, therefore we no longer need to clear bits explicitly. Signed-off-by: Benjamin Poirier Acked-by: Alexander Duyck Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/defines.h | 21 ++++++++++++++++++++- drivers/net/ethernet/intel/e1000e/netdev.c | 11 ++++------- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index afb7ebe20b24..824fd44e25f0 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -400,6 +400,10 @@ #define E1000_ICR_RXDMT0 0x00000010 /* Rx desc min. threshold (0) */ #define E1000_ICR_RXO 0x00000040 /* Receiver Overrun */ #define E1000_ICR_RXT0 0x00000080 /* Rx timer intr (ring 0) */ +#define E1000_ICR_MDAC 0x00000200 /* MDIO Access Complete */ +#define E1000_ICR_SRPD 0x00010000 /* Small Receive Packet Detected */ +#define E1000_ICR_ACK 0x00020000 /* Receive ACK Frame Detected */ +#define E1000_ICR_MNG 0x00040000 /* Manageability Event Detected */ #define E1000_ICR_ECCER 0x00400000 /* Uncorrectable ECC Error */ /* If this bit asserted, the driver should claim the interrupt */ #define E1000_ICR_INT_ASSERTED 0x80000000 @@ -407,7 +411,7 @@ #define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */ #define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */ #define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ -#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ +#define E1000_ICR_OTHER 0x01000000 /* Other Interrupt */ /* PBA ECC Register */ #define E1000_PBA_ECC_COUNTER_MASK 0xFFF00000 /* ECC counter mask */ @@ -431,12 +435,27 @@ E1000_IMS_RXSEQ | \ E1000_IMS_LSC) +/* These are all of the events related to the OTHER interrupt. + */ +#define IMS_OTHER_MASK ( \ + E1000_IMS_LSC | \ + E1000_IMS_RXO | \ + E1000_IMS_MDAC | \ + E1000_IMS_SRPD | \ + E1000_IMS_ACK | \ + E1000_IMS_MNG) + /* Interrupt Mask Set */ #define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ #define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ #define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* Rx sequence error */ #define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* Rx desc min. threshold */ +#define E1000_IMS_RXO E1000_ICR_RXO /* Receiver Overrun */ #define E1000_IMS_RXT0 E1000_ICR_RXT0 /* Rx timer intr */ +#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO Access Complete */ +#define E1000_IMS_SRPD E1000_ICR_SRPD /* Small Receive Packet */ +#define E1000_IMS_ACK E1000_ICR_ACK /* Receive ACK Frame Detected */ +#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability Event */ #define E1000_IMS_ECCER E1000_ICR_ECCER /* Uncorrectable ECC Error */ #define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */ #define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */ diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 2c9609bee2ae..9fd4050a91ca 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1914,16 +1914,12 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data) struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - u32 icr; - - icr = er32(ICR); - ew32(ICR, E1000_ICR_OTHER); + u32 icr = er32(ICR); if (icr & adapter->eiac_mask) ew32(ICS, (icr & adapter->eiac_mask)); if (icr & E1000_ICR_LSC) { - ew32(ICR, E1000_ICR_LSC); hw->mac.get_link_status = true; /* guard against interrupt when we're going down */ if (!test_bit(__E1000_DOWN, &adapter->state)) @@ -1931,7 +1927,7 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data) } if (!test_bit(__E1000_DOWN, &adapter->state)) - ew32(IMS, E1000_IMS_OTHER); + ew32(IMS, E1000_IMS_OTHER | IMS_OTHER_MASK); return IRQ_HANDLED; } @@ -2258,7 +2254,8 @@ static void e1000_irq_enable(struct e1000_adapter *adapter) if (adapter->msix_entries) { ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574); - ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC); + ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | + IMS_OTHER_MASK); } else if (hw->mac.type >= e1000_pch_lpt) { ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER); } else { -- cgit v1.2.3 From 4e7dc08e57c95673d2edaba8983c3de4dd1f65f5 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Tue, 20 Feb 2018 15:12:00 +0900 Subject: e1000e: Fix check_for_link return value with autoneg off When autoneg is off, the .check_for_link callback functions clear the get_link_status flag and systematically return a "pseudo-error". This means that the link is not detected as up until the next execution of the e1000_watchdog_task() 2 seconds later. Fixes: 19110cfbb34d ("e1000e: Separate signaling for link check/link up") Signed-off-by: Benjamin Poirier Acked-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ich8lan.c | 2 +- drivers/net/ethernet/intel/e1000e/mac.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 31277d3bb7dc..ff308b05d68c 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1602,7 +1602,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) * we have already determined whether we have link or not. */ if (!mac->autoneg) - return -E1000_ERR_CONFIG; + return 1; /* Auto-Neg is enabled. Auto Speed Detection takes care * of MAC speed/duplex configuration. So we only need to diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c index f457c5703d0c..db735644b312 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.c +++ b/drivers/net/ethernet/intel/e1000e/mac.c @@ -450,7 +450,7 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) * we have already determined whether we have link or not. */ if (!mac->autoneg) - return -E1000_ERR_CONFIG; + return 1; /* Auto-Neg is enabled. Auto Speed Detection takes care * of MAC speed/duplex configuration. So we only need to -- cgit v1.2.3 From 423ad7b3cbd1158d080e20119a7a5f93a085a486 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 8 Aug 2017 17:44:48 +0100 Subject: drm/vc4: Advertise supported modifiers for planes The IN_FORMATS blob allows the kernel to advertise to userspace which format/modifier combinations are supported, per plane. Use this to advertise that we support both T_TILED and linear. v2: - Only advertise T_TILED for RGB (Eric) - Actually turn on allow_fb_modifiers (Eric) Signed-off-by: Daniel Stone Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/170828/ --- drivers/gpu/drm/vc4/vc4_kms.c | 1 + drivers/gpu/drm/vc4/vc4_plane.c | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 4256f294c346..ba60153dddb5 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -215,6 +215,7 @@ int vc4_kms_load(struct drm_device *dev) dev->mode_config.funcs = &vc4_mode_funcs; dev->mode_config.preferred_depth = 24; dev->mode_config.async_page_flip = true; + dev->mode_config.allow_fb_modifiers = true; drm_mode_config_reset(dev); diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 61ad955645a5..c4c7af11fec5 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -906,6 +906,32 @@ out: ctx); } +static bool vc4_format_mod_supported(struct drm_plane *plane, + uint32_t format, + uint64_t modifier) +{ + /* Support T_TILING for RGB formats only. */ + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_XRGB1555: + return true; + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV16: + default: + return (modifier == DRM_FORMAT_MOD_LINEAR); + } +} + static const struct drm_plane_funcs vc4_plane_funcs = { .update_plane = vc4_update_plane, .disable_plane = drm_atomic_helper_disable_plane, @@ -914,6 +940,7 @@ static const struct drm_plane_funcs vc4_plane_funcs = { .reset = vc4_plane_reset, .atomic_duplicate_state = vc4_plane_duplicate_state, .atomic_destroy_state = vc4_plane_destroy_state, + .format_mod_supported = vc4_format_mod_supported, }; struct drm_plane *vc4_plane_init(struct drm_device *dev, @@ -925,6 +952,11 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, u32 num_formats = 0; int ret = 0; unsigned i; + static const uint64_t modifiers[] = { + DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID + }; vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), GFP_KERNEL); @@ -945,7 +977,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, ret = drm_universal_plane_init(dev, plane, 0, &vc4_plane_funcs, formats, num_formats, - NULL, type, NULL); + modifiers, type, NULL); drm_plane_helper_add(plane, &vc4_plane_helper_funcs); -- cgit v1.2.3 From d8eb9de42320a0d02bd12118a8ac51d14bcaf5e1 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 24 Feb 2018 13:38:14 +0100 Subject: drm/vc4: Replace long HDMI udelay with usleep_range Since we aren't in atomic context replace this long udelay with a usleep_range. Signed-off-by: Stefan Wahren Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/1519475894-11701-1-git-send-email-stefan.wahren@i2se.com --- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 984501e3f0b0..1a6db291d48b 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -681,7 +681,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) drift & ~VC4_HDMI_FIFO_CTL_RECENTER); HDMI_WRITE(VC4_HDMI_FIFO_CTL, drift | VC4_HDMI_FIFO_CTL_RECENTER); - udelay(1000); + usleep_range(1000, 1100); HDMI_WRITE(VC4_HDMI_FIFO_CTL, drift & ~VC4_HDMI_FIFO_CTL_RECENTER); HDMI_WRITE(VC4_HDMI_FIFO_CTL, -- cgit v1.2.3 From 0bf6718537cf1112cbe2d7c4349188d7e89be90c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 26 Feb 2018 11:05:10 -0500 Subject: drm/amdgpu: used cached pcie gen info for SI (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than querying it every time we need it. Also fixes a crash in VM pass through if there is no root bridge because the cached value fetch already checks this properly. v2: fix includes Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=105244 Acked-by: Christian König Reviewed-by: Rex Zhu Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/si.c | 22 ++++++++-------- drivers/gpu/drm/amd/amdgpu/si_dpm.c | 50 ++++++++++--------------------------- 2 files changed, 23 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index f20c4b7414e8..6e61b56bfbfc 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -31,6 +31,7 @@ #include "amdgpu_uvd.h" #include "amdgpu_vce.h" #include "atom.h" +#include "amd_pcie.h" #include "amdgpu_powerplay.h" #include "sid.h" #include "si_ih.h" @@ -1484,8 +1485,8 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) { struct pci_dev *root = adev->pdev->bus->self; int bridge_pos, gpu_pos; - u32 speed_cntl, mask, current_data_rate; - int ret, i; + u32 speed_cntl, current_data_rate; + int i; u16 tmp16; if (pci_is_root_bus(adev->pdev->bus)) @@ -1497,23 +1498,20 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) if (adev->flags & AMD_IS_APU) return; - ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask); - if (ret != 0) - return; - - if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) + if (!(adev->pm.pcie_gen_mask & (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3))) return; speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >> LC_CURRENT_DATA_RATE_SHIFT; - if (mask & DRM_PCIE_SPEED_80) { + if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) { if (current_data_rate == 2) { DRM_INFO("PCIE gen 3 link speeds already enabled\n"); return; } DRM_INFO("enabling PCIE gen 3 link speeds, disable with amdgpu.pcie_gen2=0\n"); - } else if (mask & DRM_PCIE_SPEED_50) { + } else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) { if (current_data_rate == 1) { DRM_INFO("PCIE gen 2 link speeds already enabled\n"); return; @@ -1529,7 +1527,7 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) if (!gpu_pos) return; - if (mask & DRM_PCIE_SPEED_80) { + if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) { if (current_data_rate != 2) { u16 bridge_cfg, gpu_cfg; u16 bridge_cfg2, gpu_cfg2; @@ -1612,9 +1610,9 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); tmp16 &= ~0xf; - if (mask & DRM_PCIE_SPEED_80) + if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) tmp16 |= 3; - else if (mask & DRM_PCIE_SPEED_50) + else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) tmp16 |= 2; else tmp16 |= 1; diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index 8138053fcef1..8137c02fd16a 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -26,6 +26,7 @@ #include "amdgpu_pm.h" #include "amdgpu_dpm.h" #include "amdgpu_atombios.h" +#include "amd_pcie.h" #include "sid.h" #include "r600_dpm.h" #include "si_dpm.h" @@ -3331,29 +3332,6 @@ static void btc_apply_voltage_delta_rules(struct amdgpu_device *adev, } } -static enum amdgpu_pcie_gen r600_get_pcie_gen_support(struct amdgpu_device *adev, - u32 sys_mask, - enum amdgpu_pcie_gen asic_gen, - enum amdgpu_pcie_gen default_gen) -{ - switch (asic_gen) { - case AMDGPU_PCIE_GEN1: - return AMDGPU_PCIE_GEN1; - case AMDGPU_PCIE_GEN2: - return AMDGPU_PCIE_GEN2; - case AMDGPU_PCIE_GEN3: - return AMDGPU_PCIE_GEN3; - default: - if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == AMDGPU_PCIE_GEN3)) - return AMDGPU_PCIE_GEN3; - else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == AMDGPU_PCIE_GEN2)) - return AMDGPU_PCIE_GEN2; - else - return AMDGPU_PCIE_GEN1; - } - return AMDGPU_PCIE_GEN1; -} - static void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b, u32 *p, u32 *u) { @@ -5028,10 +5006,11 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev, table->ACPIState.levels[0].vddc.index, &table->ACPIState.levels[0].std_vddc); } - table->ACPIState.levels[0].gen2PCIE = (u8)r600_get_pcie_gen_support(adev, - si_pi->sys_pcie_mask, - si_pi->boot_pcie_gen, - AMDGPU_PCIE_GEN1); + table->ACPIState.levels[0].gen2PCIE = + (u8)amdgpu_get_pcie_gen_support(adev, + si_pi->sys_pcie_mask, + si_pi->boot_pcie_gen, + AMDGPU_PCIE_GEN1); if (si_pi->vddc_phase_shed_control) si_populate_phase_shedding_value(adev, @@ -7168,10 +7147,10 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev, pl->vddc = le16_to_cpu(clock_info->si.usVDDC); pl->vddci = le16_to_cpu(clock_info->si.usVDDCI); pl->flags = le32_to_cpu(clock_info->si.ulFlags); - pl->pcie_gen = r600_get_pcie_gen_support(adev, - si_pi->sys_pcie_mask, - si_pi->boot_pcie_gen, - clock_info->si.ucPCIEGen); + pl->pcie_gen = amdgpu_get_pcie_gen_support(adev, + si_pi->sys_pcie_mask, + si_pi->boot_pcie_gen, + clock_info->si.ucPCIEGen); /* patch up vddc if necessary */ ret = si_get_leakage_voltage_from_leakage_index(adev, pl->vddc, @@ -7326,7 +7305,6 @@ static int si_dpm_init(struct amdgpu_device *adev) struct si_power_info *si_pi; struct atom_clock_dividers dividers; int ret; - u32 mask; si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL); if (si_pi == NULL) @@ -7336,11 +7314,9 @@ static int si_dpm_init(struct amdgpu_device *adev) eg_pi = &ni_pi->eg; pi = &eg_pi->rv7xx; - ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask); - if (ret) - si_pi->sys_pcie_mask = 0; - else - si_pi->sys_pcie_mask = mask; + si_pi->sys_pcie_mask = + (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK) >> + CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT; si_pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID; si_pi->boot_pcie_gen = si_get_current_pcie_speed(adev); -- cgit v1.2.3 From 3126bf79586aa0fcd27422af3bba2d0539ee9e18 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Wed, 28 Feb 2018 14:17:03 -0800 Subject: drm/radeon/mkregtable: Delete unused list functions and macros The util mkregtable includes a copy of the kernel API for linked lists, only a small subset of it is used. Delete the unused functions and macros. Reviewed-by: Guenter Roeck Signed-off-by: Matthias Kaehlcke Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/mkregtable.c | 433 ------------------------------------ 1 file changed, 433 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/mkregtable.c b/drivers/gpu/drm/radeon/mkregtable.c index c21d8fa591ef..ba704633b072 100644 --- a/drivers/gpu/drm/radeon/mkregtable.c +++ b/drivers/gpu/drm/radeon/mkregtable.c @@ -43,10 +43,6 @@ struct list_head { struct list_head *next, *prev; }; -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) static inline void INIT_LIST_HEAD(struct list_head *list) { @@ -74,19 +70,6 @@ extern void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next); #endif -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - /** * list_add_tail - add a new entry * @new: new entry to be added @@ -100,250 +83,6 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head) __list_add(new, head->prev, head); } -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head *prev, struct list_head *next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -#ifndef CONFIG_DEBUG_LIST -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = (void *)0xDEADBEEF; - entry->prev = (void *)0xBEEFDEAD; -} -#else -extern void list_del(struct list_head *entry); -#endif - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new) -{ - list_replace(old, new); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -/** - * list_is_singular - tests whether a list has just one entry. - * @head: the list to test. - */ -static inline int list_is_singular(const struct list_head *head) -{ - return !list_empty(head) && (head->next == head->prev); -} - -static inline void __list_cut_position(struct list_head *list, - struct list_head *head, - struct list_head *entry) -{ - struct list_head *new_first = entry->next; - list->next = head->next; - list->next->prev = list; - list->prev = entry; - entry->next = list; - head->next = new_first; - new_first->prev = head; -} - -/** - * list_cut_position - cut a list into two - * @list: a new list to add all removed entries - * @head: a list with entries - * @entry: an entry within head, could be the head itself - * and if so we won't cut the list - * - * This helper moves the initial part of @head, up to and - * including @entry, from @head to @list. You should - * pass on @entry an element you know is on @head. @list - * should be an empty list or a list you do not care about - * losing its data. - * - */ -static inline void list_cut_position(struct list_head *list, - struct list_head *head, - struct list_head *entry) -{ - if (list_empty(head)) - return; - if (list_is_singular(head) && (head->next != entry && head != entry)) - return; - if (entry == head) - INIT_LIST_HEAD(list); - else - __list_cut_position(list, head, entry); -} - -static inline void __list_splice(const struct list_head *list, - struct list_head *prev, struct list_head *next) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - - first->prev = prev; - prev->next = first; - - last->next = next; - next->prev = last; -} - -/** - * list_splice - join two lists, this is designed for stacks - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(const struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head, head->next); -} - -/** - * list_splice_tail - join two lists, each list being a queue - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice_tail(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head->prev, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head, head->next); - INIT_LIST_HEAD(list); - } -} - -/** - * list_splice_tail_init - join two lists and reinitialise the emptied list - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * Each of the lists is a queue. - * The list at @list is reinitialised - */ -static inline void list_splice_tail_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head->prev, head); - INIT_LIST_HEAD(list); - } -} - /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. @@ -353,56 +92,6 @@ static inline void list_splice_tail_init(struct list_head *list, #define list_entry(ptr, type, member) \ container_of(ptr, type, member) -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_head within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; prefetch(pos->next), pos != (head); \ - pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - prefetch(pos->prev), pos != (head); \ - pos = n, n = pos->prev) - /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop cursor. @@ -414,128 +103,6 @@ static inline void list_splice_tail_init(struct list_head *list, &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_head within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Start to iterate over list of given type backwards, continuing after - * the current position. - */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_head within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - struct offset { struct list_head list; unsigned offset; -- cgit v1.2.3 From 57270b8191a9d3d15d8c77287733ba1ce5213937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 23 Jan 2018 19:08:55 +0200 Subject: drm/armada: Construct a temporary crtc state for plane checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As armada isn't an atomic driver trying to pass a non-populated crtc->state to drm_atomic_helper_check_plane_state() will end in tears. Construct a temporary crtc state a la drm_plane_helper_check_update() and pass that instead. For now we just really need crtc_state->enable to be there. Cc: Dave Airlie Cc: Russell King Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180123170857.13818-3-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter Acked-by: Dave Airlie --- drivers/gpu/drm/armada/armada_crtc.c | 6 +++++- drivers/gpu/drm/armada/armada_overlay.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index e2adfbef7d6b..9621ed5d3f98 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1200,13 +1200,17 @@ static int armada_drm_primary_update(struct drm_plane *plane, .crtc_h = crtc_h, .rotation = DRM_MODE_ROTATE_0, }; + struct drm_crtc_state crtc_state = { + .crtc = crtc, + .enable = crtc->enabled, + }; const struct drm_rect clip = { .x2 = crtc->mode.hdisplay, .y2 = crtc->mode.vdisplay, }; int ret; - ret = drm_atomic_helper_check_plane_state(&state, crtc->state, &clip, 0, + ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, &clip, 0, INT_MAX, true, false); if (ret) return ret; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 77b55adaa2ac..825cb642b55e 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -205,6 +205,10 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, .crtc_h = crtc_h, .rotation = DRM_MODE_ROTATE_0, }; + struct drm_crtc_state crtc_state = { + .crtc = crtc, + .enable = crtc->enabled, + }; const struct drm_rect clip = { .x2 = crtc->mode.hdisplay, .y2 = crtc->mode.vdisplay, @@ -215,7 +219,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h); - ret = drm_atomic_helper_check_plane_state(&state, crtc->state, &clip, 0, + ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, &clip, 0, INT_MAX, true, false); if (ret) return ret; -- cgit v1.2.3 From bf817d0cf719d07d642837de00160ad03ec5fe9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 23 Jan 2018 19:08:56 +0200 Subject: drm/armada: Use drm_mode_get_hv_timing() to populate plane clip rectangle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_mode_get_hv_timing() to fill out the plane clip rectangle. Since armada isn't atomic we'll use crtc->enabled and crtc->mode instead of the stuff under crtc_state. Once everyone agrees on how the clip rectangle gets set up we can move the code into drm_atomic_helper_check_plane_state(). Cc: Dave Airlie Cc: Russell King Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180123170857.13818-4-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter Acked-by: Dave Airlie --- drivers/gpu/drm/armada/armada_crtc.c | 9 +++++---- drivers/gpu/drm/armada/armada_overlay.c | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 9621ed5d3f98..fdc34ad4ca62 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1204,12 +1204,13 @@ static int armada_drm_primary_update(struct drm_plane *plane, .crtc = crtc, .enable = crtc->enabled, }; - const struct drm_rect clip = { - .x2 = crtc->mode.hdisplay, - .y2 = crtc->mode.vdisplay, - }; + struct drm_rect clip = {}; int ret; + if (crtc->enabled) + drm_mode_get_hv_timing(&crtc->mode, + &clip.x2, &clip.y2); + ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, &clip, 0, INT_MAX, true, false); if (ret) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 825cb642b55e..4f2a7a6e0fd3 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -209,16 +209,17 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, .crtc = crtc, .enable = crtc->enabled, }; - const struct drm_rect clip = { - .x2 = crtc->mode.hdisplay, - .y2 = crtc->mode.vdisplay, - }; + struct drm_rect clip = {}; int ret; trace_armada_ovl_plane_update(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h); + if (crtc->enabled) + drm_mode_get_hv_timing(&crtc->mode, + &clip.x2, &clip.y2); + ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, &clip, 0, INT_MAX, true, false); if (ret) -- cgit v1.2.3 From 81af63a4af82e739aaa391d1fbb97e02c58ea6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 23 Jan 2018 19:08:57 +0200 Subject: drm: Don't pass clip to drm_atomic_helper_check_plane_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the plane clip rectangle handling into drm_atomic_helper_check_plane_state(). Drivers no longer have to worry about such mundane details. v2: Convert armada, rcar, and sun4i as well v3: Resolve simple_kms_helper conflict Cc: Liviu Dudau Cc: Brian Starkey Cc: Mali DP Maintainers Cc: Daniel Vetter Cc: Gustavo Padovan Cc: Sean Paul Cc: Philipp Zabel Cc: CK Hu Cc: Neil Armstrong Cc: Rob Clark Cc: Ben Skeggs Cc: Laurent Pinchart Cc: Sandy Huang Cc: "Heiko Stübner" Cc: Maxime Ripard Cc: Thierry Reding Cc: VMware Graphics Cc: Sinclair Yeh Cc: Thomas Hellstrom Cc: Shawn Guo Cc: Archit Taneja Cc: linux-amlogic@lists.infradead.org Cc: linux-arm-msm@vger.kernel.org Cc: freedreno@lists.freedesktop.org Cc: nouveau@lists.freedesktop.org Cc: linux-renesas-soc@vger.kernel.org Cc: linux-tegra@vger.kernel.org Cc: Russell King Suggested-by: Daniel Vetter Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Reviewed-by: Thierry Reding Reviewed-by: Archit Taneja #msm Link: https://patchwork.freedesktop.org/patch/msgid/20180123170857.13818-5-ville.syrjala@linux.intel.com Acked-by: Liviu Dudau #hdlcd,malidp Acked-by: Philipp Zabel #imx,mtk Reviewed-by: Laurent Pinchart Reviewed-by: Sinclair Yeh #vmwgfx Acked-by: Neil Armstrong #meson Acked-by: Shawn Guo #zte --- drivers/gpu/drm/arm/hdlcd_crtc.c | 7 +------ drivers/gpu/drm/arm/malidp_planes.c | 7 +------ drivers/gpu/drm/armada/armada_crtc.c | 8 ++------ drivers/gpu/drm/armada/armada_overlay.c | 8 ++------ drivers/gpu/drm/drm_atomic_helper.c | 12 +++++++----- drivers/gpu/drm/drm_plane_helper.c | 11 +++-------- drivers/gpu/drm/drm_simple_kms_helper.c | 4 ---- drivers/gpu/drm/i915/intel_display.c | 12 ------------ drivers/gpu/drm/imx/ipuv3-plane.c | 7 +------ drivers/gpu/drm/mediatek/mtk_drm_plane.c | 7 +------ drivers/gpu/drm/meson/meson_plane.c | 7 +------ drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 14 ++------------ drivers/gpu/drm/nouveau/nv50_display.c | 12 ------------ drivers/gpu/drm/rcar-du/rcar_du_plane.c | 7 +------ drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 7 +------ drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 7 +------ drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 7 +------ drivers/gpu/drm/tegra/plane.c | 7 +------ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 7 +------ drivers/gpu/drm/zte/zx_plane.c | 13 +------------ 20 files changed, 28 insertions(+), 143 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index 877647ef35a9..cf5cbd63ecdf 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -229,7 +229,6 @@ static const struct drm_crtc_helper_funcs hdlcd_crtc_helper_funcs = { static int hdlcd_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { - struct drm_rect clip = { 0 }; struct drm_crtc_state *crtc_state; u32 src_h = state->src_h >> 16; @@ -249,11 +248,7 @@ static int hdlcd_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - - return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + return drm_atomic_helper_check_plane_state(state, crtc_state, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, false, true); diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 2885d69af456..ee32361c87ac 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -141,18 +141,13 @@ static int malidp_se_check_scaling(struct malidp_plane *mp, struct drm_crtc_state *crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc); struct malidp_crtc_state *mc; - struct drm_rect clip = { 0 }; u32 src_w, src_h; int ret; if (!crtc_state) return -EINVAL; - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - - ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + ret = drm_atomic_helper_check_plane_state(state, crtc_state, 0, INT_MAX, true, true); if (ret) return ret; diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index fdc34ad4ca62..03eeee11dd5b 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1203,15 +1203,11 @@ static int armada_drm_primary_update(struct drm_plane *plane, struct drm_crtc_state crtc_state = { .crtc = crtc, .enable = crtc->enabled, + .mode = crtc->mode, }; - struct drm_rect clip = {}; int ret; - if (crtc->enabled) - drm_mode_get_hv_timing(&crtc->mode, - &clip.x2, &clip.y2); - - ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, &clip, 0, + ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, 0, INT_MAX, true, false); if (ret) return ret; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 4f2a7a6e0fd3..c391955009d6 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -208,19 +208,15 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_crtc_state crtc_state = { .crtc = crtc, .enable = crtc->enabled, + .mode = crtc->mode, }; - struct drm_rect clip = {}; int ret; trace_armada_ovl_plane_update(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h); - if (crtc->enabled) - drm_mode_get_hv_timing(&crtc->mode, - &clip.x2, &clip.y2); - - ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, &clip, 0, + ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, 0, INT_MAX, true, false); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index ae3cbfe9e01c..00c78c1c9681 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -699,7 +699,6 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset); * drm_atomic_helper_check_plane_state() - Check plane state for validity * @plane_state: plane state to check * @crtc_state: crtc state to check - * @clip: integer clipping coordinates * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point * @can_position: is it legal to position the plane such that it @@ -719,7 +718,6 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset); */ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, const struct drm_crtc_state *crtc_state, - const struct drm_rect *clip, int min_scale, int max_scale, bool can_position, @@ -729,6 +727,7 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, struct drm_rect *src = &plane_state->src; struct drm_rect *dst = &plane_state->dst; unsigned int rotation = plane_state->rotation; + struct drm_rect clip = {}; int hscale, vscale; WARN_ON(plane_state->crtc && plane_state->crtc != crtc_state->crtc); @@ -764,7 +763,10 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, return -ERANGE; } - plane_state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); + if (crtc_state->enable) + drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2); + + plane_state->visible = drm_rect_clip_scaled(src, dst, &clip, hscale, vscale); drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); @@ -778,10 +780,10 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, */ return 0; - if (!can_position && !drm_rect_equals(dst, clip)) { + if (!can_position && !drm_rect_equals(dst, &clip)) { DRM_DEBUG_KMS("Plane must cover entire CRTC\n"); drm_rect_debug_print("dst: ", dst, false); - drm_rect_debug_print("clip: ", clip, false); + drm_rect_debug_print("clip: ", &clip, false); return -EINVAL; } diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index f1be8cd4e387..f88f68161519 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -106,7 +106,6 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc, * @fb: framebuffer to flip onto plane * @src: source coordinates in 16.16 fixed point * @dst: integer destination coordinates - * @clip: integer clipping coordinates * @rotation: plane rotation * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point @@ -131,7 +130,6 @@ int drm_plane_helper_check_update(struct drm_plane *plane, struct drm_framebuffer *fb, struct drm_rect *src, struct drm_rect *dst, - const struct drm_rect *clip, unsigned int rotation, int min_scale, int max_scale, @@ -157,11 +155,12 @@ int drm_plane_helper_check_update(struct drm_plane *plane, struct drm_crtc_state crtc_state = { .crtc = crtc, .enable = crtc->enabled, + .mode = crtc->mode, }; int ret; ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - clip, min_scale, max_scale, + min_scale, max_scale, can_position, can_update_disabled); if (ret) @@ -239,16 +238,12 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, .x2 = crtc_x + crtc_w, .y2 = crtc_y + crtc_h, }; - const struct drm_rect clip = { - .x2 = crtc->mode.hdisplay, - .y2 = crtc->mode.vdisplay, - }; struct drm_connector **connector_list; int num_connectors, ret; bool visible; ret = drm_plane_helper_check_update(plane, crtc, fb, - &src, &dest, &clip, + &src, &dest, DRM_MODE_ROTATE_0, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 6808f732f285..987a353c7f72 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -128,7 +128,6 @@ static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = { static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *plane_state) { - struct drm_rect clip = { 0 }; struct drm_simple_display_pipe *pipe; struct drm_crtc_state *crtc_state; int ret; @@ -138,7 +137,6 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, &pipe->crtc); ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, - &clip, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, false, true); @@ -148,8 +146,6 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, if (!plane_state->visible) return 0; - drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2); - if (!pipe->funcs || !pipe->funcs->check) return 0; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2dceb4cc5f30..250597e6f580 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9360,18 +9360,12 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state) { const struct drm_framebuffer *fb = plane_state->base.fb; - struct drm_rect clip = {}; int src_x, src_y; u32 offset; int ret; - if (crtc_state->base.enable) - drm_mode_get_hv_timing(&crtc_state->base.mode, - &clip.x2, &clip.y2); - ret = drm_atomic_helper_check_plane_state(&plane_state->base, &crtc_state->base, - &clip, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, true, true); @@ -12806,7 +12800,6 @@ intel_check_primary_plane(struct intel_plane *plane, int min_scale = DRM_PLANE_HELPER_NO_SCALING; int max_scale = DRM_PLANE_HELPER_NO_SCALING; bool can_position = false; - struct drm_rect clip = {}; int ret; if (INTEL_GEN(dev_priv) >= 9) { @@ -12818,13 +12811,8 @@ intel_check_primary_plane(struct intel_plane *plane, can_position = true; } - if (crtc_state->base.enable) - drm_mode_get_hv_timing(&crtc_state->base.mode, - &clip.x2, &clip.y2); - ret = drm_atomic_helper_check_plane_state(&state->base, &crtc_state->base, - &clip, min_scale, max_scale, can_position, true); if (ret) diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 150628293c51..d7e3583e608e 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -351,7 +351,6 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, struct drm_framebuffer *old_fb = old_state->fb; unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba; bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY); - struct drm_rect clip = {}; int hsub, vsub; int ret; @@ -367,11 +366,7 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, if (WARN_ON(!crtc_state)) return -EINVAL; - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - - ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + ret = drm_atomic_helper_check_plane_state(state, crtc_state, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, can_position, true); diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index b5c6eec9a584..2f4b0ffee598 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -91,7 +91,6 @@ static int mtk_plane_atomic_check(struct drm_plane *plane, { struct drm_framebuffer *fb = state->fb; struct drm_crtc_state *crtc_state; - struct drm_rect clip = { 0, }; if (!fb) return 0; @@ -108,11 +107,7 @@ static int mtk_plane_atomic_check(struct drm_plane *plane, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - - return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + return drm_atomic_helper_check_plane_state(state, crtc_state, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, true, true); diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 3801bee1f9e6..c78a3a59f58c 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -49,7 +49,6 @@ static int meson_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { struct drm_crtc_state *crtc_state; - struct drm_rect clip = { 0, }; if (!state->crtc) return 0; @@ -58,11 +57,7 @@ static int meson_plane_atomic_check(struct drm_plane *plane, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - - return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + return drm_atomic_helper_check_plane_state(state, crtc_state, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, true, true); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 98d4d7331767..44fc9fe4737a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -286,7 +286,6 @@ static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state, uint32_t max_width, max_height; bool out_of_bounds = false; uint32_t caps = 0; - struct drm_rect clip = {}; int min_scale, max_scale; int ret; @@ -323,11 +322,7 @@ static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state, min_scale = FRAC_16_16(1, 8); max_scale = FRAC_16_16(8, 1); - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - - ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + ret = drm_atomic_helper_check_plane_state(state, crtc_state, min_scale, max_scale, true, true); if (ret) @@ -471,7 +466,6 @@ static int mdp5_plane_atomic_async_check(struct drm_plane *plane, { struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state); struct drm_crtc_state *crtc_state; - struct drm_rect clip = {}; int min_scale, max_scale; int ret; @@ -502,11 +496,7 @@ static int mdp5_plane_atomic_async_check(struct drm_plane *plane, min_scale = FRAC_16_16(1, 8); max_scale = FRAC_16_16(8, 1); - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - - ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + ret = drm_atomic_helper_check_plane_state(state, crtc_state, min_scale, max_scale, true, true); if (ret) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 1f55b3d80a56..6af3bc483c84 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1143,15 +1143,9 @@ static int nv50_curs_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, struct nv50_head_atom *asyh) { - struct drm_rect clip = {}; int ret; - if (asyh->state.enable) - drm_mode_get_hv_timing(&asyh->state.mode, - &clip.x2, &clip.y2); - ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, - &clip, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, true, true); @@ -1435,18 +1429,12 @@ nv50_base_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, struct nv50_head_atom *asyh) { const struct drm_framebuffer *fb = asyw->state.fb; - struct drm_rect clip = {}; int ret; if (!fb->format->depth) return -EINVAL; - if (asyh->state.enable) - drm_mode_get_hv_timing(&asyh->state.mode, - &clip.x2, &clip.y2); - ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, - &clip, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, false, true); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 5687a94d4cb1..68556bd9dad2 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -572,7 +572,6 @@ int __rcar_du_plane_atomic_check(struct drm_plane *plane, { struct drm_device *dev = plane->dev; struct drm_crtc_state *crtc_state; - struct drm_rect clip = {}; int ret; if (!state->crtc) { @@ -589,11 +588,7 @@ int __rcar_du_plane_atomic_check(struct drm_plane *plane, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - - ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + ret = drm_atomic_helper_check_plane_state(state, crtc_state, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, true, true); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 9f72762532bf..998e65d76bf8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -630,7 +630,6 @@ static int vop_plane_atomic_check(struct drm_plane *plane, struct vop_win *vop_win = to_vop_win(plane); const struct vop_win_data *win = vop_win->data; int ret; - struct drm_rect clip = {}; int min_scale = win->phy->scl ? FRAC_16_16(1, 8) : DRM_PLANE_HELPER_NO_SCALING; int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : @@ -643,11 +642,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane, if (WARN_ON(!crtc_state)) return -EINVAL; - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - - ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + ret = drm_atomic_helper_check_plane_state(state, crtc_state, min_scale, max_scale, true, true); if (ret) diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c index 2f0ccd50b54d..9a540330cb79 100644 --- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c @@ -211,7 +211,6 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane, struct drm_crtc *crtc = state->crtc; struct drm_crtc_state *crtc_state; int min_scale, max_scale; - struct drm_rect clip = {}; if (!crtc) return 0; @@ -220,10 +219,6 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane, if (WARN_ON(!crtc_state)) return -EINVAL; - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - min_scale = DRM_PLANE_HELPER_NO_SCALING; max_scale = DRM_PLANE_HELPER_NO_SCALING; @@ -232,7 +227,7 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane, max_scale = SUN8I_UI_SCALER_SCALE_MAX; } - return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + return drm_atomic_helper_check_plane_state(state, crtc_state, min_scale, max_scale, true, true); } diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c index eb3bf2d7291a..5877f8ef5895 100644 --- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c @@ -239,7 +239,6 @@ static int sun8i_vi_layer_atomic_check(struct drm_plane *plane, struct drm_crtc *crtc = state->crtc; struct drm_crtc_state *crtc_state; int min_scale, max_scale; - struct drm_rect clip = {}; if (!crtc) return 0; @@ -248,10 +247,6 @@ static int sun8i_vi_layer_atomic_check(struct drm_plane *plane, if (WARN_ON(!crtc_state)) return -EINVAL; - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - min_scale = DRM_PLANE_HELPER_NO_SCALING; max_scale = DRM_PLANE_HELPER_NO_SCALING; @@ -260,7 +255,7 @@ static int sun8i_vi_layer_atomic_check(struct drm_plane *plane, max_scale = SUN8I_VI_SCALER_SCALE_MAX; } - return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + return drm_atomic_helper_check_plane_state(state, crtc_state, min_scale, max_scale, true, true); } diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index 7267a01e6f08..a056fbf83b53 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -82,7 +82,6 @@ int tegra_plane_state_add(struct tegra_plane *plane, { struct drm_crtc_state *crtc_state; struct tegra_dc_state *tegra; - struct drm_rect clip = {}; int err; /* Propagate errors from allocation or locking failures. */ @@ -90,12 +89,8 @@ int tegra_plane_state_add(struct tegra_plane *plane, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - /* Check plane state for visibility and calculate clipping bounds */ - err = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + err = drm_atomic_helper_check_plane_state(state, crtc_state, 0, INT_MAX, true, true); if (err < 0) return err; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 1107d6d03506..34ecc27fc30a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -443,17 +443,12 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, { struct drm_crtc_state *crtc_state = NULL; struct drm_framebuffer *new_fb = state->fb; - struct drm_rect clip = {}; int ret; if (state->crtc) crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc); - if (crtc_state && crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - - ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + ret = drm_atomic_helper_check_plane_state(state, crtc_state, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, false, true); diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c index 8e1f34274e24..94545adac50d 100644 --- a/drivers/gpu/drm/zte/zx_plane.c +++ b/drivers/gpu/drm/zte/zx_plane.c @@ -55,7 +55,6 @@ static int zx_vl_plane_atomic_check(struct drm_plane *plane, struct drm_framebuffer *fb = plane_state->fb; struct drm_crtc *crtc = plane_state->crtc; struct drm_crtc_state *crtc_state; - struct drm_rect clip = {}; int min_scale = FRAC_16_16(1, 8); int max_scale = FRAC_16_16(8, 1); @@ -75,12 +74,8 @@ static int zx_vl_plane_atomic_check(struct drm_plane *plane, if (!plane_state->crtc) return -EINVAL; - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - return drm_atomic_helper_check_plane_state(plane_state, crtc_state, - &clip, min_scale, max_scale, + min_scale, max_scale, true, true); } @@ -291,7 +286,6 @@ static int zx_gl_plane_atomic_check(struct drm_plane *plane, struct drm_framebuffer *fb = plane_state->fb; struct drm_crtc *crtc = plane_state->crtc; struct drm_crtc_state *crtc_state; - struct drm_rect clip = {}; if (!crtc || !fb) return 0; @@ -309,12 +303,7 @@ static int zx_gl_plane_atomic_check(struct drm_plane *plane, if (!plane_state->crtc) return -EINVAL; - if (crtc_state->enable) - drm_mode_get_hv_timing(&crtc_state->mode, - &clip.x2, &clip.y2); - return drm_atomic_helper_check_plane_state(plane_state, crtc_state, - &clip, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, false, true); -- cgit v1.2.3 From fd92ac1b4658bd1c9650f720e1094fa29fbfd995 Mon Sep 17 00:00:00 2001 From: Hersen Wu Date: Fri, 9 Feb 2018 16:35:14 -0500 Subject: drm/amd/display: move MST branch initialize to before link training some MST capable scaler doesn't like recieving CLEAR_PAYLOAD_ID_TABLE after link training. move branch initialize to before link training Signed-off-by: Hersen Wu Signed-off-by: Tony Cheng Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 9 +++++++++ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 3 +++ drivers/gpu/drm/amd/display/dc/dm_helpers.h | 7 +++++++ 3 files changed, 19 insertions(+) (limited to 'drivers') 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 9bd142f65f9b..3e157e65d7cd 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 @@ -258,6 +258,15 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( return true; } + +/* + * Clear payload allocation table before enable MST DP link. + */ +void dm_helpers_dp_mst_clear_payload_allocation_table( + struct dc_context *ctx, + const struct dc_link *link) +{} + /* * Polls for ACT (allocation change trigger) handled and sends * ALLOCATE_PAYLOAD message. diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 95955ade4012..f40c9c7aa733 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1311,6 +1311,9 @@ static enum dc_status enable_link_dp_mst( if (link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) return DC_OK; + /* clear payload table */ + dm_helpers_dp_mst_clear_payload_allocation_table(link->ctx, link); + /* set the sink to MST mode before enabling the link */ dp_enable_mst_on_sink(link, true); diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index ab88f07772a3..53d5566f89b8 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -49,6 +49,13 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( struct dp_mst_stream_allocation_table *proposed_table, bool enable); +/* + * Clear payload allocation table before enable MST DP link. + */ +void dm_helpers_dp_mst_clear_payload_allocation_table( + struct dc_context *ctx, + const struct dc_link *link); + /* * Polls for ACT (allocation change trigger) handled and */ -- cgit v1.2.3 From 88ac3ddab12e2b04dca2958e0bc8b90c703e0397 Mon Sep 17 00:00:00 2001 From: Roman Li Date: Fri, 9 Feb 2018 16:57:38 -0500 Subject: drm/amd/display: Fix active dongle hotplug Clean fake sink flag after detecting link on downstream port. Fixing display light-up after "hot-unplug&plug again" downstream of an active dongle. Signed-off-by: Roman Li Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') 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 84f6fe9a448b..3af6f0b0836f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1058,6 +1058,10 @@ static void handle_hpd_rx_irq(void *param) !is_mst_root_connector) { /* Downstream Port status changed. */ if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) { + + if (aconnector->fake_enable) + aconnector->fake_enable = false; + amdgpu_dm_update_connector_after_detect(aconnector); -- cgit v1.2.3 From 11fffe45b76d2849a684f2d769bc76901ba0d301 Mon Sep 17 00:00:00 2001 From: John Barberiz Date: Fri, 9 Feb 2018 17:48:18 -0500 Subject: drm/amd/display: Add passive dongle support for HPD Rearch Add HPD delay timer support to 1. Single/dual link DVI. 2. DP to HDMI passive dongle 3. DP to DVI passive dongle. Signed-off-by: John Barberiz Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 7 +++++-- drivers/gpu/drm/amd/display/dc/dc_link.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index f40c9c7aa733..556b155ba5af 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -2358,11 +2358,14 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) core_dc->hwss.set_avmute(pipe_ctx, enable); } -void dc_link_disable_hpd_filter(struct dc_link *link) +void dc_link_enable_hpd_filter(struct dc_link *link, bool enable) { struct gpio *hpd; - if (!link->is_hpd_filter_disabled) { + if (enable) { + link->is_hpd_filter_disabled = false; + program_hpd_filter(link); + } else { link->is_hpd_filter_disabled = true; /* Obtain HPD handle */ hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index ac0f617b43c9..fb4d9eafdc6e 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -197,7 +197,7 @@ bool dc_link_dp_set_test_pattern( const unsigned char *p_custom_pattern, unsigned int cust_pattern_size); -void dc_link_disable_hpd_filter(struct dc_link *link); +void dc_link_enable_hpd_filter(struct dc_link *link, bool enable); /* * DPCD access interfaces -- cgit v1.2.3 From 086247a4b2fba49800b27807f22bb894cd8363fb Mon Sep 17 00:00:00 2001 From: "Leo (Sunpeng) Li" Date: Mon, 12 Feb 2018 13:20:56 -0500 Subject: drm/amd/display: Use 4096 lut entries Points in the DRM LUT are spaced linearly. Points in hardware are spaced exponentially, with greater density towards 0. To maintain low-end accuracy in hardware when sampling the DRM LUT, more points are needed. However, X doesn't seem to play with legacy LUTs of such size. Therefore, check for legacy lut when updating DC states, and update accordingly. v2: Use a macro for the maximum drm LUT value. v3: Update commit to reflect that this does not map 1-1 to HW Signed-off-by: Leo (Sunpeng) Li Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 4 +- .../drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 77 ++++++++++++++++------ 3 files changed, 61 insertions(+), 22 deletions(-) (limited to 'drivers') 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 3af6f0b0836f..fa7b2fa25e22 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3197,7 +3197,7 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, dm->adev->mode_info.crtcs[crtc_index] = acrtc; drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES, true, MAX_COLOR_LUT_ENTRIES); - drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LUT_ENTRIES); + drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES); return 0; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index aa7df5775545..b68400c1154b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -268,7 +268,9 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc); #define amdgpu_dm_crtc_handle_crc_irq(x) #endif -#define MAX_COLOR_LUT_ENTRIES 256 +#define MAX_COLOR_LUT_ENTRIES 4096 +/* Legacy gamm LUT users such as X doesn't like large LUT sizes */ +#define MAX_COLOR_LEGACY_LUT_ENTRIES 256 void amdgpu_dm_init_color_mod(void); int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 62bb72fe9aa5..e845c511656e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -27,6 +27,8 @@ #include "amdgpu_dm.h" #include "modules/color/color_gamma.h" +#define MAX_DRM_LUT_VALUE 0xFFFF + /* * Initialize the color module. * @@ -47,19 +49,18 @@ void amdgpu_dm_init_color_mod(void) * f(a) = (0xFF00/MAX_COLOR_LUT_ENTRIES-1)a; for integer a in * [0, MAX_COLOR_LUT_ENTRIES) */ -static bool __is_lut_linear(struct drm_color_lut *lut) +static bool __is_lut_linear(struct drm_color_lut *lut, uint32_t size) { int i; - uint32_t max_os = 0xFF00; uint32_t expected; int delta; - for (i = 0; i < MAX_COLOR_LUT_ENTRIES; i++) { + for (i = 0; i < size; i++) { /* All color values should equal */ if ((lut[i].red != lut[i].green) || (lut[i].green != lut[i].blue)) return false; - expected = i * max_os / (MAX_COLOR_LUT_ENTRIES-1); + expected = i * MAX_DRM_LUT_VALUE / (size-1); /* Allow a +/-1 error. */ delta = lut[i].red - expected; @@ -69,6 +70,42 @@ static bool __is_lut_linear(struct drm_color_lut *lut) return true; } +/** + * Convert the drm_color_lut to dc_gamma. The conversion depends on the size + * of the lut - whether or not it's legacy. + */ +static void __drm_lut_to_dc_gamma(struct drm_color_lut *lut, + struct dc_gamma *gamma, + bool is_legacy) +{ + uint32_t r, g, b; + int i; + + if (is_legacy) { + for (i = 0; i < MAX_COLOR_LEGACY_LUT_ENTRIES; i++) { + r = drm_color_lut_extract(lut[i].red, 16); + g = drm_color_lut_extract(lut[i].green, 16); + b = drm_color_lut_extract(lut[i].blue, 16); + + gamma->entries.red[i] = dal_fixed31_32_from_int(r); + gamma->entries.green[i] = dal_fixed31_32_from_int(g); + gamma->entries.blue[i] = dal_fixed31_32_from_int(b); + } + return; + } + + /* else */ + for (i = 0; i < MAX_COLOR_LUT_ENTRIES; i++) { + r = drm_color_lut_extract(lut[i].red, 16); + g = drm_color_lut_extract(lut[i].green, 16); + b = drm_color_lut_extract(lut[i].blue, 16); + + gamma->entries.red[i] = dal_fixed31_32_from_fraction(r, MAX_DRM_LUT_VALUE); + gamma->entries.green[i] = dal_fixed31_32_from_fraction(g, MAX_DRM_LUT_VALUE); + gamma->entries.blue[i] = dal_fixed31_32_from_fraction(b, MAX_DRM_LUT_VALUE); + } +} + /** * amdgpu_dm_set_regamma_lut: Set regamma lut for the given CRTC. * @crtc: amdgpu_dm crtc state @@ -85,11 +122,10 @@ int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc) struct drm_property_blob *blob = crtc->base.gamma_lut; struct dc_stream_state *stream = crtc->stream; struct drm_color_lut *lut; + uint32_t lut_size; struct dc_gamma *gamma; enum dc_transfer_func_type old_type = stream->out_transfer_func->type; - uint32_t r, g, b; - int i; bool ret; if (!blob) { @@ -100,8 +136,9 @@ int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc) } lut = (struct drm_color_lut *)blob->data; + lut_size = blob->length / sizeof(struct drm_color_lut); - if (__is_lut_linear(lut)) { + if (__is_lut_linear(lut, lut_size)) { /* Set to bypass if lut is set to linear */ stream->out_transfer_func->type = TF_TYPE_BYPASS; stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; @@ -112,20 +149,20 @@ int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc) if (!gamma) return -ENOMEM; - gamma->num_entries = MAX_COLOR_LUT_ENTRIES; - gamma->type = GAMMA_RGB_256; - - /* Truncate, and store in dc_gamma for output tf calculation */ - for (i = 0; i < gamma->num_entries; i++) { - r = drm_color_lut_extract(lut[i].red, 16); - g = drm_color_lut_extract(lut[i].green, 16); - b = drm_color_lut_extract(lut[i].blue, 16); - - gamma->entries.red[i] = dal_fixed31_32_from_int(r); - gamma->entries.green[i] = dal_fixed31_32_from_int(g); - gamma->entries.blue[i] = dal_fixed31_32_from_int(b); + gamma->num_entries = lut_size; + if (gamma->num_entries == MAX_COLOR_LEGACY_LUT_ENTRIES) + gamma->type = GAMMA_RGB_256; + else if (gamma->num_entries == MAX_COLOR_LUT_ENTRIES) + gamma->type = GAMMA_CS_TFM_1D; + else { + /* Invalid lut size */ + dc_gamma_release(&gamma); + return -EINVAL; } + /* Convert drm_lut into dc_gamma */ + __drm_lut_to_dc_gamma(lut, gamma, gamma->type == GAMMA_RGB_256); + /* Call color module to translate into something DC understands. Namely * a transfer function. */ @@ -212,7 +249,7 @@ int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state, } lut = (struct drm_color_lut *)blob->data; - if (__is_lut_linear(lut)) { + if (__is_lut_linear(lut, MAX_COLOR_LUT_ENTRIES)) { dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; return 0; -- cgit v1.2.3 From 3d53f424796b05b4dfd287d034357f0e19e36c9e Mon Sep 17 00:00:00 2001 From: Yue Hin Lau Date: Mon, 12 Feb 2018 17:43:19 -0500 Subject: drm/amd/display: update cur_clock correctly within set bandwidth Signed-off-by: Yue Hin Lau Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 29dc37fbdb26..0384aefd79b6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -2054,22 +2054,24 @@ static void dcn10_set_bandwidth( dc->res_pool->display_clock->funcs->set_clock( dc->res_pool->display_clock, context->bw.dcn.calc_clk.dispclk_khz); - dc->current_state->bw.dcn.cur_clk.dispclk_khz = + context->bw.dcn.cur_clk.dispclk_khz = context->bw.dcn.calc_clk.dispclk_khz; } if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_khz > dc->current_state->bw.dcn.cur_clk.dcfclk_khz) { + context->bw.dcn.cur_clk.dcfclk_khz = + context->bw.dcn.calc_clk.dcfclk_khz; smu_req.hard_min_dcefclk_khz = context->bw.dcn.calc_clk.dcfclk_khz; } if (decrease_allowed || context->bw.dcn.calc_clk.fclk_khz > dc->current_state->bw.dcn.cur_clk.fclk_khz) { + context->bw.dcn.cur_clk.fclk_khz = + context->bw.dcn.calc_clk.fclk_khz; smu_req.hard_min_fclk_khz = context->bw.dcn.calc_clk.fclk_khz; } if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz > dc->current_state->bw.dcn.cur_clk.dcfclk_deep_sleep_khz) { - dc->current_state->bw.dcn.calc_clk.dcfclk_deep_sleep_khz = - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz = context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; } @@ -2084,15 +2086,11 @@ static void dcn10_set_bandwidth( /* Decrease in freq is increase in period so opposite comparison for dram_ccm */ if (decrease_allowed || context->bw.dcn.calc_clk.dram_ccm_us < dc->current_state->bw.dcn.cur_clk.dram_ccm_us) { - dc->current_state->bw.dcn.calc_clk.dram_ccm_us = - context->bw.dcn.calc_clk.dram_ccm_us; context->bw.dcn.cur_clk.dram_ccm_us = context->bw.dcn.calc_clk.dram_ccm_us; } if (decrease_allowed || context->bw.dcn.calc_clk.min_active_dram_ccm_us < dc->current_state->bw.dcn.cur_clk.min_active_dram_ccm_us) { - dc->current_state->bw.dcn.calc_clk.min_active_dram_ccm_us = - context->bw.dcn.calc_clk.min_active_dram_ccm_us; context->bw.dcn.cur_clk.min_active_dram_ccm_us = context->bw.dcn.calc_clk.min_active_dram_ccm_us; } -- cgit v1.2.3 From cf1df90f35ac8f8625ef3df1baf8c57fb5582e72 Mon Sep 17 00:00:00 2001 From: Hersen Wu Date: Tue, 13 Feb 2018 16:23:12 -0500 Subject: drm/amd/display: Check DCN PState ASSERT failure [Description] ASIC change debug register definition Signed-off-by: Hersen Wu Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c | 9 ++++++--- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c index eb8317187f30..f984583b9caa 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -100,7 +100,6 @@ bool hubbub1_verify_allow_pstate_change_high( static unsigned int max_sampled_pstate_wait_us; /* data collection */ static bool forced_pstate_allow; /* help with revert wa */ - unsigned int debug_index = 0x7; unsigned int debug_data; unsigned int i; @@ -115,7 +114,9 @@ bool hubbub1_verify_allow_pstate_change_high( forced_pstate_allow = false; } - /* description "3-0: Pipe0 cursor0 QOS + /* RV1: + * dchubbubdebugind, at: 0x7 + * description "3-0: Pipe0 cursor0 QOS * 7-4: Pipe1 cursor0 QOS * 11-8: Pipe2 cursor0 QOS * 15-12: Pipe3 cursor0 QOS @@ -137,7 +138,8 @@ bool hubbub1_verify_allow_pstate_change_high( * 31: SOC pstate change request */ - REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, debug_index); + + REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub->debug_test_index_pstate); for (i = 0; i < pstate_wait_timeout_us; i++) { debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA); @@ -512,5 +514,6 @@ void hubbub1_construct(struct hubbub *hubbub, hubbub->shifts = hubbub_shift; hubbub->masks = hubbub_mask; + hubbub->debug_test_index_pstate = 0x7; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index d5c97844312f..a16e908821a0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -185,6 +185,7 @@ struct hubbub { const struct dcn_hubbub_registers *regs; const struct dcn_hubbub_shift *shifts; const struct dcn_hubbub_mask *masks; + unsigned int debug_test_index_pstate; }; void hubbub1_update_dchub( -- cgit v1.2.3 From e9df99303a7badd1b2a98e8887be9a1b5e955e35 Mon Sep 17 00:00:00 2001 From: Tony Cheng Date: Fri, 2 Feb 2018 01:17:34 -0500 Subject: drm/amd/display: dal 3.1.35 Signed-off-by: Tony Cheng Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 5bb0e5defaf4..a6402c651251 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -38,7 +38,7 @@ #include "inc/compressor.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.1.34" +#define DC_VER "3.1.35" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- cgit v1.2.3 From ea7ea2a8cac1ae7224022b55dcafd51321474ad7 Mon Sep 17 00:00:00 2001 From: Eric Yang Date: Thu, 15 Feb 2018 15:55:31 -0500 Subject: drm/amd/display: fix missing az disable in reset backend Optimization in reset backend skips disable stream if it is already done in dc_stream_set_dpms. However that path does not disable az in order to prevent audio from toggling between internal and external displays. This still need to be done. Signed-off-by: Eric Yang Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 0384aefd79b6..4adb2d311d4e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -536,6 +536,22 @@ static void reset_back_end_for_pipe( /* DPMS may already disable */ if (!pipe_ctx->stream->dpms_off) core_link_disable_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); + else if (pipe_ctx->stream_res.audio) { + /* + * if stream is already disabled outside of commit streams path, + * audio disable was skipped. Need to do it here + */ + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + + if (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); + } + + } + } /* by upper caller loop, parent pipe: pipe0, will be reset last. -- cgit v1.2.3 From f03628232fe93ce7af18079ce69c2dfd4c95d70f Mon Sep 17 00:00:00 2001 From: Yongqiang Sun Date: Wed, 14 Feb 2018 17:12:39 -0500 Subject: drm/amd/display: Clear dmps off for eDP when resume. This patch fixed secondary screen only S4 resume, eDP is unintentionally light up due to incorrect dpms off flag. When entering S4, dpms off flags are set to true via set power state. During resume, eDP is light up by vbios, so the flags should be changed to false to match the real state. By change the flag properly, eDP is able to be turned off properly as per OS request. This change may affect S3/S4 Shut down resume IOIC, need to verify those cases. Signed-off-by: Yongqiang Sun Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 4 ++++ drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 6 ++---- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 556b155ba5af..b7540152005b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -2297,9 +2297,13 @@ void core_link_enable_stream( if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP && core_dc->apply_edp_fast_boot_optimization) { core_dc->apply_edp_fast_boot_optimization = false; + pipe_ctx->stream->dpms_off = false; return; } + if (pipe_ctx->stream->dpms_off) + return; + status = enable_link(state, pipe_ctx); if (status != DC_OK) { 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 0422c72a7579..73e0bcd5ba8f 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 @@ -1320,10 +1320,8 @@ static enum dc_status apply_single_controller_ctx_to_hw( resource_build_info_frame(pipe_ctx); dce110_update_info_frame(pipe_ctx); - if (!pipe_ctx_old->stream) { - if (!pipe_ctx->stream->dpms_off) - core_link_enable_stream(context, pipe_ctx); - } + if (!pipe_ctx_old->stream) + core_link_enable_stream(context, pipe_ctx); pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0; -- cgit v1.2.3 From 85075fa04287dce81397dab75af0992274727b82 Mon Sep 17 00:00:00 2001 From: Xingyue Tao Date: Fri, 16 Feb 2018 16:29:13 -0500 Subject: drm/amd/display: add psr_version to stream Brightness could not be changed for some panels whose DPCD_version is below 1.2 Now psr_version is added into stream, and it copies from the displayTarget's psr_version. It checks if the stream's psr_versio is non-zero and sets the vsc info packet revision now. Signed-off-by: Xingyue Tao Reviewed-by: Tony Cheng Reviewed-by: Anthony Koo Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 2 +- drivers/gpu/drm/amd/display/dc/dc_stream.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index ce0e9e76eb35..48709d4b5627 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -2436,7 +2436,7 @@ static void set_vsc_info_packet( unsigned int i; /*VSC packet set to 2 when DP revision >= 1.2*/ - if (stream->sink->link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { + if (stream->psr_version != 0) { vscPacketRevision = 2; } diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 78a2bbe0b272..f44cd4d87b79 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -70,7 +70,8 @@ struct dc_stream_state { bool ignore_msa_timing_param; /* TODO: custom INFO packets */ /* TODO: ABM info (DMCU) */ - /* TODO: PSR info */ + /* PSR info */ + unsigned char psr_version; /* TODO: CEA VIC */ /* from core_stream struct */ -- cgit v1.2.3 From 94405cf63884e364ec560d99af47084cb1b47b5f Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Fri, 16 Feb 2018 14:04:16 -0500 Subject: drm/amd/display: Update Link Training Fallback logic [Description] When CR fails to minimum link rate, we should reduce lane count to the number lowest cr_done lanes. [Code Review] Jun Lei Signed-off-by: Wenjing Liu Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 98 ++++++++++++++++------ drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c | 1 + .../drm/amd/display/include/link_service_types.h | 5 +- 3 files changed, 79 insertions(+), 25 deletions(-) (limited to 'drivers') 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 604fb0171ee3..4c21da54a9d5 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 @@ -709,6 +709,22 @@ static enum hw_dp_training_pattern get_supported_tp(struct dc_link *link) return HW_DP_TRAINING_PATTERN_2; } +static enum link_training_result get_cr_failure(enum dc_lane_count ln_count, + union lane_status *dpcd_lane_status) +{ + enum link_training_result result = LINK_TRAINING_SUCCESS; + + if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0) + result = LINK_TRAINING_CR_FAIL_LANE0; + else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0) + result = LINK_TRAINING_CR_FAIL_LANE1; + else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0) + result = LINK_TRAINING_CR_FAIL_LANE23; + else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0) + result = LINK_TRAINING_CR_FAIL_LANE23; + return result; +} + static enum link_training_result perform_channel_equalization_sequence( struct dc_link *link, struct link_training_settings *lt_settings) @@ -771,7 +787,7 @@ static enum link_training_result perform_channel_equalization_sequence( } -static bool perform_clock_recovery_sequence( +static enum link_training_result perform_clock_recovery_sequence( struct dc_link *link, struct link_training_settings *lt_settings) { @@ -846,11 +862,11 @@ static bool perform_clock_recovery_sequence( /* 5. check CR done*/ if (is_cr_done(lane_count, dpcd_lane_status)) - return true; + return LINK_TRAINING_SUCCESS; /* 6. max VS reached*/ if (is_max_vs_reached(lt_settings)) - return false; + break; /* 7. same voltage*/ /* Note: VS same for all lanes, @@ -876,13 +892,13 @@ static bool perform_clock_recovery_sequence( } - return false; + return get_cr_failure(lane_count, dpcd_lane_status); } -static inline bool perform_link_training_int( +static inline enum link_training_result perform_link_training_int( struct dc_link *link, struct link_training_settings *lt_settings, - bool status) + enum link_training_result status) { union lane_count_set lane_count_set = { {0} }; union dpcd_training_pattern dpcd_pattern = { {0} }; @@ -903,9 +919,9 @@ static inline bool perform_link_training_int( get_supported_tp(link) == HW_DP_TRAINING_PATTERN_4) return status; - if (status && + if (status == LINK_TRAINING_SUCCESS && perform_post_lt_adj_req_sequence(link, lt_settings) == false) - status = false; + status = LINK_TRAINING_LQA_FAIL; lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count; lane_count_set.bits.ENHANCED_FRAMING = 1; @@ -928,6 +944,8 @@ enum link_training_result dc_link_dp_perform_link_training( enum link_training_result status = LINK_TRAINING_SUCCESS; char *link_rate = "Unknown"; + char *lt_result = "Unknown"; + struct link_training_settings lt_settings; memset(<_settings, '\0', sizeof(lt_settings)); @@ -951,22 +969,16 @@ enum link_training_result dc_link_dp_perform_link_training( /* 2. perform link training (set link training done * to false is done as well)*/ - if (!perform_clock_recovery_sequence(link, <_settings)) { - status = LINK_TRAINING_CR_FAIL; - } else { + status = perform_clock_recovery_sequence(link, <_settings); + if (status == LINK_TRAINING_SUCCESS) { status = perform_channel_equalization_sequence(link, <_settings); } if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) { - if (!perform_link_training_int(link, + status = perform_link_training_int(link, <_settings, - status == LINK_TRAINING_SUCCESS)) { - /* the next link training setting in this case - * would be the same as CR failure case. - */ - status = LINK_TRAINING_CR_FAIL; - } + status); } /* 6. print status message*/ @@ -991,13 +1003,37 @@ enum link_training_result dc_link_dp_perform_link_training( break; } + switch (status) { + case LINK_TRAINING_SUCCESS: + lt_result = "pass"; + break; + case LINK_TRAINING_CR_FAIL_LANE0: + lt_result = "CR failed lane0"; + break; + case LINK_TRAINING_CR_FAIL_LANE1: + lt_result = "CR failed lane1"; + break; + case LINK_TRAINING_CR_FAIL_LANE23: + lt_result = "CR failed lane23"; + break; + case LINK_TRAINING_EQ_FAIL_CR: + lt_result = "CR failed in EQ"; + break; + case LINK_TRAINING_EQ_FAIL_EQ: + lt_result = "EQ failed"; + break; + case LINK_TRAINING_LQA_FAIL: + lt_result = "LQA failed"; + break; + default: + break; + } + /* Connectivity log: link training */ CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d", link_rate, lt_settings.link_settings.lane_count, - (status == LINK_TRAINING_SUCCESS) ? "pass" : - ((status == LINK_TRAINING_CR_FAIL) ? "CR failed" : - "EQ failed"), + lt_result, lt_settings.lane_settings[0].VOLTAGE_SWING, lt_settings.lane_settings[0].PRE_EMPHASIS); @@ -1115,6 +1151,7 @@ bool dp_hbr_verify_link_cap( dp_cs_id, cur); + if (skip_link_training) success = true; else { @@ -1279,7 +1316,10 @@ static bool decide_fallback_link_setting( return false; switch (training_result) { - case LINK_TRAINING_CR_FAIL: + case LINK_TRAINING_CR_FAIL_LANE0: + case LINK_TRAINING_CR_FAIL_LANE1: + case LINK_TRAINING_CR_FAIL_LANE23: + case LINK_TRAINING_LQA_FAIL: { if (!reached_minimum_link_rate (current_link_setting->link_rate)) { @@ -1290,8 +1330,18 @@ static bool decide_fallback_link_setting( (current_link_setting->lane_count)) { current_link_setting->link_rate = initial_link_settings.link_rate; - current_link_setting->lane_count = - reduce_lane_count( + if (training_result == LINK_TRAINING_CR_FAIL_LANE0) + return false; + else if (training_result == LINK_TRAINING_CR_FAIL_LANE1) + current_link_setting->lane_count = + LANE_COUNT_ONE; + else if (training_result == + LINK_TRAINING_CR_FAIL_LANE23) + current_link_setting->lane_count = + LANE_COUNT_TWO; + else + current_link_setting->lane_count = + reduce_lane_count( current_link_setting->lane_count); } else { return false; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c index bae9b0587e12..7c866a7d5e77 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c @@ -279,6 +279,7 @@ void dp_retrain_link_dp_test(struct dc_link *link, for (i = 0; i < MAX_PIPES; i++) { if (pipes[i].stream != NULL && + !pipes[i].top_pipe && pipes[i].stream->sink != NULL && pipes[i].stream->sink->link != NULL && pipes[i].stream_res.stream_enc != NULL && diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h index adea1a59f620..80f0d93cfd94 100644 --- a/drivers/gpu/drm/amd/display/include/link_service_types.h +++ b/drivers/gpu/drm/amd/display/include/link_service_types.h @@ -58,11 +58,14 @@ enum { enum link_training_result { LINK_TRAINING_SUCCESS, - LINK_TRAINING_CR_FAIL, + LINK_TRAINING_CR_FAIL_LANE0, + LINK_TRAINING_CR_FAIL_LANE1, + LINK_TRAINING_CR_FAIL_LANE23, /* CR DONE bit is cleared during EQ step */ LINK_TRAINING_EQ_FAIL_CR, /* other failure during EQ step */ LINK_TRAINING_EQ_FAIL_EQ, + LINK_TRAINING_LQA_FAIL, }; struct link_training_settings { -- cgit v1.2.3 From 8acad1a18a78b5ec09b8a02eb26e6ded1404e8b0 Mon Sep 17 00:00:00 2001 From: "Leo (Sunpeng) Li" Date: Tue, 20 Feb 2018 13:30:47 -0500 Subject: drm/amd/display: Add regamma lut write mask to SOC base Mask and shift values for DCP0_REGAMMA_LUT_WRITE_EN_MASK were missing from XFM_COMMON_MASK_SH_LIST_SOC_BASE. Add it. Signed-off-by: Leo (Sunpeng) Li Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dce_transform.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.h b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.h index bfc94b4927b9..948281d8b6af 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.h @@ -248,6 +248,7 @@ XFM_SF(DCP0_REGAMMA_CNTLA_REGION_0_1, REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, mask_sh),\ XFM_SF(DCP0_REGAMMA_CNTLA_REGION_0_1, REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\ XFM_SF(DCP0_REGAMMA_CONTROL, GRPH_REGAMMA_MODE, mask_sh),\ + XFM_SF(DCP0_REGAMMA_LUT_WRITE_EN_MASK, REGAMMA_LUT_WRITE_EN_MASK, mask_sh),\ XFM_SF(SCL0_SCL_MODE, SCL_MODE, mask_sh), \ XFM_SF(SCL0_SCL_TAP_CONTROL, SCL_H_NUM_OF_TAPS, mask_sh), \ XFM_SF(SCL0_SCL_TAP_CONTROL, SCL_V_NUM_OF_TAPS, mask_sh), \ -- cgit v1.2.3 From 0e5916ffb8b1f0158651f5867c150ceea3d06991 Mon Sep 17 00:00:00 2001 From: Shirish S Date: Tue, 20 Feb 2018 14:34:16 +0530 Subject: drm/amd/display: allocate fbc buffer in AMDGPU_GEM_DOMAIN_GTT Currently the FBC buffer is allocated in VRAM, since VRAM usage is dedicatedly for scanouts, by allocating FBC back buffer in GTT shall help in conserving VRAM for other purposes. Signed-off-by: Shirish S Reviewed-by: Charlene Liu Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') 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 fa7b2fa25e22..92fe2111e774 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -374,7 +374,7 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector) if (max_size) { int r = amdgpu_bo_create_kernel(adev, max_size * 4, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, &compressor->bo_ptr, + AMDGPU_GEM_DOMAIN_GTT, &compressor->bo_ptr, &compressor->gpu_addr, &compressor->cpu_addr); if (r) -- cgit v1.2.3 From 8ff15a8fcc5862c1edfc0d149aaafaf35fa3569f Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Wed, 17 Jan 2018 17:40:16 -0500 Subject: drm/amd/display: Update DCN OPTC registers Signed-off-by: Dmytro Laktyushkin Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 4 +++- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 4adb2d311d4e..7a1b2deaf3d7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1584,6 +1584,7 @@ static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); } + static void update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct hubp *hubp = pipe_ctx->plane_res.hubp; @@ -1819,8 +1820,9 @@ static void program_all_pipe_in_tree( dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); } - if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) + if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) { program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); + } } static void dcn10_pplib_apply_display_requirements( diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index 014543235df8..d25e7bf0d0d7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -83,6 +83,8 @@ struct dcn_optc_registers { + uint32_t OTG_GLOBAL_CONTROL1; + uint32_t OTG_GLOBAL_CONTROL2; uint32_t OTG_VERT_SYNC_CONTROL; uint32_t OTG_MASTER_UPDATE_MODE; uint32_t OTG_GSL_CONTROL; @@ -126,6 +128,7 @@ struct dcn_optc_registers { uint32_t OTG_VERTICAL_INTERRUPT2_POSITION; uint32_t OPTC_INPUT_CLOCK_CONTROL; uint32_t OPTC_DATA_SOURCE_SELECT; + uint32_t OPTC_MEMORY_CONFIG; uint32_t OPTC_INPUT_GLOBAL_CONTROL; uint32_t CONTROL; uint32_t OTG_GSL_WINDOW_X; @@ -325,10 +328,9 @@ struct dcn_optc_registers { type OPTC_INPUT_CLK_EN;\ type OPTC_INPUT_CLK_ON;\ type OPTC_INPUT_CLK_GATE_DIS;\ - type OPTC_SRC_SEL;\ - type OPTC_SEG0_SRC_SEL;\ type OPTC_UNDERFLOW_OCCURRED_STATUS;\ type OPTC_UNDERFLOW_CLEAR;\ + type OPTC_SRC_SEL;\ type VTG0_ENABLE;\ type VTG0_FP2;\ type VTG0_VCOUNT_INIT;\ -- cgit v1.2.3 From f553e6810259d8bd31a4b9ac3001cfcde7f8fb7e Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Mon, 12 Feb 2018 15:19:20 -0500 Subject: drm/amd/display: add per pipe dppclk v2: Fix commit title Signed-off-by: Dmytro Laktyushkin Reviewed-by: Tony Cheng Acked-by: Harry Wentland Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 2 +- drivers/gpu/drm/amd/display/dc/core/dc_debug.c | 13 +++++++------ drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c | 6 ++---- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 9 +++++---- drivers/gpu/drm/amd/display/dc/inc/core_types.h | 15 +++++++++++++-- 5 files changed, 28 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index c9aa686d16b9..e4d8a8dbc5ef 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -996,7 +996,7 @@ bool dcn_validate_bandwidth( dc->debug.min_disp_clk_khz; } - context->bw.dcn.calc_clk.dppclk_div = (int)(v->dispclk_dppclk_ratio) == 2; + context->bw.dcn.calc_clk.max_dppclk_khz = (int)(v->dppclk * 1000); for (i = 0, input_idx = 0; i < pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index 1babac07bcc9..c15565092ca8 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -361,21 +361,22 @@ void context_clock_trace( struct dc *core_dc = dc; struct dal_logger *logger = core_dc->ctx->logger; - CLOCK_TRACE("Current: dispclk_khz:%d dppclk_div:%d dcfclk_khz:%d\n" - "dcfclk_deep_sleep_khz:%d fclk_khz:%d\n" + CLOCK_TRACE("Current: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" + "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n" "dram_ccm_us:%d min_active_dram_ccm_us:%d\n", context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.dppclk_div, + context->bw.dcn.calc_clk.max_dppclk_khz, context->bw.dcn.calc_clk.dcfclk_khz, context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, context->bw.dcn.calc_clk.fclk_khz, + context->bw.dcn.calc_clk.socclk_khz, context->bw.dcn.calc_clk.dram_ccm_us, context->bw.dcn.calc_clk.min_active_dram_ccm_us); - CLOCK_TRACE("Calculated: dispclk_khz:%d dppclk_div:%d dcfclk_khz:%d\n" - "dcfclk_deep_sleep_khz:%d fclk_khz:%d\n" + CLOCK_TRACE("Calculated: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" + "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n" "dram_ccm_us:%d min_active_dram_ccm_us:%d\n", context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.dppclk_div, + context->bw.dcn.calc_clk.max_dppclk_khz, context->bw.dcn.calc_clk.dcfclk_khz, context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, context->bw.dcn.calc_clk.fclk_khz, 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 8725cab9ec00..f0b798930b51 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -432,14 +432,12 @@ void dpp1_dppclk_control( struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); if (enable) { - if (dpp->tf_mask->DPPCLK_RATE_CONTROL) { + if (dpp->tf_mask->DPPCLK_RATE_CONTROL) REG_UPDATE_2(DPP_CONTROL, DPPCLK_RATE_CONTROL, dppclk_div, DPP_CLOCK_ENABLE, 1); - } else { - ASSERT(dppclk_div == false); + else REG_UPDATE(DPP_CONTROL, DPP_CLOCK_ENABLE, 1); - } } else REG_UPDATE(DPP_CONTROL, DPP_CLOCK_ENABLE, 0); } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 7a1b2deaf3d7..759e925439ce 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1684,12 +1684,13 @@ static void update_dchubp_dpp( if (plane_state->update_flags.bits.full_update) { dpp->funcs->dpp_dppclk_control( dpp, - context->bw.dcn.calc_clk.dppclk_div, + context->bw.dcn.calc_clk.max_dppclk_khz < + context->bw.dcn.calc_clk.dispclk_khz, true); - dc->current_state->bw.dcn.cur_clk.dppclk_div = - context->bw.dcn.calc_clk.dppclk_div; - context->bw.dcn.cur_clk.dppclk_div = context->bw.dcn.calc_clk.dppclk_div; + dc->current_state->bw.dcn.cur_clk.max_dppclk_khz = + context->bw.dcn.calc_clk.max_dppclk_khz; + context->bw.dcn.cur_clk.max_dppclk_khz = context->bw.dcn.calc_clk.max_dppclk_khz; } /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 5509e13e7edf..a9b21a4a0c17 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -177,6 +177,15 @@ struct resource_pool { const struct resource_caps *res_cap; }; +struct dcn_fe_clocks { + int dppclk_khz; +}; + +struct dcn_fe_bandwidth { + struct dcn_fe_clocks calc; + struct dcn_fe_clocks cur; +}; + struct stream_resource { struct output_pixel_processor *opp; struct timing_generator *tg; @@ -195,6 +204,8 @@ struct plane_resource { struct transform *xfm; struct dpp *dpp; uint8_t mpcc_inst; + + struct dcn_fe_bandwidth bw; }; struct pipe_ctx { @@ -247,9 +258,9 @@ struct dce_bw_output { struct dcn_bw_clocks { int dispclk_khz; - int dppclk_khz; - bool dppclk_div; + int max_dppclk_khz; int dcfclk_khz; + int socclk_khz; int dcfclk_deep_sleep_khz; int fclk_khz; int dram_ccm_us; -- cgit v1.2.3 From 15cf3974eb06e7b6be1f8f02581759b5f3d9f1e4 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Tue, 13 Feb 2018 14:41:51 -0500 Subject: drm/amd/display: add diags clock programming Signed-off-by: Dmytro Laktyushkin Reviewed-by: Dmytro Laktyushkin Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 5 +++++ drivers/gpu/drm/amd/display/dc/dc.h | 11 +++++++++++ drivers/gpu/drm/amd/display/dc/dm_helpers.h | 3 +++ drivers/gpu/drm/amd/display/dc/inc/core_types.h | 15 ++------------- 4 files changed, 21 insertions(+), 13 deletions(-) (limited to 'drivers') 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 3e157e65d7cd..9ab69b22b989 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 @@ -505,3 +505,8 @@ enum dc_edid_status dm_helpers_read_local_edid( return edid_status; } + +void dm_set_dcn_clocks(struct dc_context *ctx, struct dc_clocks *clks) +{ + /* TODO: something */ +} diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index a6402c651251..14cc4beb12c1 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -184,6 +184,17 @@ enum wm_report_mode { WM_REPORT_OVERRIDE = 1, }; +struct dc_clocks { + int dispclk_khz; + int max_dppclk_khz; + int dcfclk_khz; + int socclk_khz; + int dcfclk_deep_sleep_khz; + int fclk_khz; + int dram_ccm_us; + int min_active_dram_ccm_us; +}; + struct dc_debug { bool surface_visual_confirm; bool sanity_checks; diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index 53d5566f89b8..034369fbb9e2 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -108,5 +108,8 @@ enum dc_edid_status dm_helpers_read_local_edid( struct dc_link *link, struct dc_sink *sink); +void dm_set_dcn_clocks( + struct dc_context *ctx, + struct dc_clocks *clks); #endif /* __DM_HELPERS__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index a9b21a4a0c17..b8f05384a897 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -256,20 +256,9 @@ struct dce_bw_output { int blackout_recovery_time_us; }; -struct dcn_bw_clocks { - int dispclk_khz; - int max_dppclk_khz; - int dcfclk_khz; - int socclk_khz; - int dcfclk_deep_sleep_khz; - int fclk_khz; - int dram_ccm_us; - int min_active_dram_ccm_us; -}; - struct dcn_bw_output { - struct dcn_bw_clocks cur_clk; - struct dcn_bw_clocks calc_clk; + struct dc_clocks cur_clk; + struct dc_clocks calc_clk; struct dcn_watermark_set watermarks; }; -- cgit v1.2.3 From c1d8ba6e0a1c34811afe7f881207062227d81872 Mon Sep 17 00:00:00 2001 From: Tony Cheng Date: Sat, 17 Feb 2018 01:34:42 -0500 Subject: drm/amd/display: dal 3.1.36 Signed-off-by: Tony Cheng Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 14cc4beb12c1..e954705f7f0f 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -38,7 +38,7 @@ #include "inc/compressor.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.1.35" +#define DC_VER "3.1.36" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- cgit v1.2.3 From aef5f5237beded4cbe197aedfc03fceed7f9b7da Mon Sep 17 00:00:00 2001 From: Eric Bernstein Date: Fri, 16 Feb 2018 17:46:54 -0500 Subject: drm/amd/display: Fix DAL surface change test Signed-off-by: Eric Bernstein Reviewed-by: Yongqiang Sun Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 759e925439ce..b4a6b6729e62 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1943,7 +1943,7 @@ static void dcn10_apply_ctx_for_surface( if (old_pipe_ctx->stream_res.tg == tg && old_pipe_ctx->plane_res.hubp && old_pipe_ctx->plane_res.hubp->opp_id != 0xf) { - dcn10_disable_plane(dc, pipe_ctx); + dcn10_disable_plane(dc, old_pipe_ctx); /* * power down fe will unlock when calling reset, need * to lock it back here. Messy, need rework. -- cgit v1.2.3 From 44c6f2e59ee815711a966a82b7d19dbab2110f4a Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak Date: Tue, 13 Feb 2018 13:18:43 -0600 Subject: drm/amd/display: Handle HDR use cases. Implementation of de-gamma, blnd-gamma, shaper and 3d lut's. Removed memory allocations in transfer functions. Refactor color module. Signed-off-by: Vitaly Prosyak Reviewed-by: Krunoslav Kovac Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c | 153 +++++++++++++++++++++ .../gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h | 5 + drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h | 2 + .../drm/amd/display/modules/color/color_gamma.c | 143 +++++++++---------- 4 files changed, 227 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c index b3db6397d353..881a1bff94d2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c @@ -416,3 +416,156 @@ bool cm_helper_translate_curve_to_hw_format( return true; } + +#define NUM_DEGAMMA_REGIONS 12 + + +bool cm_helper_translate_curve_to_degamma_hw_format( + const struct dc_transfer_func *output_tf, + struct pwl_params *lut_params) +{ + struct curve_points *arr_points; + struct pwl_result_data *rgb_resulted; + struct pwl_result_data *rgb; + struct pwl_result_data *rgb_plus_1; + struct fixed31_32 y_r; + struct fixed31_32 y_g; + struct fixed31_32 y_b; + struct fixed31_32 y1_min; + struct fixed31_32 y3_max; + + int32_t region_start, region_end; + int32_t i; + uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points; + + if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS) + return false; + + PERF_TRACE(); + + arr_points = lut_params->arr_points; + rgb_resulted = lut_params->rgb_resulted; + hw_points = 0; + + memset(lut_params, 0, sizeof(struct pwl_params)); + memset(seg_distr, 0, sizeof(seg_distr)); + + region_start = -NUM_DEGAMMA_REGIONS; + region_end = 0; + + + for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) + seg_distr[i] = -1; + /* 12 segments + * segments are from 2^-12 to 0 + */ + for (i = 0; i < NUM_DEGAMMA_REGIONS ; i++) + seg_distr[i] = 4; + + for (k = 0; k < MAX_REGIONS_NUMBER; k++) { + if (seg_distr[k] != -1) + hw_points += (1 << seg_distr[k]); + } + + j = 0; + for (k = 0; k < (region_end - region_start); k++) { + increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]); + start_index = (region_start + k + MAX_LOW_POINT) * + NUMBER_SW_SEGMENTS; + for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS; + i += increment) { + if (j == hw_points - 1) + break; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; + j++; + } + } + + /* last point */ + start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS; + rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index]; + rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index]; + rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index]; + + arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), + dal_fixed31_32_from_int(region_start)); + arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), + dal_fixed31_32_from_int(region_end)); + + y_r = rgb_resulted[0].red; + y_g = rgb_resulted[0].green; + y_b = rgb_resulted[0].blue; + + y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b)); + + arr_points[0].y = y1_min; + arr_points[0].slope = dal_fixed31_32_div(arr_points[0].y, arr_points[0].x); + y_r = rgb_resulted[hw_points - 1].red; + y_g = rgb_resulted[hw_points - 1].green; + y_b = rgb_resulted[hw_points - 1].blue; + + /* see comment above, m_arrPoints[1].y should be the Y value for the + * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) + */ + y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b)); + + arr_points[1].y = y3_max; + + arr_points[1].slope = dal_fixed31_32_zero; + + if (output_tf->tf == TRANSFER_FUNCTION_PQ) { + /* for PQ, we want to have a straight line from last HW X point, + * and the slope to be such that we hit 1.0 at 10000 nits. + */ + const struct fixed31_32 end_value = + dal_fixed31_32_from_int(125); + + arr_points[1].slope = dal_fixed31_32_div( + dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y), + dal_fixed31_32_sub(end_value, arr_points[1].x)); + } + + lut_params->hw_points_num = hw_points; + + i = 1; + for (k = 0; k < MAX_REGIONS_NUMBER && i < MAX_REGIONS_NUMBER; k++) { + if (seg_distr[k] != -1) { + lut_params->arr_curve_points[k].segments_num = + seg_distr[k]; + lut_params->arr_curve_points[i].offset = + lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]); + } + i++; + } + + if (seg_distr[k] != -1) + lut_params->arr_curve_points[k].segments_num = seg_distr[k]; + + rgb = rgb_resulted; + rgb_plus_1 = rgb_resulted + 1; + + i = 1; + while (i != hw_points + 1) { + if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red)) + rgb_plus_1->red = rgb->red; + if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green)) + rgb_plus_1->green = rgb->green; + if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue)) + rgb_plus_1->blue = rgb->blue; + + rgb->delta_red = dal_fixed31_32_sub(rgb_plus_1->red, rgb->red); + rgb->delta_green = dal_fixed31_32_sub(rgb_plus_1->green, rgb->green); + rgb->delta_blue = dal_fixed31_32_sub(rgb_plus_1->blue, rgb->blue); + + ++rgb_plus_1; + ++rgb; + ++i; + } + cm_helper_convert_to_custom_float(rgb_resulted, + lut_params->arr_points, + hw_points, false); + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h index 64e476b83bcb..7a531b02871f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h @@ -106,4 +106,9 @@ bool cm_helper_translate_curve_to_hw_format( const struct dc_transfer_func *output_tf, struct pwl_params *lut_params, bool fixpoint); +bool cm_helper_translate_curve_to_degamma_hw_format( + const struct dc_transfer_func *output_tf, + struct pwl_params *lut_params); + + #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index 78abc16ec4dc..c5aae2daf442 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -35,6 +35,8 @@ struct dpp { int inst; struct dpp_caps *caps; struct pwl_params regamma_params; + struct pwl_params degamma_params; + }; struct dpp_grph_csc_adjustment { 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 a5fd14a4016f..57d5c2575de1 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -30,15 +30,12 @@ #define NUM_PTS_IN_REGION 16 #define NUM_REGIONS 32 -#define NUM_DEGAMMA_REGIONS 12 #define MAX_HW_POINTS (NUM_PTS_IN_REGION*NUM_REGIONS) -#define MAX_HW_DEGAMMA_POINTS (NUM_PTS_IN_REGION*NUM_DEGAMMA_REGIONS) static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2]; -static struct hw_x_point degamma_coordinates_x[MAX_HW_DEGAMMA_POINTS + 2]; static struct fixed31_32 pq_table[MAX_HW_POINTS + 2]; -static struct fixed31_32 de_pq_table[MAX_HW_DEGAMMA_POINTS + 2]; +static struct fixed31_32 de_pq_table[MAX_HW_POINTS + 2]; static bool pq_initialized; /* = false; */ static bool de_pq_initialized; /* = false; */ @@ -69,26 +66,6 @@ void setup_x_points_distribution(void) (coordinates_x[index-1].x, increment); } } - - region_size = dal_fixed31_32_from_int(1); - degamma_coordinates_x[MAX_HW_DEGAMMA_POINTS].x = region_size; - degamma_coordinates_x[MAX_HW_DEGAMMA_POINTS + 1].x = region_size; - - for (segment = -1; segment > -(NUM_DEGAMMA_REGIONS + 1); segment--) { - region_size = dal_fixed31_32_div_int(region_size, 2); - increment = dal_fixed31_32_div_int(region_size, - NUM_PTS_IN_REGION); - seg_offset = (segment + NUM_DEGAMMA_REGIONS) * NUM_PTS_IN_REGION; - degamma_coordinates_x[seg_offset].x = region_size; - - for (index = seg_offset + 1; - index < seg_offset + NUM_PTS_IN_REGION; - index++) { - degamma_coordinates_x[index].x = dal_fixed31_32_add - (degamma_coordinates_x[index-1].x, increment); - } - } - } static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) @@ -179,15 +156,26 @@ void precompute_de_pq(void) { int i; struct fixed31_32 y; - const struct hw_x_point *coord_x = degamma_coordinates_x; + uint32_t begin_index, end_index; + struct fixed31_32 scaling_factor = dal_fixed31_32_from_int(125); + /* X points is 2^-25 to 2^7 + * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions + */ + begin_index = 13 * NUM_PTS_IN_REGION; + end_index = begin_index + 12 * NUM_PTS_IN_REGION; - for (i = 0; i <= MAX_HW_DEGAMMA_POINTS; i++) { - compute_de_pq(coord_x->x, &y); + for (i = 0; i <= begin_index; i++) + de_pq_table[i] = dal_fixed31_32_zero; + + for (; i <= end_index; i++) { + compute_de_pq(coordinates_x[i].x, &y); de_pq_table[i] = dal_fixed31_32_mul(y, scaling_factor); - ++coord_x; } + + for (; i <= MAX_HW_POINTS; i++) + de_pq_table[i] = de_pq_table[i-1]; } struct dividers { struct fixed31_32 divider1; @@ -617,8 +605,6 @@ static void build_de_pq(struct pwl_float_data_ex *de_pq, uint32_t i; struct fixed31_32 output; - struct pwl_float_data_ex *rgb = de_pq; - const struct hw_x_point *coord_x = degamma_coordinates_x; struct fixed31_32 scaling_factor = dal_fixed31_32_from_int(125); if (!de_pq_initialized) { @@ -634,13 +620,9 @@ static void build_de_pq(struct pwl_float_data_ex *de_pq, output = dal_fixed31_32_zero; else if (dal_fixed31_32_lt(scaling_factor, output)) output = scaling_factor; - - rgb->r = output; - rgb->g = output; - rgb->b = output; - - ++coord_x; - ++rgb; + de_pq[i].r = output; + de_pq[i].g = output; + de_pq[i].b = output; } } @@ -675,24 +657,37 @@ static void build_degamma(struct pwl_float_data_ex *curve, const struct hw_x_point *coordinate_x, bool is_2_4) { uint32_t i; - struct gamma_coefficients coeff; - struct pwl_float_data_ex *rgb = curve; - const struct hw_x_point *coord_x = degamma_coordinates_x; + uint32_t begin_index, end_index; build_coefficients(&coeff, is_2_4); - i = 0; + /* X points is 2^-25 to 2^7 + * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions + */ + begin_index = 13 * NUM_PTS_IN_REGION; + end_index = begin_index + 12 * NUM_PTS_IN_REGION; + + while (i != begin_index) { + curve[i].r = dal_fixed31_32_zero; + curve[i].g = dal_fixed31_32_zero; + curve[i].b = dal_fixed31_32_zero; + i++; + } + + while (i != end_index) { + curve[i].r = translate_to_linear_space_ex( + coordinate_x[i].x, &coeff, 0); + curve[i].g = curve[i].r; + curve[i].b = curve[i].r; + i++; + } while (i != hw_points_num + 1) { - /*TODO use y vs r,g,b*/ - rgb->r = translate_to_linear_space_ex( - coord_x->x, &coeff, 0); - rgb->g = rgb->r; - rgb->b = rgb->r; - ++coord_x; - ++rgb; - ++i; + curve[i].r = dal_fixed31_32_one; + curve[i].g = dal_fixed31_32_one; + curve[i].b = dal_fixed31_32_one; + i++; } } @@ -1173,10 +1168,6 @@ rgb_user_alloc_fail: return ret; } - -/*TODO fix me should be 2*/ -#define _EXTRA_POINTS 3 - bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, const struct dc_gamma *ramp, bool mapUserRamp) { @@ -1205,7 +1196,7 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, GFP_KERNEL); if (!rgb_user) goto rgb_user_alloc_fail; - curve = kzalloc(sizeof(*curve) * (MAX_HW_DEGAMMA_POINTS + _EXTRA_POINTS), + curve = kzalloc(sizeof(*curve) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); if (!curve) goto curve_alloc_fail; @@ -1213,7 +1204,7 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, GFP_KERNEL); if (!axix_x) goto axix_x_alloc_fail; - coeff = kzalloc(sizeof(*coeff) * (MAX_HW_DEGAMMA_POINTS + _EXTRA_POINTS), GFP_KERNEL); + coeff = kzalloc(sizeof(*coeff) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); if (!coeff) goto coeff_alloc_fail; @@ -1235,12 +1226,12 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, if (tf == TRANSFER_FUNCTION_PQ) build_de_pq(curve, - MAX_HW_DEGAMMA_POINTS, - degamma_coordinates_x); + MAX_HW_POINTS, + coordinates_x); else build_degamma(curve, - MAX_HW_DEGAMMA_POINTS, - degamma_coordinates_x, + MAX_HW_POINTS, + coordinates_x, tf == TRANSFER_FUNCTION_SRGB ? true:false); tf_pts->end_exponent = 0; @@ -1249,8 +1240,8 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, tf_pts->x_point_at_y1_blue = 1; map_regamma_hw_to_x_user(ramp, coeff, rgb_user, - degamma_coordinates_x, axix_x, curve, - MAX_HW_DEGAMMA_POINTS, tf_pts, + coordinates_x, axix_x, curve, + MAX_HW_POINTS, tf_pts, mapUserRamp); ret = true; @@ -1282,7 +1273,7 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, points->x_point_at_y1_green = 1; points->x_point_at_y1_blue = 1; - for (i = 0; i < MAX_HW_POINTS ; i++) { + for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = coordinates_x[i].x; points->green[i] = coordinates_x[i].x; points->blue[i] = coordinates_x[i].x; @@ -1303,7 +1294,7 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, MAX_HW_POINTS, coordinates_x, 80); - for (i = 0; i < MAX_HW_POINTS ; i++) { + for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = rgb_regamma[i].r; points->green[i] = rgb_regamma[i].g; points->blue[i] = rgb_regamma[i].b; @@ -1325,7 +1316,7 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, build_regamma(rgb_regamma, MAX_HW_POINTS, coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false); - for (i = 0; i < MAX_HW_POINTS ; i++) { + for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = rgb_regamma[i].r; points->green[i] = rgb_regamma[i].g; points->blue[i] = rgb_regamma[i].b; @@ -1348,23 +1339,23 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, if (trans == TRANSFER_FUNCTION_UNITY) { - for (i = 0; i < MAX_HW_DEGAMMA_POINTS ; i++) { - points->red[i] = degamma_coordinates_x[i].x; - points->green[i] = degamma_coordinates_x[i].x; - points->blue[i] = degamma_coordinates_x[i].x; + for (i = 0; i <= MAX_HW_POINTS ; i++) { + points->red[i] = coordinates_x[i].x; + points->green[i] = coordinates_x[i].x; + points->blue[i] = coordinates_x[i].x; } ret = true; } else if (trans == TRANSFER_FUNCTION_PQ) { - rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_DEGAMMA_POINTS + + rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); if (!rgb_degamma) goto rgb_degamma_alloc_fail; build_de_pq(rgb_degamma, - MAX_HW_DEGAMMA_POINTS, - degamma_coordinates_x); - for (i = 0; i < MAX_HW_DEGAMMA_POINTS ; i++) { + MAX_HW_POINTS, + coordinates_x); + for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = rgb_degamma[i].r; points->green[i] = rgb_degamma[i].g; points->blue[i] = rgb_degamma[i].b; @@ -1374,15 +1365,15 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, kfree(rgb_degamma); } else if (trans == TRANSFER_FUNCTION_SRGB || trans == TRANSFER_FUNCTION_BT709) { - rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_DEGAMMA_POINTS + + rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); if (!rgb_degamma) goto rgb_degamma_alloc_fail; build_degamma(rgb_degamma, - MAX_HW_DEGAMMA_POINTS, - degamma_coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false); - for (i = 0; i < MAX_HW_DEGAMMA_POINTS ; i++) { + MAX_HW_POINTS, + coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false); + for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = rgb_degamma[i].r; points->green[i] = rgb_degamma[i].g; points->blue[i] = rgb_degamma[i].b; -- cgit v1.2.3 From 2f3fd67a8af25f5b4d549c3e9cc515dbf1839ffc Mon Sep 17 00:00:00 2001 From: Bhawanpreet Lakha Date: Fri, 16 Feb 2018 13:57:42 -0500 Subject: drm/amd/display: Use MACROS instead of dm_logger Created MACROS for all log levels. Also Replaced usage of dm_logger_write to the defined MACROS Signed-off-by: Bhawanpreet Lakha Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 2 +- .../gpu/drm/amd/display/dc/bios/command_table2.c | 6 +-- drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 6 +-- drivers/gpu/drm/amd/display/dc/core/dc.c | 8 ++-- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 32 ++++++++-------- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 34 ++++++++--------- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 2 +- drivers/gpu/drm/amd/display/dc/dce/dce_abm.c | 2 +- drivers/gpu/drm/amd/display/dc/dce/dce_audio.c | 10 ++--- .../gpu/drm/amd/display/dc/dce/dce_clock_source.c | 24 ++++++------ drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c | 4 +- .../gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 10 ++--- .../drm/amd/display/dc/dce/dce_stream_encoder.c | 6 +-- drivers/gpu/drm/amd/display/dc/dce/dce_transform.c | 6 +-- .../drm/amd/display/dc/dce110/dce110_compressor.c | 12 +++--- .../amd/display/dc/dce110/dce110_hw_sequencer.c | 16 ++++---- .../drm/amd/display/dc/dce110/dce110_resource.c | 6 +-- .../display/dc/dce110/dce110_timing_generator_v.c | 10 ++--- .../drm/amd/display/dc/dce110/dce110_transform_v.c | 2 +- .../drm/amd/display/dc/dce112/dce112_compressor.c | 32 ++++++++-------- .../drm/amd/display/dc/dce112/dce112_resource.c | 6 +-- .../gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c | 44 +++++++++++----------- .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 28 +++++++------- drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c | 4 +- .../dc/i2caux/dce110/i2c_hw_engine_dce110.c | 4 +- .../amd/display/dc/irq/dce110/irq_service_dce110.c | 8 ++-- drivers/gpu/drm/amd/display/dc/irq/irq_service.c | 8 ++-- drivers/gpu/drm/amd/display/include/logger_types.h | 33 ++++++++++++++++ 28 files changed, 199 insertions(+), 166 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index 69c59e050a96..52f524a55b57 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -3079,7 +3079,7 @@ static enum bp_result patch_bios_image_from_ext_display_connection_info( opm_object, &ext_display_connection_info_tbl) != BP_RESULT_OK) { - dm_logger_write(bp->base.ctx->logger, LOG_WARNING, + DC_LOG_WARNING(bp->base.ctx->logger, "%s: Failed to read Connection Info Table", __func__); return BP_RESULT_UNSUPPORTED; } diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index fea5e83736fd..03df7b7a2d80 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -239,7 +239,7 @@ static enum bp_result transmitter_control_v1_6( if (cntl->action == TRANSMITTER_CONTROL_ENABLE || cntl->action == TRANSMITTER_CONTROL_ACTIAVATE || cntl->action == TRANSMITTER_CONTROL_DEACTIVATE) { - dm_logger_write(bp->base.ctx->logger, LOG_BIOS,\ + DC_LOG_BIOS(bp->base.ctx->logger, \ "%s:ps.param.symclk_10khz = %d\n",\ __func__, ps.param.symclk_10khz); } @@ -331,7 +331,7 @@ static enum bp_result set_pixel_clock_v7( (uint8_t) bp->cmd_helper-> transmitter_color_depth_to_atom( bp_params->color_depth); - dm_logger_write(bp->base.ctx->logger, LOG_BIOS,\ + DC_LOG_BIOS(bp->base.ctx->logger, \ "%s:program display clock = %d"\ "colorDepth = %d\n", __func__,\ bp_params->target_pixel_clock, bp_params->color_depth); @@ -772,7 +772,7 @@ static enum bp_result set_dce_clock_v2_1( */ params.param.dceclk_10khz = cpu_to_le32( bp_params->target_clock_frequency / 10); - dm_logger_write(bp->base.ctx->logger, LOG_BIOS, + DC_LOG_BIOS(bp->base.ctx->logger, "%s:target_clock_frequency = %d"\ "clock_type = %d \n", __func__,\ bp_params->target_clock_frequency,\ diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index e4d8a8dbc5ef..7728c85bcb0e 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -1242,7 +1242,7 @@ unsigned int dcn_find_dcfclk_suits_all( else dcf_clk = dc->dcn_soc->dcfclkv_min0p65*1000; - dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\tdcf_clk for voltage = %d\n", dcf_clk); return dcf_clk; } @@ -1441,7 +1441,7 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc) void dcn_bw_sync_calcs_and_dml(struct dc *dc) { kernel_fpu_begin(); - dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "sr_exit_time: %d ns\n" "sr_enter_plus_exit_time: %d ns\n" "urgent_latency: %d ns\n" @@ -1510,7 +1510,7 @@ void dcn_bw_sync_calcs_and_dml(struct dc *dc) dc->dcn_soc->vmm_page_size, dc->dcn_soc->dram_clock_change_latency * 1000, dc->dcn_soc->return_bus_width); - dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "rob_buffer_size_in_kbyte: %d\n" "det_buffer_size_in_kbyte: %d\n" "dpp_output_buffer_pixels: %d\n" diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 77a1bf233c3c..73bb416cb7dc 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -264,7 +264,7 @@ bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream, /* Only call if supported */ if (tg->funcs->configure_crc) return tg->funcs->configure_crc(tg, ¶m); - dm_logger_write(dc->ctx->logger, LOG_WARNING, "CRC capture not supported."); + DC_LOG_WARNING(dc->ctx->logger, "CRC capture not supported."); return false; } @@ -297,7 +297,7 @@ bool dc_stream_get_crc(struct dc *dc, struct dc_stream_state *stream, if (tg->funcs->get_crc) return tg->funcs->get_crc(tg, r_cr, g_y, b_cb); - dm_logger_write(dc->ctx->logger, LOG_WARNING, "CRC capture not supported."); + DC_LOG_WARNING(dc->ctx->logger, "CRC capture not supported."); return false; } @@ -618,7 +618,7 @@ struct dc *dc_create(const struct dc_init_data *init_params) dc->config = init_params->flags; - dm_logger_write(dc->ctx->logger, LOG_DC, + DC_LOG_DC(dc->ctx->logger, "Display Core initialized\n"); @@ -888,7 +888,7 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context) if (false == context_changed(dc, context)) return DC_OK; - dm_logger_write(dc->ctx->logger, LOG_DC, "%s: %d streams\n", + DC_LOG_DC(dc->ctx->logger, "%s: %d streams\n", __func__, context->stream_count); for (i = 0; i < context->stream_count; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index b7540152005b..059ceada2095 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -47,7 +47,7 @@ #include "dce/dce_11_0_sh_mask.h" #define LINK_INFO(...) \ - dm_logger_write(dc_ctx->logger, LOG_HW_HOTPLUG, \ + DC_LOG_HW_HOTPLUG(dc_ctx->logger, \ __VA_ARGS__) /******************************************************************************* @@ -677,11 +677,11 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) switch (edid_status) { case EDID_BAD_CHECKSUM: - dm_logger_write(link->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(link->ctx->logger, "EDID checksum invalid.\n"); break; case EDID_NO_RESPONSE: - dm_logger_write(link->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(link->ctx->logger, "No EDID read.\n"); default: break; @@ -712,7 +712,7 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) "%s: [Block %d] ", sink->edid_caps.display_name, i); } - dm_logger_write(link->ctx->logger, LOG_DETECTION_EDID_PARSER, + DC_LOG_DETECTION_EDID_PARSER(link->ctx->logger, "%s: " "manufacturer_id = %X, " "product_id = %X, " @@ -733,7 +733,7 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) sink->edid_caps.audio_mode_count); for (i = 0; i < sink->edid_caps.audio_mode_count; i++) { - dm_logger_write(link->ctx->logger, LOG_DETECTION_EDID_PARSER, + DC_LOG_DETECTION_EDID_PARSER(link->ctx->logger, "%s: mode number = %d, " "format_code = %d, " "channel_count = %d, " @@ -984,7 +984,7 @@ static bool construct( } break; default: - dm_logger_write(dc_ctx->logger, LOG_WARNING, + DC_LOG_WARNING(dc_ctx->logger, "Unsupported Connector type:%d!\n", link->link_id.id); goto create_fail; } @@ -1175,7 +1175,7 @@ static void dpcd_configure_panel_mode( ASSERT(result == DDC_RESULT_SUCESSFULL); } } - dm_logger_write(link->ctx->logger, LOG_DETECTION_DP_CAPS, + DC_LOG_DETECTION_DP_CAPS(link->ctx->logger, "Link: %d eDP panel mode supported: %d " "eDP panel mode enabled: %d \n", link->link_index, @@ -1965,7 +1965,7 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level, use_smooth_brightness = dmcu->funcs->is_dmcu_initialized(dmcu); - dm_logger_write(link->ctx->logger, LOG_BACKLIGHT, + DC_LOG_BACKLIGHT(link->ctx->logger, "New Backlight level: %d (0x%X)\n", level, level); if (dc_is_embedded_signal(link->connector_signal)) { @@ -2150,20 +2150,20 @@ static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx) link, pipe_ctx->stream_res.stream_enc, &proposed_table); } else - dm_logger_write(link->ctx->logger, LOG_WARNING, + DC_LOG_WARNING(link->ctx->logger, "Failed to update" "MST allocation table for" "pipe idx:%d\n", pipe_ctx->pipe_idx); - dm_logger_write(link->ctx->logger, LOG_MST, + DC_LOG_MST(link->ctx->logger, "%s " "stream_count: %d: \n ", __func__, link->mst_stream_alloc_table.stream_count); for (i = 0; i < MAX_CONTROLLER_NUM; i++) { - dm_logger_write(link->ctx->logger, LOG_MST, + DC_LOG_MST(link->ctx->logger, "stream_enc[%d]: 0x%x " "stream[%d].vcp_id: %d " "stream[%d].slot_count: %d\n", @@ -2240,7 +2240,7 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) link, pipe_ctx->stream_res.stream_enc, &proposed_table); } else { - dm_logger_write(link->ctx->logger, LOG_WARNING, + DC_LOG_WARNING(link->ctx->logger, "Failed to update" "MST allocation table for" "pipe idx:%d\n", @@ -2248,14 +2248,14 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) } } - dm_logger_write(link->ctx->logger, LOG_MST, + DC_LOG_MST(link->ctx->logger, "%s" "stream_count: %d: ", __func__, link->mst_stream_alloc_table.stream_count); for (i = 0; i < MAX_CONTROLLER_NUM; i++) { - dm_logger_write(link->ctx->logger, LOG_MST, + DC_LOG_MST(link->ctx->logger, "stream_enc[%d]: 0x%x " "stream[%d].vcp_id: %d " "stream[%d].slot_count: %d\n", @@ -2307,8 +2307,8 @@ void core_link_enable_stream( status = enable_link(state, pipe_ctx); if (status != DC_OK) { - dm_logger_write(pipe_ctx->stream->ctx->logger, - LOG_WARNING, "enabling link %u failed: %d\n", + DC_LOG_WARNING(pipe_ctx->stream->ctx->logger, + "enabling link %u failed: %d\n", pipe_ctx->stream->sink->link->link_index, status); 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 4c21da54a9d5..9a041641a539 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 @@ -63,7 +63,7 @@ static void wait_for_training_aux_rd_interval( udelay(default_wait_in_micro_secs); - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, + DC_LOG_HW_LINK_TRAINING(link->ctx->logger, "%s:\n wait = %d\n", __func__, default_wait_in_micro_secs); @@ -79,7 +79,7 @@ static void dpcd_set_training_pattern( &dpcd_pattern.raw, 1); - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, + DC_LOG_HW_LINK_TRAINING(link->ctx->logger, "%s\n %x pattern = %x\n", __func__, DP_TRAINING_PATTERN_SET, @@ -116,7 +116,7 @@ static void dpcd_set_link_settings( core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, &downspread.raw, sizeof(downspread)); - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, + DC_LOG_HW_LINK_TRAINING(link->ctx->logger, "%s\n %x rate = %x\n %x lane = %x\n %x spread = %x\n", __func__, DP_LINK_BW_SET, @@ -151,7 +151,7 @@ static enum dpcd_training_patterns break; default: ASSERT(0); - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, + DC_LOG_HW_LINK_TRAINING(link->ctx->logger, "%s: Invalid HW Training pattern: %d\n", __func__, pattern); break; @@ -184,7 +184,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - dpcd_base_lt_offset] = dpcd_pattern.raw; - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, + DC_LOG_HW_LINK_TRAINING(link->ctx->logger, "%s\n %x pattern = %x\n", __func__, DP_TRAINING_PATTERN_SET, @@ -219,7 +219,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( dpcd_lane, size_in_bytes); - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, + DC_LOG_HW_LINK_TRAINING(link->ctx->logger, "%s:\n %x VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", __func__, DP_TRAINING_LANE0_SET, @@ -456,13 +456,13 @@ static void get_lane_status_and_drive_settings( ln_status_updated->raw = dpcd_buf[2]; - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, + DC_LOG_HW_LINK_TRAINING(link->ctx->logger, "%s:\n%x Lane01Status = %x\n %x Lane23Status = %x\n ", __func__, DP_LANE0_1_STATUS, dpcd_buf[0], DP_LANE2_3_STATUS, dpcd_buf[1]); - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, + DC_LOG_HW_LINK_TRAINING(link->ctx->logger, "%s:\n %x Lane01AdjustRequest = %x\n %x Lane23AdjustRequest = %x\n", __func__, DP_ADJUST_REQUEST_LANE0_1, @@ -556,7 +556,7 @@ static void dpcd_set_lane_settings( } */ - dm_logger_write(link->ctx->logger, LOG_HW_LINK_TRAINING, + DC_LOG_HW_LINK_TRAINING(link->ctx->logger, "%s\n %x VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", __func__, DP_TRAINING_LANE0_SET, @@ -669,7 +669,7 @@ static bool perform_post_lt_adj_req_sequence( } if (!req_drv_setting_changed) { - dm_logger_write(link->ctx->logger, LOG_WARNING, + DC_LOG_WARNING(link->ctx->logger, "%s: Post Link Training Adjust Request Timed out\n", __func__); @@ -677,7 +677,7 @@ static bool perform_post_lt_adj_req_sequence( return true; } } - dm_logger_write(link->ctx->logger, LOG_WARNING, + DC_LOG_WARNING(link->ctx->logger, "%s: Post Link Training Adjust Request limit reached\n", __func__); @@ -885,7 +885,7 @@ static enum link_training_result perform_clock_recovery_sequence( if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { ASSERT(0); - dm_logger_write(link->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(link->ctx->logger, "%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", __func__, LINK_TRAINING_MAX_CR_RETRY); @@ -1606,7 +1606,7 @@ static bool hpd_rx_irq_check_link_loss_status( if (sink_status_changed || !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) { - dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, + DC_LOG_HW_HPD_IRQ(link->ctx->logger, "%s: Link Status changed.\n", __func__); return_code = true; @@ -1620,7 +1620,7 @@ static bool hpd_rx_irq_check_link_loss_status( sizeof(irq_reg_rx_power_state)); if (dpcd_result != DC_OK) { - dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, + DC_LOG_HW_HPD_IRQ(link->ctx->logger, "%s: DPCD read failed to obtain power state.\n", __func__); } else { @@ -1982,7 +1982,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd * PSR and device auto test, refer to function handle_sst_hpd_irq * in DAL2.1*/ - dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, + DC_LOG_HW_HPD_IRQ(link->ctx->logger, "%s: Got short pulse HPD on link %d\n", __func__, link->link_index); @@ -1997,7 +1997,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd *out_hpd_irq_dpcd_data = hpd_irq_dpcd_data; if (result != DC_OK) { - dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, + DC_LOG_HW_HPD_IRQ(link->ctx->logger, "%s: DPCD read failed to obtain irq data\n", __func__); return false; @@ -2016,7 +2016,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd } if (!allow_hpd_rx_irq(link)) { - dm_logger_write(link->ctx->logger, LOG_HW_HPD_IRQ, + DC_LOG_HW_HPD_IRQ(link->ctx->logger, "%s: skipping HPD handling on %d\n", __func__, link->link_index); return false; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 48709d4b5627..52b0a4ae2f9a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -893,7 +893,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) /* May need to re-check lb size after this in some obscure scenario */ calculate_inits_and_adj_vp(pipe_ctx, &recout_skip); - dm_logger_write(pipe_ctx->stream->ctx->logger, LOG_SCALER, + DC_LOG_SCALER(pipe_ctx->stream->ctx->logger, "%s: Viewport:\nheight:%d width:%d x:%d " "y:%d\n dst_rect:\nheight:%d width:%d x:%d " "y:%d\n", diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c index b231bd53613e..5efd0c460bee 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c @@ -403,7 +403,7 @@ static bool dce_abm_set_backlight_level( { struct dce_abm *abm_dce = TO_DCE_ABM(abm); - dm_logger_write(abm->ctx->logger, LOG_BACKLIGHT, + DC_LOG_BACKLIGHT(abm->ctx->logger, "New Backlight level: %d (0x%X)\n", backlight_level, backlight_level); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c index e366bfd7cf6f..2e86d8cb4ef3 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c @@ -63,7 +63,7 @@ static void write_indirect_azalia_reg(struct audio *audio, REG_SET(AZALIA_F0_CODEC_ENDPOINT_DATA, 0, AZALIA_ENDPOINT_REG_DATA, reg_data); - dm_logger_write(CTX->logger, LOG_HW_AUDIO, + DC_LOG_HW_AUDIO(CTX->logger, "AUDIO:write_indirect_azalia_reg: index: %u data: %u\n", reg_index, reg_data); } @@ -81,7 +81,7 @@ static uint32_t read_indirect_azalia_reg(struct audio *audio, uint32_t reg_index /* AZALIA_F0_CODEC_ENDPOINT_DATA endpoint data */ value = REG_READ(AZALIA_F0_CODEC_ENDPOINT_DATA); - dm_logger_write(CTX->logger, LOG_HW_AUDIO, + DC_LOG_HW_AUDIO(CTX->logger, "AUDIO:read_indirect_azalia_reg: index: %u data: %u\n", reg_index, value); @@ -364,7 +364,7 @@ void dce_aud_az_enable(struct audio *audio) CLOCK_GATING_DISABLE); AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value); - dm_logger_write(CTX->logger, LOG_HW_AUDIO, + DC_LOG_HW_AUDIO(CTX->logger, "\n\t========= AUDIO:dce_aud_az_enable: index: %u data: 0x%x\n", audio->inst, value); } @@ -390,7 +390,7 @@ void dce_aud_az_disable(struct audio *audio) CLOCK_GATING_DISABLE); AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value); value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL); - dm_logger_write(CTX->logger, LOG_HW_AUDIO, + DC_LOG_HW_AUDIO(CTX->logger, "\n\t========= AUDIO:dce_aud_az_disable: index: %u data: 0x%x\n", audio->inst, value); } @@ -795,7 +795,7 @@ void dce_aud_wall_dto_setup( crtc_info->calculated_pixel_clock, &clock_info); - dm_logger_write(audio->ctx->logger, LOG_HW_AUDIO,\ + DC_LOG_HW_AUDIO(audio->ctx->logger, \ "\n%s:Input::requested_pixel_clock = %d"\ "calculated_pixel_clock =%d\n"\ "audio_dto_module = %d audio_dto_phase =%d \n\n", __func__,\ 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 5036b674f68b..2860d0a39be4 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 @@ -288,7 +288,7 @@ static uint32_t calculate_pixel_clock_pll_dividers( uint32_t max_ref_divider; if (pll_settings->adjusted_pix_clk == 0) { - dm_logger_write(calc_pll_cs->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(calc_pll_cs->ctx->logger, "%s Bad requested pixel clock", __func__); return MAX_PLL_CALC_ERROR; } @@ -349,13 +349,13 @@ static uint32_t calculate_pixel_clock_pll_dividers( * ## SVS Wed 15 Jul 2009 */ if (min_post_divider > max_post_divider) { - dm_logger_write(calc_pll_cs->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(calc_pll_cs->ctx->logger, "%s Post divider range is invalid", __func__); return MAX_PLL_CALC_ERROR; } if (min_ref_divider > max_ref_divider) { - dm_logger_write(calc_pll_cs->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(calc_pll_cs->ctx->logger, "%s Reference divider range is invalid", __func__); return MAX_PLL_CALC_ERROR; } @@ -493,7 +493,7 @@ static uint32_t dce110_get_pix_clk_dividers_helper ( if (!pll_adjust_pix_clk(clk_src, pix_clk_params, pll_settings)) { /* Should never happen, ASSERT and fill up values to be able * to continue. */ - dm_logger_write(clk_src->base.ctx->logger, LOG_ERROR, + DC_LOG_ERROR(clk_src->base.ctx->logger, "%s: Failed to adjust pixel clock!!", __func__); pll_settings->actual_pix_clk = pix_clk_params->requested_pix_clk; @@ -560,7 +560,7 @@ static uint32_t dce110_get_pix_clk_dividers( if (pix_clk_params == NULL || pll_settings == NULL || pix_clk_params->requested_pix_clk == 0) { - dm_logger_write(clk_src->base.ctx->logger, LOG_ERROR, + DC_LOG_ERROR(clk_src->base.ctx->logger, "%s: Invalid parameters!!\n", __func__); return pll_calc_error; } @@ -1054,12 +1054,12 @@ static void get_ss_info_from_atombios( uint32_t i; if (ss_entries_num == NULL) { - dm_logger_write(clk_src->base.ctx->logger, LOG_SYNC, + DC_LOG_SYNC(clk_src->base.ctx->logger, "Invalid entry !!!\n"); return; } if (spread_spectrum_data == NULL) { - dm_logger_write(clk_src->base.ctx->logger, LOG_SYNC, + DC_LOG_SYNC(clk_src->base.ctx->logger, "Invalid array pointer!!!\n"); return; } @@ -1104,7 +1104,7 @@ static void get_ss_info_from_atombios( ++i, ++ss_info_cur, ++ss_data_cur) { if (ss_info_cur->type.STEP_AND_DELAY_INFO != false) { - dm_logger_write(clk_src->base.ctx->logger, LOG_SYNC, + DC_LOG_SYNC(clk_src->base.ctx->logger, "Invalid ATOMBIOS SS Table!!!\n"); goto out_free_data; } @@ -1114,9 +1114,9 @@ static void get_ss_info_from_atombios( if (as_signal == AS_SIGNAL_TYPE_HDMI && ss_info_cur->spread_spectrum_percentage > 6){ /* invalid input, do nothing */ - dm_logger_write(clk_src->base.ctx->logger, LOG_SYNC, + DC_LOG_SYNC(clk_src->base.ctx->logger, "Invalid SS percentage "); - dm_logger_write(clk_src->base.ctx->logger, LOG_SYNC, + DC_LOG_SYNC(clk_src->base.ctx->logger, "for HDMI in ATOMBIOS info Table!!!\n"); continue; } @@ -1228,12 +1228,12 @@ static bool calc_pll_max_vco_construct( if (init_data->num_fract_fb_divider_decimal_point == 0 || init_data->num_fract_fb_divider_decimal_point_precision > init_data->num_fract_fb_divider_decimal_point) { - dm_logger_write(calc_pll_cs->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(calc_pll_cs->ctx->logger, "The dec point num or precision is incorrect!"); return false; } if (init_data->num_fract_fb_divider_decimal_point_precision == 0) { - dm_logger_write(calc_pll_cs->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(calc_pll_cs->ctx->logger, "Incorrect fract feedback divider precision num!"); return false; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 046658c8498a..654dcc6df97d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -292,7 +292,7 @@ static enum dm_pp_clocks_state dce_get_required_clocks_state( low_req_clk = i + 1; if (low_req_clk > clk->max_clks_state) { - dm_logger_write(clk->ctx->logger, LOG_WARNING, + DC_LOG_WARNING(clk->ctx->logger, "%s: clocks unsupported disp_clk %d pix_clk %d", __func__, req_clocks->display_clk_khz, @@ -312,7 +312,7 @@ static bool dce_clock_set_min_clocks_state( if (clocks_state > clk->max_clks_state) { /*Requested state exceeds max supported state.*/ - dm_logger_write(clk->ctx->logger, LOG_WARNING, + DC_LOG_WARNING(clk->ctx->logger, "Requested state exceeds max supported state"); return false; } else if (clocks_state == clk->cur_min_clks_state) { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index 11f50588b3f4..e063a50a5771 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -827,7 +827,7 @@ void dce110_link_encoder_hw_init( result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { - dm_logger_write(ctx->logger, LOG_ERROR, + DC_LOG_ERROR(ctx->logger, "%s: Failed to execute VBIOS command table!\n", __func__); BREAK_TO_DEBUGGER(); @@ -928,7 +928,7 @@ void dce110_link_encoder_enable_tmds_output( result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { - dm_logger_write(ctx->logger, LOG_ERROR, + DC_LOG_ERROR(ctx->logger, "%s: Failed to execute VBIOS command table!\n", __func__); BREAK_TO_DEBUGGER(); @@ -969,7 +969,7 @@ void dce110_link_encoder_enable_dp_output( result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { - dm_logger_write(ctx->logger, LOG_ERROR, + DC_LOG_ERROR(ctx->logger, "%s: Failed to execute VBIOS command table!\n", __func__); BREAK_TO_DEBUGGER(); @@ -1010,7 +1010,7 @@ void dce110_link_encoder_enable_dp_mst_output( result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { - dm_logger_write(ctx->logger, LOG_ERROR, + DC_LOG_ERROR(ctx->logger, "%s: Failed to execute VBIOS command table!\n", __func__); BREAK_TO_DEBUGGER(); @@ -1053,7 +1053,7 @@ void dce110_link_encoder_disable_output( result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { - dm_logger_write(ctx->logger, LOG_ERROR, + DC_LOG_ERROR(ctx->logger, "%s: Failed to execute VBIOS command table!\n", __func__); BREAK_TO_DEBUGGER(); 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 8146b9079d51..f4d95126de2e 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 @@ -277,8 +277,8 @@ static void dce110_update_hdmi_info_packet( #endif default: /* invalid HW packet index */ - dm_logger_write( - ctx->logger, LOG_WARNING, + DC_LOG_WARNING( + ctx->logger, "Invalid HW packet index: %s()\n", __func__); return; @@ -1386,7 +1386,7 @@ static void dce110_se_setup_hdmi_audio( crtc_info->requested_pixel_clock, crtc_info->calculated_pixel_clock, &audio_clock_info); - dm_logger_write(enc->ctx->logger, LOG_HW_AUDIO, + DC_LOG_HW_AUDIO(enc->ctx->logger, "\n%s:Input::requested_pixel_clock = %d" \ "calculated_pixel_clock = %d \n", __func__, \ crtc_info->requested_pixel_clock, \ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c index ad411dac5639..5268197678f5 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c @@ -693,7 +693,7 @@ static int dce_transform_get_max_num_of_supported_lines( break; default: - dm_logger_write(xfm_dce->base.ctx->logger, LOG_WARNING, + DC_LOG_WARNING(xfm_dce->base.ctx->logger, "%s: Invalid LB pixel depth", __func__); BREAK_TO_DEBUGGER(); @@ -791,7 +791,7 @@ static void dce_transform_set_pixel_storage_depth( if (!(xfm_dce->lb_pixel_depth_supported & depth)) { /*we should use unsupported capabilities * unless it is required by w/a*/ - dm_logger_write(xfm->ctx->logger, LOG_WARNING, + DC_LOG_WARNING(xfm->ctx->logger, "%s: Capability not supported", __func__); } @@ -1172,7 +1172,7 @@ static void program_pwl(struct dce_transform *xfm_dce, } if (counter == max_tries) { - dm_logger_write(xfm_dce->base.ctx->logger, LOG_WARNING, + DC_LOG_WARNING(xfm_dce->base.ctx->logger, "%s: regamma lut was not powered on " "in a timely manner," " programming still proceeds\n", 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 6923662413cd..af854f21e9f5 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c @@ -120,13 +120,13 @@ static void wait_for_fbc_state_changed( } if (counter == 10) { - dm_logger_write( - cp110->base.ctx->logger, LOG_WARNING, + DC_LOG_WARNING( + cp110->base.ctx->logger, "%s: wait counter exceeded, changes to HW not applied", __func__); } else { - dm_logger_write( - cp110->base.ctx->logger, LOG_SYNC, + DC_LOG_SYNC( + cp110->base.ctx->logger, "FBC status changed to %d", enabled); } @@ -310,8 +310,8 @@ void dce110_compressor_program_compressed_surface_address_and_pitch( if (compressor->min_compress_ratio == FBC_COMPRESS_RATIO_1TO1) fbc_pitch = fbc_pitch / 8; else - dm_logger_write( - compressor->ctx->logger, LOG_WARNING, + DC_LOG_WARNING( + compressor->ctx->logger, "%s: Unexpected DCE11 compression ratio", __func__); 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 73e0bcd5ba8f..9e31f06ab4c8 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 @@ -816,7 +816,7 @@ void hwss_edp_wait_for_hpd_ready( dal_gpio_destroy_irq(&hpd); if (false == edp_hpd_high) { - dm_logger_write(ctx->logger, LOG_ERROR, + DC_LOG_ERROR(ctx->logger, "%s: wait timed out!\n", __func__); } } @@ -840,7 +840,7 @@ void hwss_edp_power_control( if (power_up != is_panel_powered_on(hwseq)) { /* Send VBIOS command to prompt eDP panel power */ - dm_logger_write(ctx->logger, LOG_HW_RESUME_S3, + DC_LOG_HW_RESUME_S3(ctx->logger, "%s: Panel Power action: %s\n", __func__, (power_up ? "On":"Off")); @@ -856,11 +856,11 @@ void hwss_edp_power_control( bp_result = link_transmitter_control(ctx->dc_bios, &cntl); if (bp_result != BP_RESULT_OK) - dm_logger_write(ctx->logger, LOG_ERROR, + DC_LOG_ERROR(ctx->logger, "%s: Panel Power bp_result: %d\n", __func__, bp_result); } else { - dm_logger_write(ctx->logger, LOG_HW_RESUME_S3, + DC_LOG_HW_RESUME_S3(ctx->logger, "%s: Skipping Panel Power action: %s\n", __func__, (power_up ? "On":"Off")); } @@ -886,7 +886,7 @@ void hwss_edp_backlight_control( } if (enable && is_panel_backlight_on(hws)) { - dm_logger_write(ctx->logger, LOG_HW_RESUME_S3, + DC_LOG_HW_RESUME_S3(ctx->logger, "%s: panel already powered up. Do nothing.\n", __func__); return; @@ -894,7 +894,7 @@ void hwss_edp_backlight_control( /* Send VBIOS command to control eDP panel backlight */ - dm_logger_write(ctx->logger, LOG_HW_RESUME_S3, + DC_LOG_HW_RESUME_S3(ctx->logger, "%s: backlight action: %s\n", __func__, (enable ? "On":"Off")); @@ -2762,7 +2762,7 @@ static void dce110_program_front_end_for_pipe( if (pipe_ctx->plane_state->update_flags.bits.full_update) dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); - dm_logger_write(dc->ctx->logger, LOG_SURFACE, + DC_LOG_SURFACE(dc->ctx->logger, "Pipe:%d 0x%x: addr hi:0x%x, " "addr low:0x%x, " "src: %d, %d, %d," @@ -2785,7 +2785,7 @@ static void dce110_program_front_end_for_pipe( pipe_ctx->plane_state->clip_rect.width, pipe_ctx->plane_state->clip_rect.height); - dm_logger_write(dc->ctx->logger, LOG_SURFACE, + DC_LOG_SURFACE(dc->ctx->logger, "Pipe %d: width, height, x, y\n" "viewport:%d, %d, %d, %d\n" "recout: %d, %d, %d, %d\n", diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index c4e877ac95d3..d938047fc17f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -771,8 +771,8 @@ static bool dce110_validate_bandwidth( { bool result = false; - dm_logger_write( - dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS( + dc->ctx->logger, "%s: start", __func__); @@ -786,7 +786,7 @@ static bool dce110_validate_bandwidth( result = true; if (!result) - dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_VALIDATION, + DC_LOG_BANDWIDTH_VALIDATION(dc->ctx->logger, "%s: %dx%d@%d Bandwidth validation failed!\n", __func__, context->streams[0]->timing.h_addressable, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c index 59b4cd329715..a8e93072ab5c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c @@ -606,7 +606,7 @@ static uint32_t dce110_timing_generator_v_get_vblank_counter(struct timing_gener static bool dce110_timing_generator_v_did_triggered_reset_occur( struct timing_generator *tg) { - dm_logger_write(tg->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(tg->ctx->logger, "Timing Sync not supported on underlay pipe\n"); return false; } @@ -615,7 +615,7 @@ static void dce110_timing_generator_v_setup_global_swap_lock( struct timing_generator *tg, const struct dcp_gsl_params *gsl_params) { - dm_logger_write(tg->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(tg->ctx->logger, "Timing Sync not supported on underlay pipe\n"); return; } @@ -624,7 +624,7 @@ static void dce110_timing_generator_v_enable_reset_trigger( struct timing_generator *tg, int source_tg_inst) { - dm_logger_write(tg->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(tg->ctx->logger, "Timing Sync not supported on underlay pipe\n"); return; } @@ -632,7 +632,7 @@ static void dce110_timing_generator_v_enable_reset_trigger( static void dce110_timing_generator_v_disable_reset_trigger( struct timing_generator *tg) { - dm_logger_write(tg->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(tg->ctx->logger, "Timing Sync not supported on underlay pipe\n"); return; } @@ -640,7 +640,7 @@ static void dce110_timing_generator_v_disable_reset_trigger( static void dce110_timing_generator_v_tear_down_global_swap_lock( struct timing_generator *tg) { - dm_logger_write(tg->ctx->logger, LOG_ERROR, + DC_LOG_ERROR(tg->ctx->logger, "Timing Sync not supported on underlay pipe\n"); return; } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c index 47390dc58306..809db96a8ba5 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c @@ -670,7 +670,7 @@ static void dce110_xfmv_set_pixel_storage_depth( if (!(xfm_dce->lb_pixel_depth_supported & depth)) { /*we should use unsupported capabilities * unless it is required by w/a*/ - dm_logger_write(xfm->ctx->logger, LOG_WARNING, + DC_LOG_WARNING(xfm->ctx->logger, "%s: Capability not supported", __func__); } diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c index 69649928768c..196ddd01615c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c @@ -129,8 +129,8 @@ static uint32_t lpt_memory_control_config(struct dce112_compressor *cp110, LOW_POWER_TILING_NUM_PIPES); break; default: - dm_logger_write( - cp110->base.ctx->logger, LOG_WARNING, + DC_LOG_WARNING( + cp110->base.ctx->logger, "%s: Invalid LPT NUM_PIPES!!!", __func__); break; @@ -175,8 +175,8 @@ static uint32_t lpt_memory_control_config(struct dce112_compressor *cp110, LOW_POWER_TILING_NUM_BANKS); break; default: - dm_logger_write( - cp110->base.ctx->logger, LOG_WARNING, + DC_LOG_WARNING( + cp110->base.ctx->logger, "%s: Invalid LPT NUM_BANKS!!!", __func__); break; @@ -209,8 +209,8 @@ static uint32_t lpt_memory_control_config(struct dce112_compressor *cp110, LOW_POWER_TILING_PIPE_INTERLEAVE_SIZE); break; default: - dm_logger_write( - cp110->base.ctx->logger, LOG_WARNING, + DC_LOG_WARNING( + cp110->base.ctx->logger, "%s: Invalid LPT INTERLEAVE_SIZE!!!", __func__); break; @@ -253,15 +253,15 @@ static uint32_t lpt_memory_control_config(struct dce112_compressor *cp110, LOW_POWER_TILING_ROW_SIZE); break; default: - dm_logger_write( - cp110->base.ctx->logger, LOG_WARNING, + DC_LOG_WARNING( + cp110->base.ctx->logger, "%s: Invalid LPT ROW_SIZE!!!", __func__); break; } } else { - dm_logger_write( - cp110->base.ctx->logger, LOG_WARNING, + DC_LOG_WARNING( + cp110->base.ctx->logger, "%s: LPT MC Configuration is not provided", __func__); } @@ -311,8 +311,8 @@ static void wait_for_fbc_state_changed( } if (counter == 10) { - dm_logger_write( - cp110->base.ctx->logger, LOG_WARNING, + DC_LOG_WARNING( + cp110->base.ctx->logger, "%s: wait counter exceeded, changes to HW not applied", __func__); } @@ -525,8 +525,8 @@ void dce112_compressor_program_compressed_surface_address_and_pitch( if (compressor->min_compress_ratio == FBC_COMPRESS_RATIO_1TO1) fbc_pitch = fbc_pitch / 8; else - dm_logger_write( - compressor->ctx->logger, LOG_WARNING, + DC_LOG_WARNING( + compressor->ctx->logger, "%s: Unexpected DCE11 compression ratio", __func__); @@ -690,8 +690,8 @@ void dce112_compressor_program_lpt_control( LOW_POWER_TILING_MODE); break; default: - dm_logger_write( - compressor->ctx->logger, LOG_WARNING, + DC_LOG_WARNING( + compressor->ctx->logger, "%s: Invalid selected DRAM channels for LPT!!!", __func__); break; diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index c0757dd6c03c..bf885d7e699b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -722,8 +722,8 @@ bool dce112_validate_bandwidth( { bool result = false; - dm_logger_write( - dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS( + dc->ctx->logger, "%s: start", __func__); @@ -737,7 +737,7 @@ bool dce112_validate_bandwidth( result = true; if (!result) - dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_VALIDATION, + DC_LOG_BANDWIDTH_VALIDATION(dc->ctx->logger, "%s: Bandwidth validation failed!", __func__); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c index f984583b9caa..c1711f79ce6d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -147,7 +147,7 @@ bool hubbub1_verify_allow_pstate_change_high( if (debug_data & (1 << 30)) { if (i > pstate_wait_expected_timeout_us) - dm_logger_write(hubbub->ctx->logger, LOG_WARNING, + DC_LOG_WARNING(hubbub->ctx->logger, "pstate took longer than expected ~%dus\n", i); @@ -167,7 +167,7 @@ bool hubbub1_verify_allow_pstate_change_high( DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 1); forced_pstate_allow = true; - dm_logger_write(hubbub->ctx->logger, LOG_WARNING, + DC_LOG_WARNING(hubbub->ctx->logger, "pstate TEST_DEBUG_DATA: 0x%X\n", debug_data); @@ -211,7 +211,7 @@ void hubbub1_program_watermarks( refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "URGENCY_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n", watermarks->a.urgent_ns, prog_wm_value); @@ -219,7 +219,7 @@ void hubbub1_program_watermarks( prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "PTE_META_URGENCY_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n", watermarks->a.pte_meta_urgent_ns, prog_wm_value); @@ -229,7 +229,7 @@ void hubbub1_program_watermarks( watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n", watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); @@ -239,7 +239,7 @@ void hubbub1_program_watermarks( watermarks->a.cstate_pstate.cstate_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "SR_EXIT_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n", watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); @@ -249,7 +249,7 @@ void hubbub1_program_watermarks( watermarks->a.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n\n", watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); @@ -259,7 +259,7 @@ void hubbub1_program_watermarks( prog_wm_value = convert_and_clamp( watermarks->b.urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "URGENCY_WATERMARK_B calculated =%d\n" "HW register value = 0x%x\n", watermarks->b.urgent_ns, prog_wm_value); @@ -269,7 +269,7 @@ void hubbub1_program_watermarks( watermarks->b.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "PTE_META_URGENCY_WATERMARK_B calculated =%d\n" "HW register value = 0x%x\n", watermarks->b.pte_meta_urgent_ns, prog_wm_value); @@ -280,7 +280,7 @@ void hubbub1_program_watermarks( watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "SR_ENTER_WATERMARK_B calculated =%d\n" "HW register value = 0x%x\n", watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); @@ -290,7 +290,7 @@ void hubbub1_program_watermarks( watermarks->b.cstate_pstate.cstate_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "SR_EXIT_WATERMARK_B calculated =%d\n" "HW register value = 0x%x\n", watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); @@ -300,7 +300,7 @@ void hubbub1_program_watermarks( watermarks->b.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n\n" "HW register value = 0x%x\n", watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); @@ -309,7 +309,7 @@ void hubbub1_program_watermarks( prog_wm_value = convert_and_clamp( watermarks->c.urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "URGENCY_WATERMARK_C calculated =%d\n" "HW register value = 0x%x\n", watermarks->c.urgent_ns, prog_wm_value); @@ -319,7 +319,7 @@ void hubbub1_program_watermarks( watermarks->c.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "PTE_META_URGENCY_WATERMARK_C calculated =%d\n" "HW register value = 0x%x\n", watermarks->c.pte_meta_urgent_ns, prog_wm_value); @@ -330,7 +330,7 @@ void hubbub1_program_watermarks( watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "SR_ENTER_WATERMARK_C calculated =%d\n" "HW register value = 0x%x\n", watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); @@ -340,7 +340,7 @@ void hubbub1_program_watermarks( watermarks->c.cstate_pstate.cstate_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "SR_EXIT_WATERMARK_C calculated =%d\n" "HW register value = 0x%x\n", watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); @@ -350,7 +350,7 @@ void hubbub1_program_watermarks( watermarks->c.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n\n" "HW register value = 0x%x\n", watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); @@ -359,7 +359,7 @@ void hubbub1_program_watermarks( prog_wm_value = convert_and_clamp( watermarks->d.urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "URGENCY_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n", watermarks->d.urgent_ns, prog_wm_value); @@ -368,7 +368,7 @@ void hubbub1_program_watermarks( watermarks->d.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "PTE_META_URGENCY_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n", watermarks->d.pte_meta_urgent_ns, prog_wm_value); @@ -379,7 +379,7 @@ void hubbub1_program_watermarks( watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "SR_ENTER_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n", watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); @@ -389,7 +389,7 @@ void hubbub1_program_watermarks( watermarks->d.cstate_pstate.cstate_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "SR_EXIT_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n", watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); @@ -400,7 +400,7 @@ void hubbub1_program_watermarks( watermarks->d.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); - dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, "DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n\n", watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index b4a6b6729e62..aa5516539c95 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -335,7 +335,7 @@ static void power_on_plane( hubp_pg_control(hws, plane_id, true); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); - dm_logger_write(hws->ctx->logger, LOG_DEBUG, + DC_LOG_DEBUG(hws->ctx->logger, "Un-gated front end for pipe %d\n", plane_id); } } @@ -572,7 +572,7 @@ static void reset_back_end_for_pipe( return; pipe_ctx->stream = NULL; - dm_logger_write(dc->ctx->logger, LOG_DEBUG, + DC_LOG_DEBUG(dc->ctx->logger, "Reset back end for pipe %d, tg:%d\n", pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); } @@ -632,7 +632,7 @@ static void plane_atomic_power_down(struct dc *dc, struct pipe_ctx *pipe_ctx) dpp->funcs->dpp_reset(dpp); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); - dm_logger_write(dc->ctx->logger, LOG_DEBUG, + DC_LOG_DEBUG(dc->ctx->logger, "Power gated front end %d\n", pipe_ctx->pipe_idx); } } @@ -679,7 +679,7 @@ static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) apply_DEGVIDCN10_253_wa(dc); - dm_logger_write(dc->ctx->logger, LOG_DC, + DC_LOG_DC(dc->ctx->logger, "Power down front end %d\n", pipe_ctx->pipe_idx); } @@ -1102,7 +1102,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( struct dc *core_dc, struct pipe_ctx *pipe_ctx) { - dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, "\n============== DML TTU Output parameters [%d] ==============\n" "qos_level_low_wm: %d, \n" "qos_level_high_wm: %d, \n" @@ -1132,7 +1132,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_c ); - dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, "\n============== DML DLG Output parameters [%d] ==============\n" "refcyc_h_blank_end: %d, \n" "dlg_vblank_end: %d, \n" @@ -1167,7 +1167,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_l ); - dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, "\ndst_y_per_meta_row_nom_l: %d, \n" "refcyc_per_meta_chunk_nom_l: %d, \n" "refcyc_per_line_delivery_pre_l: %d, \n" @@ -1197,7 +1197,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( pipe_ctx->dlg_regs.refcyc_per_line_delivery_c ); - dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, "\n============== DML RQ Output parameters [%d] ==============\n" "chunk_size: %d \n" "min_chunk_size: %d \n" @@ -1330,7 +1330,7 @@ static void dcn10_enable_plane( /* TODO: enable/disable in dm as per update type. if (plane_state) { - dm_logger_write(dc->ctx->logger, LOG_DC, + DC_LOG_DC(dc->ctx->logger, "Pipe:%d 0x%x: addr hi:0x%x, " "addr low:0x%x, " "src: %d, %d, %d," @@ -1348,7 +1348,7 @@ static void dcn10_enable_plane( plane_state->dst_rect.width, plane_state->dst_rect.height); - dm_logger_write(dc->ctx->logger, LOG_DC, + DC_LOG_DC(dc->ctx->logger, "Pipe %d: width, height, x, y format:%d\n" "viewport:%d, %d, %d, %d\n" "recout: %d, %d, %d, %d\n", @@ -1959,7 +1959,7 @@ static void dcn10_apply_ctx_for_surface( plane_atomic_disconnect(dc, old_pipe_ctx); removed_pipe[i] = true; - dm_logger_write(dc->ctx->logger, LOG_DC, + DC_LOG_DC(dc->ctx->logger, "Reset mpcc for pipe %d\n", old_pipe_ctx->pipe_idx); } @@ -2002,7 +2002,7 @@ static void dcn10_apply_ctx_for_surface( dcn10_verify_allow_pstate_change_high(dc); } } -/* dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS, +/* DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\n============== Watermark parameters ==============\n" "a.urgent_ns: %d \n" "a.cstate_enter_plus_exit: %d \n" @@ -2025,7 +2025,7 @@ static void dcn10_apply_ctx_for_surface( context->bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns, context->bw.dcn.watermarks.b.pte_meta_urgent_ns ); - dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\nc.urgent_ns: %d \n" "c.cstate_enter_plus_exit: %d \n" "c.cstate_exit: %d \n" @@ -2268,7 +2268,7 @@ static void dcn10_wait_for_mpcc_disconnect( res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst); pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; hubp->funcs->set_blank(hubp, true); - /*dm_logger_write(dc->ctx->logger, LOG_ERROR, + /*DC_LOG_ERROR(dc->ctx->logger, "[debug_mpo: wait_for_mpcc finished waiting on mpcc %d]\n", i);*/ } diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c index 9c42fe5a0f27..eacc9ebd6933 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c @@ -274,7 +274,7 @@ static bool read_command( if (request->payload.address_space == I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { - dm_logger_write(engine->base.ctx->logger, LOG_I2C_AUX, "READ: addr:0x%x value:0x%x Result:%d", + DC_LOG_I2C_AUX(engine->base.ctx->logger, "READ: addr:0x%x value:0x%x Result:%d", request->payload.address, request->payload.data[0], ctx.operation_succeeded); @@ -483,7 +483,7 @@ static bool write_command( if (request->payload.address_space == I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { - dm_logger_write(engine->base.ctx->logger, LOG_I2C_AUX, "WRITE: addr:0x%x value:0x%x Result:%d", + DC_LOG_I2C_AUX(engine->base.ctx->logger, "WRITE: addr:0x%x value:0x%x Result:%d", request->payload.address, request->payload.data[0], ctx.operation_succeeded); diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c index 56e25b3d65fd..ad685b1c9b81 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c @@ -525,8 +525,8 @@ static void construct( REG_GET(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, &xtal_ref_div); if (xtal_ref_div == 0) { - dm_logger_write( - hw_engine->base.base.base.ctx->logger, LOG_WARNING, + DC_LOG_WARNING( + hw_engine->base.base.base.ctx->logger, "Invalid base timer divider\n", __func__); xtal_ref_div = 2; diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c index f7e40b292dfb..e3de56b7ac5f 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c @@ -181,8 +181,8 @@ bool dal_irq_service_dummy_set( const struct irq_source_info *info, bool enable) { - dm_logger_write( - irq_service->ctx->logger, LOG_ERROR, + DC_LOG_ERROR( + irq_service->ctx->logger, "%s: called for non-implemented irq source\n", __func__); return false; @@ -192,8 +192,8 @@ bool dal_irq_service_dummy_ack( struct irq_service *irq_service, const struct irq_source_info *info) { - dm_logger_write( - irq_service->ctx->logger, LOG_ERROR, + DC_LOG_ERROR( + irq_service->ctx->logger, "%s: called for non-implemented irq source\n", __func__); return false; diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c index b106513fc2dc..441724776441 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c @@ -104,8 +104,8 @@ bool dal_irq_service_set( find_irq_source_info(irq_service, source); if (!info) { - dm_logger_write( - irq_service->ctx->logger, LOG_ERROR, + DC_LOG_ERROR( + irq_service->ctx->logger, "%s: cannot find irq info table entry for %d\n", __func__, source); @@ -142,8 +142,8 @@ bool dal_irq_service_ack( find_irq_source_info(irq_service, source); if (!info) { - dm_logger_write( - irq_service->ctx->logger, LOG_ERROR, + DC_LOG_ERROR( + irq_service->ctx->logger, "%s: cannot find irq info table entry for %d\n", __func__, source); diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h index e2ff8cd423d6..65b6bf892839 100644 --- a/drivers/gpu/drm/amd/display/include/logger_types.h +++ b/drivers/gpu/drm/amd/display/include/logger_types.h @@ -29,6 +29,39 @@ #include "os_types.h" #define MAX_NAME_LEN 32 +#define DC_LOG_ERROR(a, b, ...) dm_logger_write(a, LOG_ERROR, b, ## __VA_ARGS__) +#define DC_LOG_WARNING(a, b, ...) dm_logger_write(a, LOG_WARNING, b, ## __VA_ARGS__) +#define DC_LOG_DEBUG(a, b, ...) dm_logger_write(a, LOG_DEBUG, b, ## __VA_ARGS__) +#define DC_LOG_DC(a, b, ...) dm_logger_write(a, LOG_DC, b, ## __VA_ARGS__) +#define DC_LOG_DTN(a, b, ...) dm_logger_write(a, LOG_DTN, b, ## __VA_ARGS__) +#define DC_LOG_SURFACE(a, b, ...) dm_logger_write(a, LOG_SURFACE, b, ## __VA_ARGS__) +#define DC_LOG_HW_HOTPLUG(a, b, ...) dm_logger_write(a, LOG_HW_HOTPLUG, b, ## __VA_ARGS__) +#define DC_LOG_HW_LINK_TRAINING(a, b, ...) dm_logger_write(a, LOG_HW_LINK_TRAINING, b, ## __VA_ARGS__) +#define DC_LOG_HW_SET_MODE(a, b, ...) dm_logger_write(a, LOG_HW_SET_MODE, b, ## __VA_ARGS__) +#define DC_LOG_HW_RESUME_S3(a, b, ...) dm_logger_write(a, LOG_HW_RESUME_S3, b, ## __VA_ARGS__) +#define DC_LOG_HW_AUDIO(a, b, ...) dm_logger_write(a, LOG_HW_AUDIO, b, ## __VA_ARGS__) +#define DC_LOG_HW_HPD_IRQ(a, b, ...) dm_logger_write(a, LOG_HW_HPD_IRQ, b, ## __VA_ARGS__) +#define DC_LOG_MST(a, b, ...) dm_logger_write(a, LOG_MST, b, ## __VA_ARGS__) +#define DC_LOG_SCALER(a, b, ...) dm_logger_write(a, LOG_SCALER, b, ## __VA_ARGS__) +#define DC_LOG_BIOS(a, b, ...) dm_logger_write(a, LOG_BIOS, b, ## __VA_ARGS__) +#define DC_LOG_BANDWIDTH_CALCS(a, b, ...) dm_logger_write(a, LOG_BANDWIDTH_CALCS, b, ## __VA_ARGS__) +#define DC_LOG_BANDWIDTH_VALIDATION(a, b, ...) dm_logger_write(a, LOG_BANDWIDTH_VALIDATION, b, ## __VA_ARGS__) +#define DC_LOG_I2C_AUX(a, b, ...) dm_logger_write(a, LOG_I2C_AUX, b, ## __VA_ARGS__) +#define DC_LOG_SYNC(a, b, ...) dm_logger_write(a, LOG_SYNC, b, ## __VA_ARGS__) +#define DC_LOG_BACKLIGHT(a, b, ...) dm_logger_write(a, LOG_BACKLIGHT, b, ## __VA_ARGS__) +#define DC_LOG_FEATURE_OVERRIDE(a, b, ...) dm_logger_write(a, LOG_FEATURE_OVERRIDE, b, ## __VA_ARGS__) +#define DC_LOG_DETECTION_EDID_PARSER(a, b, ...) dm_logger_write(a, LOG_DETECTION_EDID_PARSER, b, ## __VA_ARGS__) +#define DC_LOG_DETECTION_DP_CAPS(a, b, ...) dm_logger_write(a, LOG_DETECTION_DP_CAPS, b, ## __VA_ARGS__) +#define DC_LOG_RESOURCE(a, b, ...) dm_logger_write(a, LOG_RESOURCE, b, ## __VA_ARGS__) +#define DC_LOG_DML(a, b, ...) dm_logger_write(a, LOG_DML, b, ## __VA_ARGS__) +#define DC_LOG_EVENT_MODE_SET(a, b, ...) dm_logger_write(a, LOG_EVENT_MODE_SET, b, ## __VA_ARGS__) +#define DC_LOG_EVENT_DETECTION(a, b, ...) dm_logger_write(a, LOG_EVENT_DETECTION, b, ## __VA_ARGS__) +#define DC_LOG_EVENT_LINK_TRAINING(a, b, ...) dm_logger_write(a, LOG_EVENT_LINK_TRAINING, b, ## __VA_ARGS__) +#define DC_LOG_EVENT_LINK_LOSS(a, b, ...) dm_logger_write(a, LOG_EVENT_LINK_LOSS, b, ## __VA_ARGS__) +#define DC_LOG_EVENT_UNDERFLOW(a, b, ...) dm_logger_write(a, LOG_EVENT_UNDERFLOW, b, ## __VA_ARGS__) +#define DC_LOG_IF_TRACE(a, b, ...) dm_logger_write(a, LOG_IF_TRACE, b, ## __VA_ARGS__) +#define DC_LOG_PERF_TRACE(a, b, ...) dm_logger_write(a, LOG_PERF_TRACE, b, ## __VA_ARGS__) + struct dal_logger; -- cgit v1.2.3 From 1296423bf23c7a58133970e223b1f47ec6570308 Mon Sep 17 00:00:00 2001 From: Bhawanpreet Lakha Date: Tue, 20 Feb 2018 17:42:50 -0500 Subject: drm/amd/display: define DC_LOGGER for logger Created a DC_LOGGER define. This is used to pass the logger into the macros. Anywhere we need to use the logger we need to define DC_LOGGER Signed-off-by: Bhawanpreet Lakha Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 6 +- .../gpu/drm/amd/display/dc/bios/command_table2.c | 11 ++-- drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 11 ++-- drivers/gpu/drm/amd/display/dc/core/dc.c | 11 ++-- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 53 +++++++---------- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 53 ++++++----------- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 7 ++- drivers/gpu/drm/amd/display/dc/dce/dce_abm.c | 5 +- drivers/gpu/drm/amd/display/dc/dce/dce_audio.c | 17 +++--- .../gpu/drm/amd/display/dc/dce/dce_clock_source.c | 32 +++++----- drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c | 8 +-- .../gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 22 +++---- .../drm/amd/display/dc/dce/dce_stream_encoder.c | 7 +-- drivers/gpu/drm/amd/display/dc/dce/dce_transform.c | 11 ++-- .../drm/amd/display/dc/dce110/dce110_compressor.c | 14 ++--- .../amd/display/dc/dce110/dce110_hw_sequencer.c | 20 ++++--- .../drm/amd/display/dc/dce110/dce110_resource.c | 6 +- .../display/dc/dce110/dce110_timing_generator_v.c | 17 +++--- .../drm/amd/display/dc/dce110/dce110_transform_v.c | 5 +- .../drm/amd/display/dc/dce112/dce112_compressor.c | 11 +--- .../drm/amd/display/dc/dce112/dce112_resource.c | 5 +- .../gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c | 68 ++++++++-------------- .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 21 ++++--- drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c | 6 +- .../dc/i2caux/dce110/i2c_hw_engine_dce110.c | 6 +- .../amd/display/dc/irq/dce110/irq_service_dce110.c | 11 ++-- drivers/gpu/drm/amd/display/dc/irq/irq_service.c | 10 ++-- drivers/gpu/drm/amd/display/include/logger_types.h | 64 ++++++++++---------- 28 files changed, 230 insertions(+), 288 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index 52f524a55b57..c7f0b27e457e 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -49,6 +49,9 @@ #define LAST_RECORD_TYPE 0xff +#define DC_LOGGER \ + bp->base.ctx->logger + /* GUID to validate external display connection info table (aka OPM module) */ static const uint8_t ext_display_connection_guid[NUMBER_OF_UCHAR_FOR_GUID] = { 0x91, 0x6E, 0x57, 0x09, @@ -3079,8 +3082,7 @@ static enum bp_result patch_bios_image_from_ext_display_connection_info( opm_object, &ext_display_connection_info_tbl) != BP_RESULT_OK) { - DC_LOG_WARNING(bp->base.ctx->logger, - "%s: Failed to read Connection Info Table", __func__); + DC_LOG_WARNING("%s: Failed to read Connection Info Table", __func__); return BP_RESULT_UNSUPPORTED; } diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index 03df7b7a2d80..e362658aa3ce 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -34,6 +34,8 @@ #include "command_table_helper2.h" #include "bios_parser_helper.h" #include "bios_parser_types_internal2.h" +#define DC_LOGGER \ + bp->base.ctx->logger #define GET_INDEX_INTO_MASTER_TABLE(MasterOrData, FieldName)\ (((char *)(&((\ @@ -239,8 +241,7 @@ static enum bp_result transmitter_control_v1_6( if (cntl->action == TRANSMITTER_CONTROL_ENABLE || cntl->action == TRANSMITTER_CONTROL_ACTIAVATE || cntl->action == TRANSMITTER_CONTROL_DEACTIVATE) { - DC_LOG_BIOS(bp->base.ctx->logger, \ - "%s:ps.param.symclk_10khz = %d\n",\ + DC_LOG_BIOS("%s:ps.param.symclk_10khz = %d\n",\ __func__, ps.param.symclk_10khz); } @@ -331,8 +332,7 @@ static enum bp_result set_pixel_clock_v7( (uint8_t) bp->cmd_helper-> transmitter_color_depth_to_atom( bp_params->color_depth); - DC_LOG_BIOS(bp->base.ctx->logger, \ - "%s:program display clock = %d"\ + DC_LOG_BIOS("%s:program display clock = %d"\ "colorDepth = %d\n", __func__,\ bp_params->target_pixel_clock, bp_params->color_depth); @@ -772,8 +772,7 @@ static enum bp_result set_dce_clock_v2_1( */ params.param.dceclk_10khz = cpu_to_le32( bp_params->target_clock_frequency / 10); - DC_LOG_BIOS(bp->base.ctx->logger, - "%s:target_clock_frequency = %d"\ + DC_LOG_BIOS("%s:target_clock_frequency = %d"\ "clock_type = %d \n", __func__,\ bp_params->target_clock_frequency,\ bp_params->clock_type); diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 7728c85bcb0e..f1d8db56f406 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -33,6 +33,8 @@ #include "dcn10/dcn10_resource.h" #include "dcn_calc_math.h" +#define DC_LOGGER \ + dc->ctx->logger /* * NOTE: * This file is gcc-parseable HW gospel, coming straight from HW engineers. @@ -1242,8 +1244,7 @@ unsigned int dcn_find_dcfclk_suits_all( else dcf_clk = dc->dcn_soc->dcfclkv_min0p65*1000; - DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, - "\tdcf_clk for voltage = %d\n", dcf_clk); + DC_LOG_BANDWIDTH_CALCS("\tdcf_clk for voltage = %d\n", dcf_clk); return dcf_clk; } @@ -1441,8 +1442,7 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc) void dcn_bw_sync_calcs_and_dml(struct dc *dc) { kernel_fpu_begin(); - DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, - "sr_exit_time: %d ns\n" + DC_LOG_BANDWIDTH_CALCS("sr_exit_time: %d ns\n" "sr_enter_plus_exit_time: %d ns\n" "urgent_latency: %d ns\n" "write_back_latency: %d ns\n" @@ -1510,8 +1510,7 @@ void dcn_bw_sync_calcs_and_dml(struct dc *dc) dc->dcn_soc->vmm_page_size, dc->dcn_soc->dram_clock_change_latency * 1000, dc->dcn_soc->return_bus_width); - DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, - "rob_buffer_size_in_kbyte: %d\n" + DC_LOG_BANDWIDTH_CALCS("rob_buffer_size_in_kbyte: %d\n" "det_buffer_size_in_kbyte: %d\n" "dpp_output_buffer_pixels: %d\n" "opp_output_buffer_lines: %d\n" diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 73bb416cb7dc..2bc15a46882a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -51,6 +51,8 @@ #include "dm_helpers.h" #include "mem_input.h" #include "hubp.h" +#define DC_LOGGER \ + dc->ctx->logger /******************************************************************************* @@ -264,7 +266,7 @@ bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream, /* Only call if supported */ if (tg->funcs->configure_crc) return tg->funcs->configure_crc(tg, ¶m); - DC_LOG_WARNING(dc->ctx->logger, "CRC capture not supported."); + DC_LOG_WARNING("CRC capture not supported."); return false; } @@ -297,7 +299,7 @@ bool dc_stream_get_crc(struct dc *dc, struct dc_stream_state *stream, if (tg->funcs->get_crc) return tg->funcs->get_crc(tg, r_cr, g_y, b_cb); - DC_LOG_WARNING(dc->ctx->logger, "CRC capture not supported."); + DC_LOG_WARNING("CRC capture not supported."); return false; } @@ -618,8 +620,7 @@ struct dc *dc_create(const struct dc_init_data *init_params) dc->config = init_params->flags; - DC_LOG_DC(dc->ctx->logger, - "Display Core initialized\n"); + DC_LOG_DC("Display Core initialized\n"); /* TODO: missing feature to be enabled */ @@ -888,7 +889,7 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context) if (false == context_changed(dc, context)) return DC_OK; - DC_LOG_DC(dc->ctx->logger, "%s: %d streams\n", + DC_LOG_DC("%s: %d streams\n", __func__, context->stream_count); for (i = 0; i < context->stream_count; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 059ceada2095..f8c09273e0f1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -45,9 +45,11 @@ #include "dce/dce_11_0_d.h" #include "dce/dce_11_0_enum.h" #include "dce/dce_11_0_sh_mask.h" +#define DC_LOGGER \ + dc_ctx->logger #define LINK_INFO(...) \ - DC_LOG_HW_HOTPLUG(dc_ctx->logger, \ + DC_LOG_HW_HOTPLUG( \ __VA_ARGS__) /******************************************************************************* @@ -677,12 +679,10 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) switch (edid_status) { case EDID_BAD_CHECKSUM: - DC_LOG_ERROR(link->ctx->logger, - "EDID checksum invalid.\n"); + DC_LOG_ERROR("EDID checksum invalid.\n"); break; case EDID_NO_RESPONSE: - DC_LOG_ERROR(link->ctx->logger, - "No EDID read.\n"); + DC_LOG_ERROR("No EDID read.\n"); default: break; } @@ -712,8 +712,7 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) "%s: [Block %d] ", sink->edid_caps.display_name, i); } - DC_LOG_DETECTION_EDID_PARSER(link->ctx->logger, - "%s: " + DC_LOG_DETECTION_EDID_PARSER("%s: " "manufacturer_id = %X, " "product_id = %X, " "serial_number = %X, " @@ -733,8 +732,7 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) sink->edid_caps.audio_mode_count); for (i = 0; i < sink->edid_caps.audio_mode_count; i++) { - DC_LOG_DETECTION_EDID_PARSER(link->ctx->logger, - "%s: mode number = %d, " + DC_LOG_DETECTION_EDID_PARSER("%s: mode number = %d, " "format_code = %d, " "channel_count = %d, " "sample_rate = %d, " @@ -984,8 +982,7 @@ static bool construct( } break; default: - DC_LOG_WARNING(dc_ctx->logger, - "Unsupported Connector type:%d!\n", link->link_id.id); + DC_LOG_WARNING("Unsupported Connector type:%d!\n", link->link_id.id); goto create_fail; } @@ -1138,7 +1135,7 @@ static void dpcd_configure_panel_mode( { union dpcd_edp_config edp_config_set; bool panel_mode_edp = false; - + struct dc_context *dc_ctx = link->ctx; memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config)); if (DP_PANEL_MODE_DEFAULT != panel_mode) { @@ -1175,8 +1172,7 @@ static void dpcd_configure_panel_mode( ASSERT(result == DDC_RESULT_SUCESSFULL); } } - DC_LOG_DETECTION_DP_CAPS(link->ctx->logger, - "Link: %d eDP panel mode supported: %d " + DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d " "eDP panel mode enabled: %d \n", link->link_index, link->dpcd_caps.panel_mode_edp, @@ -1954,6 +1950,7 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level, struct dc *core_dc = link->ctx->dc; struct abm *abm = core_dc->res_pool->abm; struct dmcu *dmcu = core_dc->res_pool->dmcu; + struct dc_context *dc_ctx = link->ctx; unsigned int controller_id = 0; bool use_smooth_brightness = true; int i; @@ -1965,8 +1962,7 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level, use_smooth_brightness = dmcu->funcs->is_dmcu_initialized(dmcu); - DC_LOG_BACKLIGHT(link->ctx->logger, - "New Backlight level: %d (0x%X)\n", level, level); + DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n", level, level); if (dc_is_embedded_signal(link->connector_signal)) { if (stream != NULL) { @@ -2133,6 +2129,7 @@ static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx) struct fixed31_32 avg_time_slots_per_mtp; struct fixed31_32 pbn; struct fixed31_32 pbn_per_slot; + struct dc_context *dc_ctx = link->ctx; uint8_t i; /* enable_link_dp_mst already check link->enabled_stream_count @@ -2150,21 +2147,18 @@ static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx) link, pipe_ctx->stream_res.stream_enc, &proposed_table); } else - DC_LOG_WARNING(link->ctx->logger, - "Failed to update" + DC_LOG_WARNING("Failed to update" "MST allocation table for" "pipe idx:%d\n", pipe_ctx->pipe_idx); - DC_LOG_MST(link->ctx->logger, - "%s " + DC_LOG_MST("%s " "stream_count: %d: \n ", __func__, link->mst_stream_alloc_table.stream_count); for (i = 0; i < MAX_CONTROLLER_NUM; i++) { - DC_LOG_MST(link->ctx->logger, - "stream_enc[%d]: 0x%x " + DC_LOG_MST("stream_enc[%d]: 0x%x " "stream[%d].vcp_id: %d " "stream[%d].slot_count: %d\n", i, @@ -2215,6 +2209,7 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) struct fixed31_32 avg_time_slots_per_mtp = dal_fixed31_32_from_int(0); uint8_t i; bool mst_mode = (link->type == dc_connection_mst_branch); + struct dc_context *dc_ctx = link->ctx; /* deallocate_mst_payload is called before disable link. When mode or * disable/enable monitor, new stream is created which is not in link @@ -2240,23 +2235,20 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) link, pipe_ctx->stream_res.stream_enc, &proposed_table); } else { - DC_LOG_WARNING(link->ctx->logger, - "Failed to update" + DC_LOG_WARNING("Failed to update" "MST allocation table for" "pipe idx:%d\n", pipe_ctx->pipe_idx); } } - DC_LOG_MST(link->ctx->logger, - "%s" + DC_LOG_MST("%s" "stream_count: %d: ", __func__, link->mst_stream_alloc_table.stream_count); for (i = 0; i < MAX_CONTROLLER_NUM; i++) { - DC_LOG_MST(link->ctx->logger, - "stream_enc[%d]: 0x%x " + DC_LOG_MST("stream_enc[%d]: 0x%x " "stream[%d].vcp_id: %d " "stream[%d].slot_count: %d\n", i, @@ -2290,7 +2282,7 @@ void core_link_enable_stream( struct pipe_ctx *pipe_ctx) { struct dc *core_dc = pipe_ctx->stream->ctx->dc; - + struct dc_context *dc_ctx = pipe_ctx->stream->ctx; enum dc_status status; /* eDP lit up by bios already, no need to enable again. */ @@ -2307,8 +2299,7 @@ void core_link_enable_stream( status = enable_link(state, pipe_ctx); if (status != DC_OK) { - DC_LOG_WARNING(pipe_ctx->stream->ctx->logger, - "enabling link %u failed: %d\n", + DC_LOG_WARNING("enabling link %u failed: %d\n", pipe_ctx->stream->sink->link->link_index, status); 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 9a041641a539..3b5053570229 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 @@ -11,6 +11,8 @@ #include "dpcd_defs.h" #include "resource.h" +#define DC_LOGGER \ + link->ctx->logger /* maximum pre emphasis level allowed for each voltage swing level*/ static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = { @@ -63,8 +65,7 @@ static void wait_for_training_aux_rd_interval( udelay(default_wait_in_micro_secs); - DC_LOG_HW_LINK_TRAINING(link->ctx->logger, - "%s:\n wait = %d\n", + DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n", __func__, default_wait_in_micro_secs); } @@ -79,8 +80,7 @@ static void dpcd_set_training_pattern( &dpcd_pattern.raw, 1); - DC_LOG_HW_LINK_TRAINING(link->ctx->logger, - "%s\n %x pattern = %x\n", + DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n", __func__, DP_TRAINING_PATTERN_SET, dpcd_pattern.v1_4.TRAINING_PATTERN_SET); @@ -116,8 +116,7 @@ static void dpcd_set_link_settings( core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, &downspread.raw, sizeof(downspread)); - DC_LOG_HW_LINK_TRAINING(link->ctx->logger, - "%s\n %x rate = %x\n %x lane = %x\n %x spread = %x\n", + DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x\n %x spread = %x\n", __func__, DP_LINK_BW_SET, lt_settings->link_settings.link_rate, @@ -151,8 +150,7 @@ static enum dpcd_training_patterns break; default: ASSERT(0); - DC_LOG_HW_LINK_TRAINING(link->ctx->logger, - "%s: Invalid HW Training pattern: %d\n", + DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n", __func__, pattern); break; } @@ -184,8 +182,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - dpcd_base_lt_offset] = dpcd_pattern.raw; - DC_LOG_HW_LINK_TRAINING(link->ctx->logger, - "%s\n %x pattern = %x\n", + DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n", __func__, DP_TRAINING_PATTERN_SET, dpcd_pattern.v1_4.TRAINING_PATTERN_SET); @@ -219,8 +216,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( dpcd_lane, size_in_bytes); - DC_LOG_HW_LINK_TRAINING(link->ctx->logger, - "%s:\n %x VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", + DC_LOG_HW_LINK_TRAINING("%s:\n %x VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", __func__, DP_TRAINING_LANE0_SET, dpcd_lane[0].bits.VOLTAGE_SWING_SET, @@ -456,14 +452,12 @@ static void get_lane_status_and_drive_settings( ln_status_updated->raw = dpcd_buf[2]; - DC_LOG_HW_LINK_TRAINING(link->ctx->logger, - "%s:\n%x Lane01Status = %x\n %x Lane23Status = %x\n ", + DC_LOG_HW_LINK_TRAINING("%s:\n%x Lane01Status = %x\n %x Lane23Status = %x\n ", __func__, DP_LANE0_1_STATUS, dpcd_buf[0], DP_LANE2_3_STATUS, dpcd_buf[1]); - DC_LOG_HW_LINK_TRAINING(link->ctx->logger, - "%s:\n %x Lane01AdjustRequest = %x\n %x Lane23AdjustRequest = %x\n", + DC_LOG_HW_LINK_TRAINING("%s:\n %x Lane01AdjustRequest = %x\n %x Lane23AdjustRequest = %x\n", __func__, DP_ADJUST_REQUEST_LANE0_1, dpcd_buf[4], @@ -556,8 +550,7 @@ static void dpcd_set_lane_settings( } */ - DC_LOG_HW_LINK_TRAINING(link->ctx->logger, - "%s\n %x VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", + DC_LOG_HW_LINK_TRAINING("%s\n %x VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", __func__, DP_TRAINING_LANE0_SET, dpcd_lane[0].bits.VOLTAGE_SWING_SET, @@ -669,16 +662,14 @@ static bool perform_post_lt_adj_req_sequence( } if (!req_drv_setting_changed) { - DC_LOG_WARNING(link->ctx->logger, - "%s: Post Link Training Adjust Request Timed out\n", + DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n", __func__); ASSERT(0); return true; } } - DC_LOG_WARNING(link->ctx->logger, - "%s: Post Link Training Adjust Request limit reached\n", + DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n", __func__); ASSERT(0); @@ -885,8 +876,7 @@ static enum link_training_result perform_clock_recovery_sequence( if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { ASSERT(0); - DC_LOG_ERROR(link->ctx->logger, - "%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", + DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", __func__, LINK_TRAINING_MAX_CR_RETRY); @@ -1606,8 +1596,7 @@ static bool hpd_rx_irq_check_link_loss_status( if (sink_status_changed || !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) { - DC_LOG_HW_HPD_IRQ(link->ctx->logger, - "%s: Link Status changed.\n", __func__); + DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__); return_code = true; @@ -1620,8 +1609,7 @@ static bool hpd_rx_irq_check_link_loss_status( sizeof(irq_reg_rx_power_state)); if (dpcd_result != DC_OK) { - DC_LOG_HW_HPD_IRQ(link->ctx->logger, - "%s: DPCD read failed to obtain power state.\n", + DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n", __func__); } else { if (irq_reg_rx_power_state != DP_SET_POWER_D0) @@ -1982,8 +1970,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd * PSR and device auto test, refer to function handle_sst_hpd_irq * in DAL2.1*/ - DC_LOG_HW_HPD_IRQ(link->ctx->logger, - "%s: Got short pulse HPD on link %d\n", + DC_LOG_HW_HPD_IRQ("%s: Got short pulse HPD on link %d\n", __func__, link->link_index); @@ -1997,8 +1984,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd *out_hpd_irq_dpcd_data = hpd_irq_dpcd_data; if (result != DC_OK) { - DC_LOG_HW_HPD_IRQ(link->ctx->logger, - "%s: DPCD read failed to obtain irq data\n", + DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain irq data\n", __func__); return false; } @@ -2016,8 +2002,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd } if (!allow_hpd_rx_irq(link)) { - DC_LOG_HW_HPD_IRQ(link->ctx->logger, - "%s: skipping HPD handling on %d\n", + DC_LOG_HW_HPD_IRQ("%s: skipping HPD handling on %d\n", __func__, link->link_index); return false; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 52b0a4ae2f9a..b9fc6d842931 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -45,7 +45,8 @@ #include "dcn10/dcn10_resource.h" #endif #include "dce120/dce120_resource.h" - +#define DC_LOGGER \ + ctx->logger enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) { enum dce_version dc_version = DCE_VERSION_UNKNOWN; @@ -834,7 +835,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; struct view recout_skip = { 0 }; bool res = false; - + struct dc_context *ctx = pipe_ctx->stream->ctx; /* Important: scaling ratio calculation requires pixel format, * lb depth calculation requires recout and taps require scaling ratios. * Inits require viewport, taps, ratios and recout of split pipe @@ -893,7 +894,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) /* May need to re-check lb size after this in some obscure scenario */ calculate_inits_and_adj_vp(pipe_ctx, &recout_skip); - DC_LOG_SCALER(pipe_ctx->stream->ctx->logger, + DC_LOG_SCALER( "%s: Viewport:\nheight:%d width:%d x:%d " "y:%d\n dst_rect:\nheight:%d width:%d x:%d " "y:%d\n", diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c index 5efd0c460bee..fe92a1222803 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c @@ -42,6 +42,8 @@ #define FN(reg_name, field_name) \ abm_dce->abm_shift->field_name, abm_dce->abm_mask->field_name +#define DC_LOGGER \ + abm->ctx->logger #define CTX \ abm_dce->base.ctx @@ -403,8 +405,7 @@ static bool dce_abm_set_backlight_level( { struct dce_abm *abm_dce = TO_DCE_ABM(abm); - DC_LOG_BACKLIGHT(abm->ctx->logger, - "New Backlight level: %d (0x%X)\n", + DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n", backlight_level, backlight_level); /* If DMCU is in reset state, DMCU is uninitialized */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c index 2e86d8cb4ef3..6d5cdcdc8ec9 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c @@ -33,6 +33,8 @@ #define CTX \ aud->base.ctx +#define DC_LOGGER \ + aud->base.ctx->logger #define REG(reg)\ (aud->regs->reg) @@ -63,8 +65,7 @@ static void write_indirect_azalia_reg(struct audio *audio, REG_SET(AZALIA_F0_CODEC_ENDPOINT_DATA, 0, AZALIA_ENDPOINT_REG_DATA, reg_data); - DC_LOG_HW_AUDIO(CTX->logger, - "AUDIO:write_indirect_azalia_reg: index: %u data: %u\n", + DC_LOG_HW_AUDIO("AUDIO:write_indirect_azalia_reg: index: %u data: %u\n", reg_index, reg_data); } @@ -81,8 +82,7 @@ static uint32_t read_indirect_azalia_reg(struct audio *audio, uint32_t reg_index /* AZALIA_F0_CODEC_ENDPOINT_DATA endpoint data */ value = REG_READ(AZALIA_F0_CODEC_ENDPOINT_DATA); - DC_LOG_HW_AUDIO(CTX->logger, - "AUDIO:read_indirect_azalia_reg: index: %u data: %u\n", + DC_LOG_HW_AUDIO("AUDIO:read_indirect_azalia_reg: index: %u data: %u\n", reg_index, value); return value; @@ -364,8 +364,7 @@ void dce_aud_az_enable(struct audio *audio) CLOCK_GATING_DISABLE); AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value); - DC_LOG_HW_AUDIO(CTX->logger, - "\n\t========= AUDIO:dce_aud_az_enable: index: %u data: 0x%x\n", + DC_LOG_HW_AUDIO("\n\t========= AUDIO:dce_aud_az_enable: index: %u data: 0x%x\n", audio->inst, value); } @@ -390,8 +389,7 @@ void dce_aud_az_disable(struct audio *audio) CLOCK_GATING_DISABLE); AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value); value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL); - DC_LOG_HW_AUDIO(CTX->logger, - "\n\t========= AUDIO:dce_aud_az_disable: index: %u data: 0x%x\n", + DC_LOG_HW_AUDIO("\n\t========= AUDIO:dce_aud_az_disable: index: %u data: 0x%x\n", audio->inst, value); } @@ -795,8 +793,7 @@ void dce_aud_wall_dto_setup( crtc_info->calculated_pixel_clock, &clock_info); - DC_LOG_HW_AUDIO(audio->ctx->logger, \ - "\n%s:Input::requested_pixel_clock = %d"\ + DC_LOG_HW_AUDIO("\n%s:Input::requested_pixel_clock = %d"\ "calculated_pixel_clock =%d\n"\ "audio_dto_module = %d audio_dto_phase =%d \n\n", __func__,\ crtc_info->requested_pixel_clock,\ 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 2860d0a39be4..0aa2cda60890 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 @@ -41,7 +41,8 @@ #define CTX \ clk_src->base.ctx - +#define DC_LOGGER \ + calc_pll_cs->ctx->logger #undef FN #define FN(reg_name, field_name) \ clk_src->cs_shift->field_name, clk_src->cs_mask->field_name @@ -288,7 +289,7 @@ static uint32_t calculate_pixel_clock_pll_dividers( uint32_t max_ref_divider; if (pll_settings->adjusted_pix_clk == 0) { - DC_LOG_ERROR(calc_pll_cs->ctx->logger, + DC_LOG_ERROR( "%s Bad requested pixel clock", __func__); return MAX_PLL_CALC_ERROR; } @@ -349,13 +350,13 @@ static uint32_t calculate_pixel_clock_pll_dividers( * ## SVS Wed 15 Jul 2009 */ if (min_post_divider > max_post_divider) { - DC_LOG_ERROR(calc_pll_cs->ctx->logger, + DC_LOG_ERROR( "%s Post divider range is invalid", __func__); return MAX_PLL_CALC_ERROR; } if (min_ref_divider > max_ref_divider) { - DC_LOG_ERROR(calc_pll_cs->ctx->logger, + DC_LOG_ERROR( "%s Reference divider range is invalid", __func__); return MAX_PLL_CALC_ERROR; } @@ -466,7 +467,7 @@ static uint32_t dce110_get_pix_clk_dividers_helper ( { uint32_t field = 0; uint32_t pll_calc_error = MAX_PLL_CALC_ERROR; - + struct calc_pll_clock_source *calc_pll_cs = &clk_src->calc_pll; /* Check if reference clock is external (not pcie/xtalin) * HW Dce80 spec: * 00 - PCIE_REFCLK, 01 - XTALIN, 02 - GENERICA, 03 - GENERICB @@ -493,7 +494,7 @@ static uint32_t dce110_get_pix_clk_dividers_helper ( if (!pll_adjust_pix_clk(clk_src, pix_clk_params, pll_settings)) { /* Should never happen, ASSERT and fill up values to be able * to continue. */ - DC_LOG_ERROR(clk_src->base.ctx->logger, + DC_LOG_ERROR( "%s: Failed to adjust pixel clock!!", __func__); pll_settings->actual_pix_clk = pix_clk_params->requested_pix_clk; @@ -556,11 +557,12 @@ static uint32_t dce110_get_pix_clk_dividers( struct pll_settings *pll_settings) { struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs); + struct calc_pll_clock_source *calc_pll_cs = &clk_src->calc_pll; uint32_t pll_calc_error = MAX_PLL_CALC_ERROR; if (pix_clk_params == NULL || pll_settings == NULL || pix_clk_params->requested_pix_clk == 0) { - DC_LOG_ERROR(clk_src->base.ctx->logger, + DC_LOG_ERROR( "%s: Invalid parameters!!\n", __func__); return pll_calc_error; } @@ -1052,14 +1054,14 @@ static void get_ss_info_from_atombios( struct spread_spectrum_info *ss_info_cur; struct spread_spectrum_data *ss_data_cur; uint32_t i; - + struct calc_pll_clock_source *calc_pll_cs = &clk_src->calc_pll; if (ss_entries_num == NULL) { - DC_LOG_SYNC(clk_src->base.ctx->logger, + DC_LOG_SYNC( "Invalid entry !!!\n"); return; } if (spread_spectrum_data == NULL) { - DC_LOG_SYNC(clk_src->base.ctx->logger, + DC_LOG_SYNC( "Invalid array pointer!!!\n"); return; } @@ -1104,7 +1106,7 @@ static void get_ss_info_from_atombios( ++i, ++ss_info_cur, ++ss_data_cur) { if (ss_info_cur->type.STEP_AND_DELAY_INFO != false) { - DC_LOG_SYNC(clk_src->base.ctx->logger, + DC_LOG_SYNC( "Invalid ATOMBIOS SS Table!!!\n"); goto out_free_data; } @@ -1114,9 +1116,9 @@ static void get_ss_info_from_atombios( if (as_signal == AS_SIGNAL_TYPE_HDMI && ss_info_cur->spread_spectrum_percentage > 6){ /* invalid input, do nothing */ - DC_LOG_SYNC(clk_src->base.ctx->logger, + DC_LOG_SYNC( "Invalid SS percentage "); - DC_LOG_SYNC(clk_src->base.ctx->logger, + DC_LOG_SYNC( "for HDMI in ATOMBIOS info Table!!!\n"); continue; } @@ -1228,12 +1230,12 @@ static bool calc_pll_max_vco_construct( if (init_data->num_fract_fb_divider_decimal_point == 0 || init_data->num_fract_fb_divider_decimal_point_precision > init_data->num_fract_fb_divider_decimal_point) { - DC_LOG_ERROR(calc_pll_cs->ctx->logger, + DC_LOG_ERROR( "The dec point num or precision is incorrect!"); return false; } if (init_data->num_fract_fb_divider_decimal_point_precision == 0) { - DC_LOG_ERROR(calc_pll_cs->ctx->logger, + DC_LOG_ERROR( "Incorrect fract feedback divider precision num!"); return false; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 654dcc6df97d..78e6beb6cf26 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -49,6 +49,8 @@ #define CTX \ clk_dce->base.ctx +#define DC_LOGGER \ + clk->ctx->logger /* Max clock values for each state indexed by "enum clocks_state": */ static const struct state_dependent_clocks dce80_max_clks_by_state[] = { @@ -292,8 +294,7 @@ static enum dm_pp_clocks_state dce_get_required_clocks_state( low_req_clk = i + 1; if (low_req_clk > clk->max_clks_state) { - DC_LOG_WARNING(clk->ctx->logger, - "%s: clocks unsupported disp_clk %d pix_clk %d", + DC_LOG_WARNING("%s: clocks unsupported disp_clk %d pix_clk %d", __func__, req_clocks->display_clk_khz, req_clocks->pixel_clk_khz); @@ -312,8 +313,7 @@ static bool dce_clock_set_min_clocks_state( if (clocks_state > clk->max_clks_state) { /*Requested state exceeds max supported state.*/ - DC_LOG_WARNING(clk->ctx->logger, - "Requested state exceeds max supported state"); + DC_LOG_WARNING("Requested state exceeds max supported state"); return false; } else if (clocks_state == clk->cur_min_clks_state) { /*if we're trying to set the same state, we can just return diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index e063a50a5771..f0d63ac7724a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -56,6 +56,8 @@ #define CTX \ enc110->base.ctx +#define DC_LOGGER \ + enc110->base.ctx->logger #define REG(reg)\ (enc110->link_regs->reg) @@ -809,7 +811,6 @@ void dce110_link_encoder_hw_init( struct link_encoder *enc) { struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); - struct dc_context *ctx = enc110->base.ctx; struct bp_transmitter_control cntl = { 0 }; enum bp_result result; @@ -827,8 +828,7 @@ void dce110_link_encoder_hw_init( result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { - DC_LOG_ERROR(ctx->logger, - "%s: Failed to execute VBIOS command table!\n", + DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n", __func__); BREAK_TO_DEBUGGER(); return; @@ -904,7 +904,6 @@ void dce110_link_encoder_enable_tmds_output( uint32_t pixel_clock) { struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); - struct dc_context *ctx = enc110->base.ctx; struct bp_transmitter_control cntl = { 0 }; enum bp_result result; @@ -928,8 +927,7 @@ void dce110_link_encoder_enable_tmds_output( result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { - DC_LOG_ERROR(ctx->logger, - "%s: Failed to execute VBIOS command table!\n", + DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n", __func__); BREAK_TO_DEBUGGER(); } @@ -942,7 +940,6 @@ void dce110_link_encoder_enable_dp_output( enum clock_source_id clock_source) { struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); - struct dc_context *ctx = enc110->base.ctx; struct bp_transmitter_control cntl = { 0 }; enum bp_result result; @@ -969,8 +966,7 @@ void dce110_link_encoder_enable_dp_output( result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { - DC_LOG_ERROR(ctx->logger, - "%s: Failed to execute VBIOS command table!\n", + DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n", __func__); BREAK_TO_DEBUGGER(); } @@ -983,7 +979,6 @@ void dce110_link_encoder_enable_dp_mst_output( enum clock_source_id clock_source) { struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); - struct dc_context *ctx = enc110->base.ctx; struct bp_transmitter_control cntl = { 0 }; enum bp_result result; @@ -1010,8 +1005,7 @@ void dce110_link_encoder_enable_dp_mst_output( result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { - DC_LOG_ERROR(ctx->logger, - "%s: Failed to execute VBIOS command table!\n", + DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n", __func__); BREAK_TO_DEBUGGER(); } @@ -1025,7 +1019,6 @@ void dce110_link_encoder_disable_output( enum signal_type signal) { struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); - struct dc_context *ctx = enc110->base.ctx; struct bp_transmitter_control cntl = { 0 }; enum bp_result result; @@ -1053,8 +1046,7 @@ void dce110_link_encoder_disable_output( result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { - DC_LOG_ERROR(ctx->logger, - "%s: Failed to execute VBIOS command table!\n", + DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n", __func__); BREAK_TO_DEBUGGER(); return; 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 f4d95126de2e..444558ca6533 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 @@ -26,7 +26,8 @@ #include "dc_bios_types.h" #include "dce_stream_encoder.h" #include "reg_helper.h" - +#define DC_LOGGER \ + enc110->base.ctx->logger enum DP_PIXEL_ENCODING { DP_PIXEL_ENCODING_RGB444 = 0x00000000, DP_PIXEL_ENCODING_YCBCR422 = 0x00000001, @@ -197,7 +198,6 @@ static void dce110_update_hdmi_info_packet( uint32_t packet_index, const struct encoder_info_packet *info_packet) { - struct dc_context *ctx = enc110->base.ctx; uint32_t cont, send, line; if (info_packet->valid) { @@ -278,7 +278,6 @@ static void dce110_update_hdmi_info_packet( default: /* invalid HW packet index */ DC_LOG_WARNING( - ctx->logger, "Invalid HW packet index: %s()\n", __func__); return; @@ -1386,7 +1385,7 @@ static void dce110_se_setup_hdmi_audio( crtc_info->requested_pixel_clock, crtc_info->calculated_pixel_clock, &audio_clock_info); - DC_LOG_HW_AUDIO(enc->ctx->logger, + DC_LOG_HW_AUDIO( "\n%s:Input::requested_pixel_clock = %d" \ "calculated_pixel_clock = %d \n", __func__, \ crtc_info->requested_pixel_clock, \ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c index 5268197678f5..832c5daada35 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c @@ -38,6 +38,8 @@ #define CTX \ xfm_dce->base.ctx +#define DC_LOGGER \ + xfm_dce->base.ctx->logger #define IDENTITY_RATIO(ratio) (dal_fixed31_32_u2d19(ratio) == (1 << 19)) #define GAMUT_MATRIX_SIZE 12 @@ -693,8 +695,7 @@ static int dce_transform_get_max_num_of_supported_lines( break; default: - DC_LOG_WARNING(xfm_dce->base.ctx->logger, - "%s: Invalid LB pixel depth", + DC_LOG_WARNING("%s: Invalid LB pixel depth", __func__); BREAK_TO_DEBUGGER(); break; @@ -791,8 +792,7 @@ static void dce_transform_set_pixel_storage_depth( if (!(xfm_dce->lb_pixel_depth_supported & depth)) { /*we should use unsupported capabilities * unless it is required by w/a*/ - DC_LOG_WARNING(xfm->ctx->logger, - "%s: Capability not supported", + DC_LOG_WARNING("%s: Capability not supported", __func__); } } @@ -1172,8 +1172,7 @@ static void program_pwl(struct dce_transform *xfm_dce, } if (counter == max_tries) { - DC_LOG_WARNING(xfm_dce->base.ctx->logger, - "%s: regamma lut was not powered on " + DC_LOG_WARNING("%s: regamma lut was not powered on " "in a timely manner," " programming still proceeds\n", __func__); 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 af854f21e9f5..775d3bf0bd39 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c @@ -34,6 +34,8 @@ #include "dce110_compressor.h" +#define DC_LOGGER \ + cp110->base.ctx->logger #define DCP_REG(reg)\ (reg + cp110->offsets.dcp_offset) #define DMIF_REG(reg)\ @@ -120,14 +122,10 @@ static void wait_for_fbc_state_changed( } if (counter == 10) { - DC_LOG_WARNING( - cp110->base.ctx->logger, - "%s: wait counter exceeded, changes to HW not applied", + DC_LOG_WARNING("%s: wait counter exceeded, changes to HW not applied", __func__); } else { - DC_LOG_SYNC( - cp110->base.ctx->logger, - "FBC status changed to %d", enabled); + DC_LOG_SYNC("FBC status changed to %d", enabled); } @@ -310,9 +308,7 @@ void dce110_compressor_program_compressed_surface_address_and_pitch( if (compressor->min_compress_ratio == FBC_COMPRESS_RATIO_1TO1) fbc_pitch = fbc_pitch / 8; else - DC_LOG_WARNING( - compressor->ctx->logger, - "%s: Unexpected DCE11 compression ratio", + DC_LOG_WARNING("%s: Unexpected DCE11 compression ratio", __func__); /* Clear content first. */ 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 9e31f06ab4c8..f21aa04e93da 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 @@ -70,6 +70,8 @@ #define CTX \ hws->ctx +#define DC_LOGGER \ + ctx->logger #define REG(reg)\ hws->regs->reg @@ -816,7 +818,7 @@ void hwss_edp_wait_for_hpd_ready( dal_gpio_destroy_irq(&hpd); if (false == edp_hpd_high) { - DC_LOG_ERROR(ctx->logger, + DC_LOG_ERROR( "%s: wait timed out!\n", __func__); } } @@ -840,7 +842,7 @@ void hwss_edp_power_control( if (power_up != is_panel_powered_on(hwseq)) { /* Send VBIOS command to prompt eDP panel power */ - DC_LOG_HW_RESUME_S3(ctx->logger, + DC_LOG_HW_RESUME_S3( "%s: Panel Power action: %s\n", __func__, (power_up ? "On":"Off")); @@ -856,11 +858,11 @@ void hwss_edp_power_control( bp_result = link_transmitter_control(ctx->dc_bios, &cntl); if (bp_result != BP_RESULT_OK) - DC_LOG_ERROR(ctx->logger, + DC_LOG_ERROR( "%s: Panel Power bp_result: %d\n", __func__, bp_result); } else { - DC_LOG_HW_RESUME_S3(ctx->logger, + DC_LOG_HW_RESUME_S3( "%s: Skipping Panel Power action: %s\n", __func__, (power_up ? "On":"Off")); } @@ -886,7 +888,7 @@ void hwss_edp_backlight_control( } if (enable && is_panel_backlight_on(hws)) { - DC_LOG_HW_RESUME_S3(ctx->logger, + DC_LOG_HW_RESUME_S3( "%s: panel already powered up. Do nothing.\n", __func__); return; @@ -894,7 +896,7 @@ void hwss_edp_backlight_control( /* Send VBIOS command to control eDP panel backlight */ - DC_LOG_HW_RESUME_S3(ctx->logger, + DC_LOG_HW_RESUME_S3( "%s: backlight action: %s\n", __func__, (enable ? "On":"Off")); @@ -2687,7 +2689,7 @@ static void dce110_program_front_end_for_pipe( struct xfm_grph_csc_adjustment adjust; struct out_csc_color_matrix tbl_entry; unsigned int i; - + struct dc_context *ctx = dc->ctx; memset(&tbl_entry, 0, sizeof(tbl_entry)); if (dc->current_state) @@ -2762,7 +2764,7 @@ static void dce110_program_front_end_for_pipe( if (pipe_ctx->plane_state->update_flags.bits.full_update) dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); - DC_LOG_SURFACE(dc->ctx->logger, + DC_LOG_SURFACE( "Pipe:%d 0x%x: addr hi:0x%x, " "addr low:0x%x, " "src: %d, %d, %d," @@ -2785,7 +2787,7 @@ static void dce110_program_front_end_for_pipe( pipe_ctx->plane_state->clip_rect.width, pipe_ctx->plane_state->clip_rect.height); - DC_LOG_SURFACE(dc->ctx->logger, + DC_LOG_SURFACE( "Pipe %d: width, height, x, y\n" "viewport:%d, %d, %d, %d\n" "recout: %d, %d, %d, %d\n", diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index d938047fc17f..9b34c400c041 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -52,6 +52,8 @@ #include "dce/dce_abm.h" #include "dce/dce_dmcu.h" +#define DC_LOGGER \ + dc->ctx->logger #if defined(CONFIG_DRM_AMD_DC_FBC) #include "dce110/dce110_compressor.h" #endif @@ -772,7 +774,6 @@ static bool dce110_validate_bandwidth( bool result = false; DC_LOG_BANDWIDTH_CALCS( - dc->ctx->logger, "%s: start", __func__); @@ -786,8 +787,7 @@ static bool dce110_validate_bandwidth( result = true; if (!result) - DC_LOG_BANDWIDTH_VALIDATION(dc->ctx->logger, - "%s: %dx%d@%d Bandwidth validation failed!\n", + DC_LOG_BANDWIDTH_VALIDATION("%s: %dx%d@%d Bandwidth validation failed!\n", __func__, context->streams[0]->timing.h_addressable, context->streams[0]->timing.v_addressable, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c index a8e93072ab5c..8ad04816e7d3 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c @@ -38,6 +38,8 @@ #include "timing_generator.h" +#define DC_LOGGER \ + tg->ctx->logger /** ******************************************************************************** * * DCE11 Timing Generator Implementation @@ -606,8 +608,7 @@ static uint32_t dce110_timing_generator_v_get_vblank_counter(struct timing_gener static bool dce110_timing_generator_v_did_triggered_reset_occur( struct timing_generator *tg) { - DC_LOG_ERROR(tg->ctx->logger, - "Timing Sync not supported on underlay pipe\n"); + DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n"); return false; } @@ -615,8 +616,7 @@ static void dce110_timing_generator_v_setup_global_swap_lock( struct timing_generator *tg, const struct dcp_gsl_params *gsl_params) { - DC_LOG_ERROR(tg->ctx->logger, - "Timing Sync not supported on underlay pipe\n"); + DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n"); return; } @@ -624,24 +624,21 @@ static void dce110_timing_generator_v_enable_reset_trigger( struct timing_generator *tg, int source_tg_inst) { - DC_LOG_ERROR(tg->ctx->logger, - "Timing Sync not supported on underlay pipe\n"); + DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n"); return; } static void dce110_timing_generator_v_disable_reset_trigger( struct timing_generator *tg) { - DC_LOG_ERROR(tg->ctx->logger, - "Timing Sync not supported on underlay pipe\n"); + DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n"); return; } static void dce110_timing_generator_v_tear_down_global_swap_lock( struct timing_generator *tg) { - DC_LOG_ERROR(tg->ctx->logger, - "Timing Sync not supported on underlay pipe\n"); + DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n"); return; } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c index 809db96a8ba5..8ba3c12fc608 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c @@ -30,6 +30,8 @@ #include "dce/dce_11_0_sh_mask.h" #define SCLV_PHASES 64 +#define DC_LOGGER \ + xfm->ctx->logger struct sclv_ratios_inits { uint32_t h_int_scale_ratio_luma; @@ -670,8 +672,7 @@ static void dce110_xfmv_set_pixel_storage_depth( if (!(xfm_dce->lb_pixel_depth_supported & depth)) { /*we should use unsupported capabilities * unless it is required by w/a*/ - DC_LOG_WARNING(xfm->ctx->logger, - "%s: Capability not supported", + DC_LOG_WARNING("%s: Capability not supported", __func__); } } diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c index 196ddd01615c..faae12cf7968 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c @@ -33,7 +33,8 @@ #include "include/logger_interface.h" #include "dce112_compressor.h" - +#define DC_LOGGER \ + cp110->base.ctx->logger #define DCP_REG(reg)\ (reg + cp110->offsets.dcp_offset) #define DMIF_REG(reg)\ @@ -130,7 +131,6 @@ static uint32_t lpt_memory_control_config(struct dce112_compressor *cp110, break; default: DC_LOG_WARNING( - cp110->base.ctx->logger, "%s: Invalid LPT NUM_PIPES!!!", __func__); break; @@ -176,7 +176,6 @@ static uint32_t lpt_memory_control_config(struct dce112_compressor *cp110, break; default: DC_LOG_WARNING( - cp110->base.ctx->logger, "%s: Invalid LPT NUM_BANKS!!!", __func__); break; @@ -210,7 +209,6 @@ static uint32_t lpt_memory_control_config(struct dce112_compressor *cp110, break; default: DC_LOG_WARNING( - cp110->base.ctx->logger, "%s: Invalid LPT INTERLEAVE_SIZE!!!", __func__); break; @@ -254,14 +252,12 @@ static uint32_t lpt_memory_control_config(struct dce112_compressor *cp110, break; default: DC_LOG_WARNING( - cp110->base.ctx->logger, "%s: Invalid LPT ROW_SIZE!!!", __func__); break; } } else { DC_LOG_WARNING( - cp110->base.ctx->logger, "%s: LPT MC Configuration is not provided", __func__); } @@ -312,7 +308,6 @@ static void wait_for_fbc_state_changed( if (counter == 10) { DC_LOG_WARNING( - cp110->base.ctx->logger, "%s: wait counter exceeded, changes to HW not applied", __func__); } @@ -526,7 +521,6 @@ void dce112_compressor_program_compressed_surface_address_and_pitch( fbc_pitch = fbc_pitch / 8; else DC_LOG_WARNING( - compressor->ctx->logger, "%s: Unexpected DCE11 compression ratio", __func__); @@ -691,7 +685,6 @@ void dce112_compressor_program_lpt_control( break; default: DC_LOG_WARNING( - compressor->ctx->logger, "%s: Invalid selected DRAM channels for LPT!!!", __func__); break; diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index bf885d7e699b..cd1e3f72c44e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -56,6 +56,8 @@ #include "dce/dce_11_2_sh_mask.h" #include "dce100/dce100_resource.h" +#define DC_LOGGER \ + dc->ctx->logger #ifndef mmDP_DPHY_INTERNAL_CTRL #define mmDP_DPHY_INTERNAL_CTRL 0x4aa7 @@ -723,7 +725,6 @@ bool dce112_validate_bandwidth( bool result = false; DC_LOG_BANDWIDTH_CALCS( - dc->ctx->logger, "%s: start", __func__); @@ -737,7 +738,7 @@ bool dce112_validate_bandwidth( result = true; if (!result) - DC_LOG_BANDWIDTH_VALIDATION(dc->ctx->logger, + DC_LOG_BANDWIDTH_VALIDATION( "%s: Bandwidth validation failed!", __func__); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c index c1711f79ce6d..738f67ffd1b4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -30,6 +30,8 @@ #define CTX \ hubbub->ctx +#define DC_LOGGER \ + hubbub->ctx->logger #define REG(reg)\ hubbub->regs->reg @@ -147,8 +149,7 @@ bool hubbub1_verify_allow_pstate_change_high( if (debug_data & (1 << 30)) { if (i > pstate_wait_expected_timeout_us) - DC_LOG_WARNING(hubbub->ctx->logger, - "pstate took longer than expected ~%dus\n", + DC_LOG_WARNING("pstate took longer than expected ~%dus\n", i); return true; @@ -167,8 +168,7 @@ bool hubbub1_verify_allow_pstate_change_high( DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 1); forced_pstate_allow = true; - DC_LOG_WARNING(hubbub->ctx->logger, - "pstate TEST_DEBUG_DATA: 0x%X\n", + DC_LOG_WARNING("pstate TEST_DEBUG_DATA: 0x%X\n", debug_data); return false; @@ -211,16 +211,14 @@ void hubbub1_program_watermarks( refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "URGENCY_WATERMARK_A calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n", watermarks->a.urgent_ns, prog_wm_value); prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "PTE_META_URGENCY_WATERMARK_A calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n", watermarks->a.pte_meta_urgent_ns, prog_wm_value); @@ -229,8 +227,7 @@ void hubbub1_program_watermarks( watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n", watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); @@ -239,8 +236,7 @@ void hubbub1_program_watermarks( watermarks->a.cstate_pstate.cstate_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "SR_EXIT_WATERMARK_A calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n", watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); } @@ -249,8 +245,7 @@ void hubbub1_program_watermarks( watermarks->a.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n\n", watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); @@ -259,8 +254,7 @@ void hubbub1_program_watermarks( prog_wm_value = convert_and_clamp( watermarks->b.urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "URGENCY_WATERMARK_B calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" "HW register value = 0x%x\n", watermarks->b.urgent_ns, prog_wm_value); @@ -269,8 +263,7 @@ void hubbub1_program_watermarks( watermarks->b.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "PTE_META_URGENCY_WATERMARK_B calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n" "HW register value = 0x%x\n", watermarks->b.pte_meta_urgent_ns, prog_wm_value); @@ -280,8 +273,7 @@ void hubbub1_program_watermarks( watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "SR_ENTER_WATERMARK_B calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_B calculated =%d\n" "HW register value = 0x%x\n", watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); @@ -290,8 +282,7 @@ void hubbub1_program_watermarks( watermarks->b.cstate_pstate.cstate_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "SR_EXIT_WATERMARK_B calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" "HW register value = 0x%x\n", watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); } @@ -300,8 +291,7 @@ void hubbub1_program_watermarks( watermarks->b.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n\n" + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n\n" "HW register value = 0x%x\n", watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); @@ -309,8 +299,7 @@ void hubbub1_program_watermarks( prog_wm_value = convert_and_clamp( watermarks->c.urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "URGENCY_WATERMARK_C calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" "HW register value = 0x%x\n", watermarks->c.urgent_ns, prog_wm_value); @@ -319,8 +308,7 @@ void hubbub1_program_watermarks( watermarks->c.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "PTE_META_URGENCY_WATERMARK_C calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n" "HW register value = 0x%x\n", watermarks->c.pte_meta_urgent_ns, prog_wm_value); @@ -330,8 +318,7 @@ void hubbub1_program_watermarks( watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "SR_ENTER_WATERMARK_C calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_C calculated =%d\n" "HW register value = 0x%x\n", watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); @@ -340,8 +327,7 @@ void hubbub1_program_watermarks( watermarks->c.cstate_pstate.cstate_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "SR_EXIT_WATERMARK_C calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" "HW register value = 0x%x\n", watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); } @@ -350,8 +336,7 @@ void hubbub1_program_watermarks( watermarks->c.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n\n" + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n\n" "HW register value = 0x%x\n", watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); @@ -359,8 +344,7 @@ void hubbub1_program_watermarks( prog_wm_value = convert_and_clamp( watermarks->d.urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "URGENCY_WATERMARK_D calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n", watermarks->d.urgent_ns, prog_wm_value); @@ -368,8 +352,7 @@ void hubbub1_program_watermarks( watermarks->d.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "PTE_META_URGENCY_WATERMARK_D calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n", watermarks->d.pte_meta_urgent_ns, prog_wm_value); @@ -379,8 +362,7 @@ void hubbub1_program_watermarks( watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "SR_ENTER_WATERMARK_D calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n", watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); @@ -389,8 +371,7 @@ void hubbub1_program_watermarks( watermarks->d.cstate_pstate.cstate_exit_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "SR_EXIT_WATERMARK_D calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n", watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); } @@ -400,8 +381,7 @@ void hubbub1_program_watermarks( watermarks->d.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS(hubbub->ctx->logger, - "DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n\n", watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index aa5516539c95..1907ade1574a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -45,6 +45,8 @@ #include "dcn10_hubbub.h" #include "dcn10_cm_common.h" +#define DC_LOGGER \ + ctx->logger #define CTX \ hws->ctx #define REG(reg)\ @@ -328,6 +330,7 @@ static void power_on_plane( struct dce_hwseq *hws, int plane_id) { + struct dc_context *ctx = hws->ctx; if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); @@ -335,7 +338,7 @@ static void power_on_plane( hubp_pg_control(hws, plane_id, true); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); - DC_LOG_DEBUG(hws->ctx->logger, + DC_LOG_DEBUG( "Un-gated front end for pipe %d\n", plane_id); } } @@ -526,7 +529,7 @@ static void reset_back_end_for_pipe( struct dc_state *context) { int i; - + struct dc_context *ctx = dc->ctx; if (pipe_ctx->stream_res.stream_enc == NULL) { pipe_ctx->stream = NULL; return; @@ -572,8 +575,7 @@ static void reset_back_end_for_pipe( return; pipe_ctx->stream = NULL; - DC_LOG_DEBUG(dc->ctx->logger, - "Reset back end for pipe %d, tg:%d\n", + DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); } @@ -623,6 +625,7 @@ static void plane_atomic_power_down(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct dce_hwseq *hws = dc->hwseq; struct dpp *dpp = pipe_ctx->plane_res.dpp; + struct dc_context *ctx = dc->ctx; if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, @@ -632,7 +635,7 @@ static void plane_atomic_power_down(struct dc *dc, struct pipe_ctx *pipe_ctx) dpp->funcs->dpp_reset(dpp); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); - DC_LOG_DEBUG(dc->ctx->logger, + DC_LOG_DEBUG( "Power gated front end %d\n", pipe_ctx->pipe_idx); } } @@ -672,6 +675,8 @@ static void plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) { + struct dc_context *ctx = dc->ctx; + if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) return; @@ -679,8 +684,7 @@ static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) apply_DEGVIDCN10_253_wa(dc); - DC_LOG_DC(dc->ctx->logger, - "Power down front end %d\n", + DC_LOG_DC("Power down front end %d\n", pipe_ctx->pipe_idx); } @@ -1908,6 +1912,7 @@ static void dcn10_apply_ctx_for_surface( bool removed_pipe[4] = { false }; unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000; bool program_water_mark = false; + struct dc_context *ctx = dc->ctx; struct pipe_ctx *top_pipe_to_program = find_top_pipe_for_stream(dc, context, stream); @@ -1959,7 +1964,7 @@ static void dcn10_apply_ctx_for_surface( plane_atomic_disconnect(dc, old_pipe_ctx); removed_pipe[i] = true; - DC_LOG_DC(dc->ctx->logger, + DC_LOG_DC( "Reset mpcc for pipe %d\n", old_pipe_ctx->pipe_idx); } diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c index eacc9ebd6933..bb526ad326e5 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c @@ -55,6 +55,8 @@ enum { #define FROM_ENGINE(ptr) \ container_of((ptr), struct aux_engine, base) +#define DC_LOGGER \ + engine->base.ctx->logger enum i2caux_engine_type dal_aux_engine_get_engine_type( const struct engine *engine) @@ -274,7 +276,7 @@ static bool read_command( if (request->payload.address_space == I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { - DC_LOG_I2C_AUX(engine->base.ctx->logger, "READ: addr:0x%x value:0x%x Result:%d", + DC_LOG_I2C_AUX("READ: addr:0x%x value:0x%x Result:%d", request->payload.address, request->payload.data[0], ctx.operation_succeeded); @@ -483,7 +485,7 @@ static bool write_command( if (request->payload.address_space == I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { - DC_LOG_I2C_AUX(engine->base.ctx->logger, "WRITE: addr:0x%x value:0x%x Result:%d", + DC_LOG_I2C_AUX("WRITE: addr:0x%x value:0x%x Result:%d", request->payload.address, request->payload.data[0], ctx.operation_succeeded); diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c index ad685b1c9b81..abd0095ced30 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c @@ -48,6 +48,8 @@ /* * This unit */ +#define DC_LOGGER \ + hw_engine->base.base.base.ctx->logger enum dc_i2c_status { DC_I2C_STATUS__DC_I2C_STATUS_IDLE, @@ -525,9 +527,7 @@ static void construct( REG_GET(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, &xtal_ref_div); if (xtal_ref_div == 0) { - DC_LOG_WARNING( - hw_engine->base.base.base.ctx->logger, - "Invalid base timer divider\n", + DC_LOG_WARNING("Invalid base timer divider\n", __func__); xtal_ref_div = 2; } diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c index e3de56b7ac5f..aa260f9562a2 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c @@ -36,6 +36,9 @@ #include "dc.h" #include "core_types.h" +#define DC_LOGGER \ + irq_service->ctx->logger + static bool hpd_ack( struct irq_service *irq_service, const struct irq_source_info *info) @@ -181,9 +184,7 @@ bool dal_irq_service_dummy_set( const struct irq_source_info *info, bool enable) { - DC_LOG_ERROR( - irq_service->ctx->logger, - "%s: called for non-implemented irq source\n", + DC_LOG_ERROR("%s: called for non-implemented irq source\n", __func__); return false; } @@ -192,9 +193,7 @@ bool dal_irq_service_dummy_ack( struct irq_service *irq_service, const struct irq_source_info *info) { - DC_LOG_ERROR( - irq_service->ctx->logger, - "%s: called for non-implemented irq source\n", + DC_LOG_ERROR("%s: called for non-implemented irq source\n", __func__); return false; } diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c index 441724776441..dcdfa0f01551 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c @@ -47,6 +47,8 @@ #define CTX \ irq_service->ctx +#define DC_LOGGER \ + irq_service->ctx->logger void dal_irq_service_construct( struct irq_service *irq_service, @@ -104,9 +106,7 @@ bool dal_irq_service_set( find_irq_source_info(irq_service, source); if (!info) { - DC_LOG_ERROR( - irq_service->ctx->logger, - "%s: cannot find irq info table entry for %d\n", + DC_LOG_ERROR("%s: cannot find irq info table entry for %d\n", __func__, source); return false; @@ -142,9 +142,7 @@ bool dal_irq_service_ack( find_irq_source_info(irq_service, source); if (!info) { - DC_LOG_ERROR( - irq_service->ctx->logger, - "%s: cannot find irq info table entry for %d\n", + DC_LOG_ERROR("%s: cannot find irq info table entry for %d\n", __func__, source); return false; diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h index 65b6bf892839..b727f5eeb3a9 100644 --- a/drivers/gpu/drm/amd/display/include/logger_types.h +++ b/drivers/gpu/drm/amd/display/include/logger_types.h @@ -29,38 +29,38 @@ #include "os_types.h" #define MAX_NAME_LEN 32 -#define DC_LOG_ERROR(a, b, ...) dm_logger_write(a, LOG_ERROR, b, ## __VA_ARGS__) -#define DC_LOG_WARNING(a, b, ...) dm_logger_write(a, LOG_WARNING, b, ## __VA_ARGS__) -#define DC_LOG_DEBUG(a, b, ...) dm_logger_write(a, LOG_DEBUG, b, ## __VA_ARGS__) -#define DC_LOG_DC(a, b, ...) dm_logger_write(a, LOG_DC, b, ## __VA_ARGS__) -#define DC_LOG_DTN(a, b, ...) dm_logger_write(a, LOG_DTN, b, ## __VA_ARGS__) -#define DC_LOG_SURFACE(a, b, ...) dm_logger_write(a, LOG_SURFACE, b, ## __VA_ARGS__) -#define DC_LOG_HW_HOTPLUG(a, b, ...) dm_logger_write(a, LOG_HW_HOTPLUG, b, ## __VA_ARGS__) -#define DC_LOG_HW_LINK_TRAINING(a, b, ...) dm_logger_write(a, LOG_HW_LINK_TRAINING, b, ## __VA_ARGS__) -#define DC_LOG_HW_SET_MODE(a, b, ...) dm_logger_write(a, LOG_HW_SET_MODE, b, ## __VA_ARGS__) -#define DC_LOG_HW_RESUME_S3(a, b, ...) dm_logger_write(a, LOG_HW_RESUME_S3, b, ## __VA_ARGS__) -#define DC_LOG_HW_AUDIO(a, b, ...) dm_logger_write(a, LOG_HW_AUDIO, b, ## __VA_ARGS__) -#define DC_LOG_HW_HPD_IRQ(a, b, ...) dm_logger_write(a, LOG_HW_HPD_IRQ, b, ## __VA_ARGS__) -#define DC_LOG_MST(a, b, ...) dm_logger_write(a, LOG_MST, b, ## __VA_ARGS__) -#define DC_LOG_SCALER(a, b, ...) dm_logger_write(a, LOG_SCALER, b, ## __VA_ARGS__) -#define DC_LOG_BIOS(a, b, ...) dm_logger_write(a, LOG_BIOS, b, ## __VA_ARGS__) -#define DC_LOG_BANDWIDTH_CALCS(a, b, ...) dm_logger_write(a, LOG_BANDWIDTH_CALCS, b, ## __VA_ARGS__) -#define DC_LOG_BANDWIDTH_VALIDATION(a, b, ...) dm_logger_write(a, LOG_BANDWIDTH_VALIDATION, b, ## __VA_ARGS__) -#define DC_LOG_I2C_AUX(a, b, ...) dm_logger_write(a, LOG_I2C_AUX, b, ## __VA_ARGS__) -#define DC_LOG_SYNC(a, b, ...) dm_logger_write(a, LOG_SYNC, b, ## __VA_ARGS__) -#define DC_LOG_BACKLIGHT(a, b, ...) dm_logger_write(a, LOG_BACKLIGHT, b, ## __VA_ARGS__) -#define DC_LOG_FEATURE_OVERRIDE(a, b, ...) dm_logger_write(a, LOG_FEATURE_OVERRIDE, b, ## __VA_ARGS__) -#define DC_LOG_DETECTION_EDID_PARSER(a, b, ...) dm_logger_write(a, LOG_DETECTION_EDID_PARSER, b, ## __VA_ARGS__) -#define DC_LOG_DETECTION_DP_CAPS(a, b, ...) dm_logger_write(a, LOG_DETECTION_DP_CAPS, b, ## __VA_ARGS__) -#define DC_LOG_RESOURCE(a, b, ...) dm_logger_write(a, LOG_RESOURCE, b, ## __VA_ARGS__) -#define DC_LOG_DML(a, b, ...) dm_logger_write(a, LOG_DML, b, ## __VA_ARGS__) -#define DC_LOG_EVENT_MODE_SET(a, b, ...) dm_logger_write(a, LOG_EVENT_MODE_SET, b, ## __VA_ARGS__) -#define DC_LOG_EVENT_DETECTION(a, b, ...) dm_logger_write(a, LOG_EVENT_DETECTION, b, ## __VA_ARGS__) -#define DC_LOG_EVENT_LINK_TRAINING(a, b, ...) dm_logger_write(a, LOG_EVENT_LINK_TRAINING, b, ## __VA_ARGS__) -#define DC_LOG_EVENT_LINK_LOSS(a, b, ...) dm_logger_write(a, LOG_EVENT_LINK_LOSS, b, ## __VA_ARGS__) -#define DC_LOG_EVENT_UNDERFLOW(a, b, ...) dm_logger_write(a, LOG_EVENT_UNDERFLOW, b, ## __VA_ARGS__) -#define DC_LOG_IF_TRACE(a, b, ...) dm_logger_write(a, LOG_IF_TRACE, b, ## __VA_ARGS__) -#define DC_LOG_PERF_TRACE(a, b, ...) dm_logger_write(a, LOG_PERF_TRACE, b, ## __VA_ARGS__) +#define DC_LOG_ERROR(a, ...) dm_logger_write(DC_LOGGER, LOG_ERROR, a, ## __VA_ARGS__) +#define DC_LOG_WARNING(a, ...) dm_logger_write(DC_LOGGER, LOG_WARNING, a, ## __VA_ARGS__) +#define DC_LOG_DEBUG(a, ...) dm_logger_write(DC_LOGGER, LOG_DEBUG, a, ## __VA_ARGS__) +#define DC_LOG_DC(a, ...) dm_logger_write(DC_LOGGER, LOG_DC, a, ## __VA_ARGS__) +#define DC_LOG_DTN(a, ...) dm_logger_write(DC_LOGGER, LOG_DTN, a, ## __VA_ARGS__) +#define DC_LOG_SURFACE(a, ...) dm_logger_write(DC_LOGGER, LOG_SURFACE, a, ## __VA_ARGS__) +#define DC_LOG_HW_HOTPLUG(a, ...) dm_logger_write(DC_LOGGER, LOG_HW_HOTPLUG, a, ## __VA_ARGS__) +#define DC_LOG_HW_LINK_TRAINING(a, ...) dm_logger_write(DC_LOGGER, LOG_HW_LINK_TRAINING, a, ## __VA_ARGS__) +#define DC_LOG_HW_SET_MODE(a, ...) dm_logger_write(DC_LOGGER, LOG_HW_SET_MODE, a, ## __VA_ARGS__) +#define DC_LOG_HW_RESUME_S3(a, ...) dm_logger_write(DC_LOGGER, LOG_HW_RESUME_S3, a, ## __VA_ARGS__) +#define DC_LOG_HW_AUDIO(a, ...) dm_logger_write(DC_LOGGER, LOG_HW_AUDIO, a, ## __VA_ARGS__) +#define DC_LOG_HW_HPD_IRQ(a, ...) dm_logger_write(DC_LOGGER, LOG_HW_HPD_IRQ, a, ## __VA_ARGS__) +#define DC_LOG_MST(a, ...) dm_logger_write(DC_LOGGER, LOG_MST, a, ## __VA_ARGS__) +#define DC_LOG_SCALER(a, ...) dm_logger_write(DC_LOGGER, LOG_SCALER, a, ## __VA_ARGS__) +#define DC_LOG_BIOS(a, ...) dm_logger_write(DC_LOGGER, LOG_BIOS, a, ## __VA_ARGS__) +#define DC_LOG_BANDWIDTH_CALCS(a, ...) dm_logger_write(DC_LOGGER, LOG_BANDWIDTH_CALCS, a, ## __VA_ARGS__) +#define DC_LOG_BANDWIDTH_VALIDATION(a, ...) dm_logger_write(DC_LOGGER, LOG_BANDWIDTH_VALIDATION, a, ## __VA_ARGS__) +#define DC_LOG_I2C_AUX(a, ...) dm_logger_write(DC_LOGGER, LOG_I2C_AUX, a, ## __VA_ARGS__) +#define DC_LOG_SYNC(a, ...) dm_logger_write(DC_LOGGER, LOG_SYNC, a, ## __VA_ARGS__) +#define DC_LOG_BACKLIGHT(a, ...) dm_logger_write(DC_LOGGER, LOG_BACKLIGHT, a, ## __VA_ARGS__) +#define DC_LOG_FEATURE_OVERRIDE(a, ...) dm_logger_write(DC_LOGGER, LOG_FEATURE_OVERRIDE, a, ## __VA_ARGS__) +#define DC_LOG_DETECTION_EDID_PARSER(a, ...) dm_logger_write(DC_LOGGER, LOG_DETECTION_EDID_PARSER, a, ## __VA_ARGS__) +#define DC_LOG_DETECTION_DP_CAPS(a, ...) dm_logger_write(DC_LOGGER, LOG_DETECTION_DP_CAPS, a, ## __VA_ARGS__) +#define DC_LOG_RESOURCE(a, ...) dm_logger_write(DC_LOGGER, LOG_RESOURCE, a, ## __VA_ARGS__) +#define DC_LOG_DML(a, ...) dm_logger_write(DC_LOGGER, LOG_DML, a, ## __VA_ARGS__) +#define DC_LOG_EVENT_MODE_SET(a, ...) dm_logger_write(DC_LOGGER, LOG_EVENT_MODE_SET, a, ## __VA_ARGS__) +#define DC_LOG_EVENT_DETECTION(a, ...) dm_logger_write(DC_LOGGER, LOG_EVENT_DETECTION, a, ## __VA_ARGS__) +#define DC_LOG_EVENT_LINK_TRAINING(a, ...) dm_logger_write(DC_LOGGER, LOG_EVENT_LINK_TRAINING, a, ## __VA_ARGS__) +#define DC_LOG_EVENT_LINK_LOSS(a, ...) dm_logger_write(DC_LOGGER, LOG_EVENT_LINK_LOSS, a, ## __VA_ARGS__) +#define DC_LOG_EVENT_UNDERFLOW(a, ...) dm_logger_write(DC_LOGGER, LOG_EVENT_UNDERFLOW, a, ## __VA_ARGS__) +#define DC_LOG_IF_TRACE(a, ...) dm_logger_write(DC_LOGGER, LOG_IF_TRACE, a, ## __VA_ARGS__) +#define DC_LOG_PERF_TRACE(a, ...) dm_logger_write(DC_LOGGER, LOG_PERF_TRACE, a, ## __VA_ARGS__) struct dal_logger; -- cgit v1.2.3 From 28d4175413efe4ec4e6db1a197ab66d4b89c0a93 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Wed, 21 Feb 2018 15:10:02 -0500 Subject: drm/amd/display: fix dcn1 dppclk when min dispclk patch applies Applying min dispclk patch would result in incorrect dppclk divider without this change Signed-off-by: Dmytro Laktyushkin Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index f1d8db56f406..8020bc7742c1 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -998,7 +998,7 @@ bool dcn_validate_bandwidth( dc->debug.min_disp_clk_khz; } - context->bw.dcn.calc_clk.max_dppclk_khz = (int)(v->dppclk * 1000); + context->bw.dcn.calc_clk.max_dppclk_khz = context->bw.dcn.calc_clk.dispclk_khz / v->dispclk_dppclk_ratio; for (i = 0, input_idx = 0; i < pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; -- cgit v1.2.3 From f215a57dca691c0ba1c96a8905c46c1168b66ad3 Mon Sep 17 00:00:00 2001 From: Eric Yang Date: Wed, 21 Feb 2018 16:37:16 -0500 Subject: drm/amd/display: update infoframe after dig fe is turned on Before dig fe is enabled, infoframe can't be programmed. So in suspend resume case our infoframe programmming was not going through. This change changes the sequence so that infoframe is programmed after. Signed-off-by: Eric Yang Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- .../amd/display/dc/dce110/dce110_hw_sequencer.c | 23 ++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers') 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 f21aa04e93da..c2041a63cccd 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 @@ -684,15 +684,22 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; struct dc_link *link = pipe_ctx->stream->sink->link; - /* 1. update AVI info frame (HDMI, DP) - * we always need to update info frame - */ + uint32_t active_total_with_borders; uint32_t early_control = 0; struct timing_generator *tg = pipe_ctx->stream_res.tg; - /* TODOFPGA may change to hwss.update_info_frame */ + /* For MST, there are multiply stream go to only one link. + * connect DIG back_end to front_end while enable_stream and + * disconnect them during disable_stream + * BY this, it is logic clean to separate stream and link */ + link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, + pipe_ctx->stream_res.stream_enc->id, true); + + /* update AVI info frame (HDMI, DP)*/ + /* TODO: FPGA may change to hwss.update_info_frame */ dce110_update_info_frame(pipe_ctx); + /* enable early control to avoid corruption on DP monitor*/ active_total_with_borders = timing->h_addressable @@ -713,12 +720,8 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc); } - /* For MST, there are multiply stream go to only one link. - * connect DIG back_end to front_end while enable_stream and - * disconnect them during disable_stream - * BY this, it is logic clean to separate stream and link */ - link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, - pipe_ctx->stream_res.stream_enc->id, true); + + } -- cgit v1.2.3 From cc3ca53332de2b347c45262fcfb162fc186fa247 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Fri, 9 Feb 2018 16:52:15 -0500 Subject: drm/amd/display: Remove duplicate dm_pp_power_level enum This is really just a copy of dm_pp_clocks_state, so just use that one. Thanks to Matthias Kaehlke for spotting this. Signed-off-by: Harry Wentland Reviewed-by: Roman Li Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dm_services_types.h | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dm_services_types.h b/drivers/gpu/drm/amd/display/dc/dm_services_types.h index fa26cf488b3c..25ece5315353 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services_types.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services_types.h @@ -239,25 +239,8 @@ enum dm_acpi_display_type { AcpiDisplayType_DFP6 = 12 }; -enum dm_pp_power_level { - DM_PP_POWER_LEVEL_INVALID, - DM_PP_POWER_LEVEL_ULTRA_LOW, - DM_PP_POWER_LEVEL_LOW, - DM_PP_POWER_LEVEL_NOMINAL, - DM_PP_POWER_LEVEL_PERFORMANCE, - - DM_PP_POWER_LEVEL_0 = DM_PP_POWER_LEVEL_ULTRA_LOW, - DM_PP_POWER_LEVEL_1 = DM_PP_POWER_LEVEL_LOW, - DM_PP_POWER_LEVEL_2 = DM_PP_POWER_LEVEL_NOMINAL, - DM_PP_POWER_LEVEL_3 = DM_PP_POWER_LEVEL_PERFORMANCE, - DM_PP_POWER_LEVEL_4 = DM_PP_CLOCKS_DPM_STATE_LEVEL_3 + 1, - DM_PP_POWER_LEVEL_5 = DM_PP_CLOCKS_DPM_STATE_LEVEL_4 + 1, - DM_PP_POWER_LEVEL_6 = DM_PP_CLOCKS_DPM_STATE_LEVEL_5 + 1, - DM_PP_POWER_LEVEL_7 = DM_PP_CLOCKS_DPM_STATE_LEVEL_6 + 1, -}; - struct dm_pp_power_level_change_request { - enum dm_pp_power_level power_level; + enum dm_pp_clocks_state power_level; }; struct dm_pp_clock_for_voltage_req { -- cgit v1.2.3 From 5dd0bb34edc160cf725f8e00e3bc3c8be883842e Mon Sep 17 00:00:00 2001 From: Tony Cheng Date: Wed, 21 Feb 2018 16:40:50 -0500 Subject: drm/amd/display: dal 3.1.37 Signed-off-by: Tony Cheng Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index e954705f7f0f..7f0dbf6a866a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -38,7 +38,7 @@ #include "inc/compressor.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.1.36" +#define DC_VER "3.1.37" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- cgit v1.2.3 From 589d2739332db0b8e17e0fc827525311c211a410 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Tue, 13 Feb 2018 10:54:26 -0500 Subject: drm/amd/display: Use crtc enable/disable_vblank hooks Signed-off-by: Harry Wentland Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') 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 92fe2111e774..258657d20f88 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2490,6 +2490,28 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) return &state->base; } + +static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) +{ + enum dc_irq_source irq_source; + struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); + struct amdgpu_device *adev = crtc->dev->dev_private; + + irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; + dc_interrupt_set(adev->dm.dc, irq_source, enable); + return 0; +} + +static int dm_enable_vblank(struct drm_crtc *crtc) +{ + return dm_set_vblank(crtc, true); +} + +static void dm_disable_vblank(struct drm_crtc *crtc) +{ + dm_set_vblank(crtc, false); +} + /* Implemented only the options currently availible for the driver */ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { .reset = dm_crtc_reset_state, @@ -2500,6 +2522,8 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { .atomic_duplicate_state = dm_crtc_duplicate_state, .atomic_destroy_state = dm_crtc_destroy_state, .set_crc_source = amdgpu_dm_crtc_set_crc_source, + .enable_vblank = dm_enable_vblank, + .disable_vblank = dm_disable_vblank, }; static enum drm_connector_status -- cgit v1.2.3 From a0e30392dd03727c069d1cf93ee6582473dd3dd6 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Tue, 13 Feb 2018 11:03:01 -0500 Subject: drm/amd/display: Return success when enabling interrupt Signed-off-by: Harry Wentland Reviewed-by: Roman Li Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +-- drivers/gpu/drm/amd/display/dc/core/dc.c | 6 +++--- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') 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 258657d20f88..9a1e82305b07 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2498,8 +2498,7 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) struct amdgpu_device *adev = crtc->dev->dev_private; irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; - dc_interrupt_set(adev->dm.dc, irq_source, enable); - return 0; + return dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; } static int dm_enable_vblank(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 2bc15a46882a..8394d69b963f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1516,13 +1516,13 @@ enum dc_irq_source dc_interrupt_to_irq_source( return dal_irq_service_to_irq_source(dc->res_pool->irqs, src_id, ext_id); } -void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) +bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) { if (dc == NULL) - return; + return false; - dal_irq_service_set(dc->res_pool->irqs, src, enable); + return dal_irq_service_set(dc->res_pool->irqs, src, enable); } void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 7f0dbf6a866a..2cd97342bf0f 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -705,7 +705,7 @@ enum dc_irq_source dc_interrupt_to_irq_source( struct dc *dc, uint32_t src_id, uint32_t ext_id); -void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable); +bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable); void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src); enum dc_irq_source dc_get_hpd_irq_source_at_index( struct dc *dc, uint32_t link_index); -- cgit v1.2.3 From 33f2d94ecd0ebb9c9c651691b4535332aac40edf Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Tue, 13 Feb 2018 11:07:07 -0500 Subject: drm/amd/display: Clean up formatting in irq_service_dce110.c Signed-off-by: Harry Wentland Reviewed-by: Roman Li Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- .../amd/display/dc/irq/dce110/irq_service_dce110.c | 62 +++++++++------------- 1 file changed, 26 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c index aa260f9562a2..9bc1c1d90bad 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c @@ -39,27 +39,22 @@ #define DC_LOGGER \ irq_service->ctx->logger -static bool hpd_ack( - struct irq_service *irq_service, - const struct irq_source_info *info) +static bool hpd_ack(struct irq_service *irq_service, + const struct irq_source_info *info) { uint32_t addr = info->status_reg; uint32_t value = dm_read_reg(irq_service->ctx, addr); - uint32_t current_status = - get_reg_field_value( - value, - DC_HPD_INT_STATUS, - DC_HPD_SENSE_DELAYED); + uint32_t current_status = get_reg_field_value(value, + DC_HPD_INT_STATUS, + DC_HPD_SENSE_DELAYED); dal_irq_service_ack_generic(irq_service, info); value = dm_read_reg(irq_service->ctx, info->enable_reg); - set_reg_field_value( - value, - current_status ? 0 : 1, - DC_HPD_INT_CONTROL, - DC_HPD_INT_POLARITY); + set_reg_field_value(value, current_status ? 0 : 1, + DC_HPD_INT_CONTROL, + DC_HPD_INT_POLARITY); dm_write_reg(irq_service->ctx, info->enable_reg, value); @@ -179,37 +174,34 @@ static const struct irq_source_info_funcs vblank_irq_info_funcs = { #define dc_underflow_int_entry(reg_num) \ [DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry() -bool dal_irq_service_dummy_set( - struct irq_service *irq_service, - const struct irq_source_info *info, - bool enable) +bool dal_irq_service_dummy_set(struct irq_service *irq_service, + const struct irq_source_info *info, + bool enable) { DC_LOG_ERROR("%s: called for non-implemented irq source\n", - __func__); + __func__); return false; } -bool dal_irq_service_dummy_ack( - struct irq_service *irq_service, - const struct irq_source_info *info) +bool dal_irq_service_dummy_ack(struct irq_service *irq_service, + const struct irq_source_info *info) { DC_LOG_ERROR("%s: called for non-implemented irq source\n", - __func__); + __func__); return false; } -bool dce110_vblank_set( - struct irq_service *irq_service, - const struct irq_source_info *info, - bool enable) +bool dce110_vblank_set(struct irq_service *irq_service, + const struct irq_source_info *info, + bool enable) { struct dc_context *dc_ctx = irq_service->ctx; struct dc *core_dc = irq_service->ctx->dc; - enum dc_irq_source dal_irq_src = dc_interrupt_to_irq_source( - irq_service->ctx->dc, - info->src_id, - info->ext_id); + enum dc_irq_source dal_irq_src = + dc_interrupt_to_irq_source(irq_service->ctx->dc, + info->src_id, + info->ext_id); uint8_t pipe_offset = dal_irq_src - IRQ_TYPE_VBLANK; struct timing_generator *tg = @@ -224,7 +216,6 @@ bool dce110_vblank_set( dal_irq_service_set_generic(irq_service, info, enable); return true; - } static const struct irq_source_info_funcs dummy_irq_info_funcs = { @@ -405,9 +396,8 @@ static const struct irq_service_funcs irq_service_funcs_dce110 = { .to_dal_irq_source = to_dal_irq_source_dce110 }; -static void construct( - struct irq_service *irq_service, - struct irq_service_init_data *init_data) +static void construct(struct irq_service *irq_service, + struct irq_service_init_data *init_data) { dal_irq_service_construct(irq_service, init_data); @@ -415,8 +405,8 @@ static void construct( irq_service->funcs = &irq_service_funcs_dce110; } -struct irq_service *dal_irq_service_dce110_create( - struct irq_service_init_data *init_data) +struct irq_service * +dal_irq_service_dce110_create(struct irq_service_init_data *init_data) { struct irq_service *irq_service = kzalloc(sizeof(*irq_service), GFP_KERNEL); -- cgit v1.2.3 From c21b68c5ebd9b0267d59c7a899ee4c6a7e0668fc Mon Sep 17 00:00:00 2001 From: Shirish S Date: Fri, 16 Feb 2018 11:44:22 +0530 Subject: drm/amd/display: defer modeset check in dm_update_planes_state amdgpu_dm_atomic_check() is used to validate the entire configuration of planes and crtc's that the user space wants to commit. However amdgpu_dm_atomic_check() depends upon DRM_MODE_ATOMIC_ALLOW_MODESET flag else its mostly dummy. Its not mandatory for the user space to set DRM_MODE_ATOMIC_ALLOW_MODESET, and in general its not set either along with DRM_MODE_ATOMIC_TEST_ONLY. Considering its importantance, this patch defers the allow_modeset check in dm_update_planes_state(), so that there shall be scope to validate the configuration sent from user space, without impacting the population of dc/dm related data structures. Signed-off-by: Shirish S Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') 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 9a1e82305b07..2c5ef6619b17 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4687,8 +4687,6 @@ static int dm_update_planes_state(struct dc *dc, bool pflip_needed = !state->allow_modeset; int ret = 0; - if (pflip_needed) - return ret; /* Add new planes */ for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { @@ -4703,6 +4701,8 @@ static int dm_update_planes_state(struct dc *dc, /* Remove any changed/removed planes */ if (!enable) { + if (pflip_needed) + continue; if (!old_plane_crtc) continue; @@ -4747,6 +4747,8 @@ static int dm_update_planes_state(struct dc *dc, if (!dm_new_crtc_state->stream) continue; + if (pflip_needed) + continue; WARN_ON(dm_new_plane_state->dc_state); -- cgit v1.2.3 From 080589737c13a079bb0355377815b0c0c1cdf779 Mon Sep 17 00:00:00 2001 From: Shirish S Date: Tue, 13 Feb 2018 14:11:37 +0530 Subject: drm/amd/display: validate plane in dce110 for scaling CZ & ST support uptil a limit 2:1 downscaling, this patch adds validate_plane hook, that shall be used to validate the plane attributes sent by the user space based on dce110 capabilities. Signed-off-by: Shirish S Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 9b34c400c041..830cbbc4adeb 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -846,6 +846,16 @@ static bool dce110_validate_bandwidth( return result; } +enum dc_status dce110_validate_plane(const struct dc_plane_state *plane_state, + struct dc_caps *caps) +{ + if (((plane_state->dst_rect.width * 2) < plane_state->src_rect.width) || + ((plane_state->dst_rect.height * 2) < plane_state->src_rect.height)) + return DC_FAIL_SURFACE_VALIDATE; + + return DC_OK; +} + static bool dce110_validate_surface_sets( struct dc_state *context) { @@ -1021,6 +1031,7 @@ static const struct resource_funcs dce110_res_pool_funcs = { .link_enc_create = dce110_link_encoder_create, .validate_guaranteed = dce110_validate_guaranteed, .validate_bandwidth = dce110_validate_bandwidth, + .validate_plane = dce110_validate_plane, .acquire_idle_pipe_for_layer = dce110_acquire_underlay, .add_stream_to_ctx = dce110_add_stream_to_ctx, .validate_global = dce110_validate_global -- cgit v1.2.3 From c827206f7f78a33eff9496201c4122c246c87db3 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Tue, 13 Feb 2018 11:07:43 -0500 Subject: drm/amd/display: Don't blow up if TG is NULL in dce110_vblank_set Signed-off-by: Harry Wentland Reviewed-by: Roman Li Acked-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c index 9bc1c1d90bad..afe0876fe6f8 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c @@ -208,7 +208,7 @@ bool dce110_vblank_set(struct irq_service *irq_service, core_dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg; if (enable) { - if (!tg->funcs->arm_vert_intr(tg, 2)) { + if (!tg || !tg->funcs->arm_vert_intr(tg, 2)) { DC_ERROR("Failed to get VBLANK!\n"); return false; } -- cgit v1.2.3 From a05bcff10426841351010e8648e4d9d95e9b65a1 Mon Sep 17 00:00:00 2001 From: Shirish S Date: Tue, 13 Feb 2018 14:15:17 +0530 Subject: drm/amd/display: update plane params before validation This patch updates the dc's plane state with the parameters set by the user side. This is needed to validate the plane capabilities with the parameters user space wants to set. Signed-off-by: Shirish S Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') 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 2c5ef6619b17..5b175b7c507c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3086,6 +3086,9 @@ static int dm_plane_atomic_check(struct drm_plane *plane, if (!dm_plane_state->dc_state) return 0; + if (!fill_rects_from_plane_state(state, dm_plane_state->dc_state)) + return -EINVAL; + if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK) return 0; -- cgit v1.2.3 From ea74e15fb547483f9f86088443f2d3c9f518de8b Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Tue, 20 Feb 2018 13:36:23 -0500 Subject: drm/amd/display: Default HDMI6G support to true. Log VBIOS table error. There have been many reports of Ellesmere and Baffin systems not being able to drive HDMI 4k60 due to the fact that we check the HDMI_6GB_EN bit from VBIOS table. Windows seems to not have this issue. On some systems we fail to the encoder cap info from VBIOS. In that case we should default to enabling HDMI6G support. This was tested by dwagner on https://bugs.freedesktop.org/show_bug.cgi?id=102820 Signed-off-by: Harry Wentland Reviewed-by: Roman Li Reviewed-by: Tony Cheng Acked-by: Harry Wentland Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index f0d63ac7724a..81776e4797ed 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -678,6 +678,7 @@ void dce110_link_encoder_construct( { struct bp_encoder_cap_info bp_cap_info = {0}; const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; + enum bp_result result = BP_RESULT_OK; enc110->base.funcs = &dce110_lnk_enc_funcs; enc110->base.ctx = init_data->ctx; @@ -752,15 +753,24 @@ void dce110_link_encoder_construct( enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; } + /* default to one to mirror Windows behavior */ + enc110->base.features.flags.bits.HDMI_6GB_EN = 1; + + result = bp_funcs->get_encoder_cap_info(enc110->base.ctx->dc_bios, + enc110->base.id, &bp_cap_info); + /* Override features with DCE-specific values */ - if (BP_RESULT_OK == bp_funcs->get_encoder_cap_info( - enc110->base.ctx->dc_bios, enc110->base.id, - &bp_cap_info)) { + if (BP_RESULT_OK == result) { enc110->base.features.flags.bits.IS_HBR2_CAPABLE = bp_cap_info.DP_HBR2_EN; enc110->base.features.flags.bits.IS_HBR3_CAPABLE = bp_cap_info.DP_HBR3_EN; enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; + } else { + dm_logger_write(enc110->base.ctx->logger, LOG_WARNING, + "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", + __func__, + result); } } -- cgit v1.2.3 From c396ef9bf3172fd57e86df4529b11d563f9ff801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 1 Mar 2018 10:41:46 +0100 Subject: drm/amdgpu: move some functions into amdgpu_ttm.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those belong to the TTM handling. Signed-off-by: Christian König Reviewed-by: Chunming Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 86fbc8649af0..eba4abc8aac6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1827,9 +1827,6 @@ void amdgpu_device_vram_location(struct amdgpu_device *adev, void amdgpu_device_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc); int amdgpu_device_resize_fb_bar(struct amdgpu_device *adev); -void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size); -int amdgpu_ttm_init(struct amdgpu_device *adev); -void amdgpu_ttm_fini(struct amdgpu_device *adev); void amdgpu_device_program_register_sequence(struct amdgpu_device *adev, const u32 *registers, const u32 array_size); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index d31491069f2f..0fba23c69e97 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -75,6 +75,10 @@ int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man); uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man); uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man); +int amdgpu_ttm_init(struct amdgpu_device *adev); +void amdgpu_ttm_fini(struct amdgpu_device *adev); +void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size); + int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset, uint64_t dst_offset, uint32_t byte_count, struct reservation_object *resv, -- cgit v1.2.3 From 57adc4cef617d7284ac7676e14533268e73e3699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 1 Mar 2018 11:01:52 +0100 Subject: drm/amdgpu: change amdgpu_ttm_set_active_vram_size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of setting the active VRAM size directly provide a the info if we can use the buffer functions or not. Signed-off-by: Christian König Acked-by: Chunming zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 23 +++++++++++++++++------ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 3 ++- drivers/gpu/drm/amd/amdgpu/cik_sdma.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/si_dma.c | 4 ++-- 7 files changed, 29 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index f126a5ae41b3..46d7a690a287 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1411,7 +1411,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) adev->gmc.visible_vram_size = vis_vram_limit; /* Change the size here instead of the init above so only lpfn is affected */ - amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); + amdgpu_ttm_set_buffer_funcs_status(adev, false); #ifdef CONFIG_64BIT adev->mman.aper_base_kaddr = ioremap_wc(adev->gmc.aper_base, adev->gmc.visible_vram_size); @@ -1526,17 +1526,28 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) DRM_INFO("amdgpu: ttm finalized\n"); } -/* this should only be called at bootup or when userspace - * isn't running */ -void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size) +/** + * amdgpu_ttm_set_buffer_funcs_status - enable/disable use of buffer functions + * + * @adev: amdgpu_device pointer + * @enable: true when we can use buffer functions. + * + * Enable/disable use of buffer functions during suspend/resume. This should + * only be called at bootup or when userspace isn't running. + */ +void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable) { - struct ttm_mem_type_manager *man; + struct ttm_mem_type_manager *man = &adev->mman.bdev.man[TTM_PL_VRAM]; + uint64_t size; if (!adev->mman.initialized) return; - man = &adev->mman.bdev.man[TTM_PL_VRAM]; /* this just adjusts TTM size idea, which sets lpfn to the correct value */ + if (enable) + size = adev->gmc.real_vram_size; + else + size = adev->gmc.visible_vram_size; man->size = size >> PAGE_SHIFT; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 0fba23c69e97..b8117c6e51f1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -77,7 +77,8 @@ uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man); int amdgpu_ttm_init(struct amdgpu_device *adev); void amdgpu_ttm_fini(struct amdgpu_device *adev); -void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size); +void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, + bool enable); int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset, uint64_t dst_offset, uint32_t byte_count, diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index 69568cd1bb99..f48ea0dad875 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -310,7 +310,7 @@ static void cik_sdma_gfx_stop(struct amdgpu_device *adev) if ((adev->mman.buffer_funcs_ring == sdma0) || (adev->mman.buffer_funcs_ring == sdma1)) - amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); + amdgpu_ttm_set_buffer_funcs_status(adev, false); for (i = 0; i < adev->sdma.num_instances; i++) { rb_cntl = RREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i]); @@ -510,7 +510,7 @@ static int cik_sdma_gfx_resume(struct amdgpu_device *adev) } if (adev->mman.buffer_funcs_ring == ring) - amdgpu_ttm_set_active_vram_size(adev, adev->gmc.real_vram_size); + amdgpu_ttm_set_buffer_funcs_status(adev, true); } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index 6ccc9d43a7b8..6452101c7aab 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -339,7 +339,7 @@ static void sdma_v2_4_gfx_stop(struct amdgpu_device *adev) if ((adev->mman.buffer_funcs_ring == sdma0) || (adev->mman.buffer_funcs_ring == sdma1)) - amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); + amdgpu_ttm_set_buffer_funcs_status(adev, false); for (i = 0; i < adev->sdma.num_instances; i++) { rb_cntl = RREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i]); @@ -484,7 +484,7 @@ static int sdma_v2_4_gfx_resume(struct amdgpu_device *adev) } if (adev->mman.buffer_funcs_ring == ring) - amdgpu_ttm_set_active_vram_size(adev, adev->gmc.real_vram_size); + amdgpu_ttm_set_buffer_funcs_status(adev, true); } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 0c2b12ec0e9f..9c4efd4effc6 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -510,7 +510,7 @@ static void sdma_v3_0_gfx_stop(struct amdgpu_device *adev) if ((adev->mman.buffer_funcs_ring == sdma0) || (adev->mman.buffer_funcs_ring == sdma1)) - amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); + amdgpu_ttm_set_buffer_funcs_status(adev, false); for (i = 0; i < adev->sdma.num_instances; i++) { rb_cntl = RREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i]); @@ -750,7 +750,7 @@ static int sdma_v3_0_gfx_resume(struct amdgpu_device *adev) } if (adev->mman.buffer_funcs_ring == ring) - amdgpu_ttm_set_active_vram_size(adev, adev->gmc.real_vram_size); + amdgpu_ttm_set_buffer_funcs_status(adev, true); } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index 87c01d958703..215743df0957 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -426,7 +426,7 @@ static void sdma_v4_0_gfx_stop(struct amdgpu_device *adev) if ((adev->mman.buffer_funcs_ring == sdma0) || (adev->mman.buffer_funcs_ring == sdma1)) - amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); + amdgpu_ttm_set_buffer_funcs_status(adev, false); for (i = 0; i < adev->sdma.num_instances; i++) { rb_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL)); @@ -668,7 +668,7 @@ static int sdma_v4_0_gfx_resume(struct amdgpu_device *adev) } if (adev->mman.buffer_funcs_ring == ring) - amdgpu_ttm_set_active_vram_size(adev, adev->gmc.real_vram_size); + amdgpu_ttm_set_buffer_funcs_status(adev, true); } diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c index acbf5afa4f38..b75d901ba3c4 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dma.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dma.c @@ -121,7 +121,7 @@ static void si_dma_stop(struct amdgpu_device *adev) WREG32(DMA_RB_CNTL + sdma_offsets[i], rb_cntl); if (adev->mman.buffer_funcs_ring == ring) - amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); + amdgpu_ttm_set_buffer_funcs_status(adev, false); ring->ready = false; } } @@ -184,7 +184,7 @@ static int si_dma_start(struct amdgpu_device *adev) } if (adev->mman.buffer_funcs_ring == ring) - amdgpu_ttm_set_active_vram_size(adev, adev->gmc.real_vram_size); + amdgpu_ttm_set_buffer_funcs_status(adev, true); } return 0; -- cgit v1.2.3 From 380383f23594790be97639ea220e8d3e86afff85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 1 Mar 2018 11:03:27 +0100 Subject: drm/amdgpu: ignore changes of buffer function status because of GPU resets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we reset the GPU we also disable/enable the SDMA, but we don't want to change TTM idea of the VRAM size in the middle of that. Signed-off-by: Christian König Acked-by: Chunming zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 46d7a690a287..2aa6823ef503 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1540,7 +1540,7 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable) struct ttm_mem_type_manager *man = &adev->mman.bdev.man[TTM_PL_VRAM]; uint64_t size; - if (!adev->mman.initialized) + if (!adev->mman.initialized || adev->in_gpu_reset) return; /* this just adjusts TTM size idea, which sets lpfn to the correct value */ -- cgit v1.2.3 From 81988f9c3d9907d7df0ea97e8e4842064b88b7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 1 Mar 2018 11:09:15 +0100 Subject: drm/amdgpu: use separate status for buffer funcs availability v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ring status can change during GPU reset, but we still need to be able to schedule TTM buffer moves in the meantime. Otherwise we can ran into problems because of aborted move/fill operations during GPU resets. v2: still check if ring is available during direct submit. Signed-off-by: Christian König Acked-by: Chunming zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 21 +++++++++++---------- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 1 + 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 2aa6823ef503..614811061d3d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -213,9 +213,7 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, abo = ttm_to_amdgpu_bo(bo); switch (bo->mem.mem_type) { case TTM_PL_VRAM: - if (adev->mman.buffer_funcs && - adev->mman.buffer_funcs_ring && - adev->mman.buffer_funcs_ring->ready == false) { + if (!adev->mman.buffer_funcs_enabled) { amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU); } else if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && !(abo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)) { @@ -331,7 +329,7 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev, const uint64_t GTT_MAX_BYTES = (AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GPU_PAGE_SIZE); - if (!ring->ready) { + if (!adev->mman.buffer_funcs_enabled) { DRM_ERROR("Trying to move memory with ring turned off.\n"); return -EINVAL; } @@ -577,12 +575,9 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, amdgpu_move_null(bo, new_mem); return 0; } - if (adev->mman.buffer_funcs == NULL || - adev->mman.buffer_funcs_ring == NULL || - !adev->mman.buffer_funcs_ring->ready) { - /* use memcpy */ + + if (!adev->mman.buffer_funcs_enabled) goto memcpy; - } if (old_mem->mem_type == TTM_PL_VRAM && new_mem->mem_type == TTM_PL_SYSTEM) { @@ -1549,6 +1544,7 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable) else size = adev->gmc.visible_vram_size; man->size = size >> PAGE_SHIFT; + adev->mman.buffer_funcs_enabled = enable; } int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma) @@ -1647,6 +1643,11 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset, unsigned i; int r; + if (direct_submit && !ring->ready) { + DRM_ERROR("Trying to move memory with ring turned off.\n"); + return -EINVAL; + } + max_bytes = adev->mman.buffer_funcs->copy_max_bytes; num_loops = DIV_ROUND_UP(byte_count, max_bytes); num_dw = num_loops * adev->mman.buffer_funcs->copy_num_dw; @@ -1720,7 +1721,7 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo, struct amdgpu_job *job; int r; - if (!ring->ready) { + if (!adev->mman.buffer_funcs_enabled) { DRM_ERROR("Trying to clear memory with ring turned off.\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index b8117c6e51f1..6ea7de863041 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -53,6 +53,7 @@ struct amdgpu_mman { /* buffer handling */ const struct amdgpu_buffer_funcs *buffer_funcs; struct amdgpu_ring *buffer_funcs_ring; + bool buffer_funcs_enabled; struct mutex gtt_window_lock; /* Scheduler entity for buffer moves */ -- cgit v1.2.3 From a44f8626603292c40bb88e11db0a50bb8c9a900a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 23 Feb 2018 12:29:04 +0100 Subject: drm/amdgpu/dce6: Use DRM_DEBUG instead of DRM_INFO for HPD IRQ info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency with other DCE generations. HPD IRQs appear to be working fine. Reviewed-by: Alex Deucher Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index 03f19363f8f6..ee2162e81da9 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -3037,7 +3037,7 @@ static int dce_v6_0_hpd_irq(struct amdgpu_device *adev, tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK; WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp); schedule_work(&adev->hotplug_work); - DRM_INFO("IH: HPD%d\n", hpd + 1); + DRM_DEBUG("IH: HPD%d\n", hpd + 1); } return 0; -- cgit v1.2.3 From 16a6620c32b0cffe7171181fa7cb57125235c107 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Fri, 2 Mar 2018 18:41:41 +0800 Subject: drm/amd/pp: Fix incorrect return value in smu7_check_clk_voltage_valid Reviewed-by: Evan Quan Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 731475b06be7..cb9e2f912311 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -4770,7 +4770,7 @@ static bool smu7_check_clk_voltage_valid(struct pp_hwmgr *hwmgr, struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table; if (table_info == NULL) - return -EINVAL; + return false; dep_sclk_table = table_info->vdd_dep_on_sclk; min_vddc = dep_sclk_table->entries[0].vddc; -- cgit v1.2.3 From b58f0c81e9ab40ebed723ac71c34d87769540ad2 Mon Sep 17 00:00:00 2001 From: Shirish S Date: Wed, 28 Feb 2018 12:14:58 +0530 Subject: drm/amd/display: disable CRTCs with NULL FB on their primary plane (V2) The below commit "drm/atomic: Try to preserve the crtc enabled state in drm_atomic_remove_fb, v2" introduces a slight behavioral change to rmfb. Instead of disabling a crtc when the primary plane is disabled, it now preserves it. This change leads to BUG hit while performing atomic commit on amd driver. As a fix this patch ensures that we disable the CRTC's with NULL FB by returning -EINVAL and hence triggering fall back to the old behavior and turning off the crtc in atomic_remove_fb(). V2: Added error check for plane_state and removed sanity check for crtc. Signed-off-by: Shirish S Signed-off-by: Pratik Vishwakarma Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers') 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 5b175b7c507c..8b5489f0e5e7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4796,6 +4796,30 @@ static int dm_update_planes_state(struct dc *dc, return ret; } +static int dm_atomic_check_plane_state_fb(struct drm_atomic_state *state, + struct drm_crtc *crtc) +{ + struct drm_plane *plane; + struct drm_crtc_state *crtc_state; + + WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc)); + + drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) { + struct drm_plane_state *plane_state = + drm_atomic_get_plane_state(state, plane); + + if (IS_ERR(plane_state)) + return -EDEADLK; + + crtc_state = drm_atomic_get_crtc_state(plane_state->state, crtc); + if (crtc->primary == plane && crtc_state->active) { + if (!plane_state->fb) + return -EINVAL; + } + } + return 0; +} + static int amdgpu_dm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { @@ -4819,6 +4843,10 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, goto fail; for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + ret = dm_atomic_check_plane_state_fb(state, crtc); + if (ret) + goto fail; + if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && !new_crtc_state->color_mgmt_changed) continue; -- cgit v1.2.3 From 2eeb3a839954616d6faa024da69d2990374995f0 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Mon, 26 Feb 2018 19:47:54 +0800 Subject: drm/amd/dc: Use forward declaration instand of include header file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit avoid build error: drivers/gpu/drm/amd/amdgpu/../powerplay/inc/smu9_driver_if.h:342:3: error: redeclaration of enumerator ‘WM_COUNT’ WM_COUNT, ^ In file included from drivers/gpu/drm/amd/amdgpu/../display/dc/dm_services_types.h:32:0, from drivers/gpu/drm/amd/amdgpu/../display/dc/dm_services.h:35, from drivers/gpu/drm/amd/amdgpu/../display/modules/inc/mod_freesync.h:57, from drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgpu_mode.h:48, from drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgpu.h:55, from drivers/gpu/drm/amd/amdgpu/../powerplay/inc/amd_powerplay.h:33, from drivers/gpu/drm/amd/amdgpu/../powerplay/inc/smumgr.h:26, from drivers/gpu/drm/amd/amdgpu/../powerplay/smumgr/vega10_smumgr.c:24: drivers/gpu/drm/amd/amdgpu/../display/dc/dm_pp_smu.h:43:2: note: previous definition of ‘WM_COUNT’ was here WM_COUNT, Reviewed-by: Alex Deucher Reviewed-by: Harry Wentland Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dm_services_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dm_services_types.h b/drivers/gpu/drm/amd/display/dc/dm_services_types.h index 25ece5315353..ab8c77d4e6df 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services_types.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services_types.h @@ -29,7 +29,7 @@ #include "os_types.h" #include "dc_types.h" -#include "dm_pp_smu.h" +struct pp_smu_funcs_rv; struct dm_pp_clock_range { int min_khz; -- cgit v1.2.3 From a2c120ce6b686c753968b7b1293c7bb878440b7f Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Mon, 26 Feb 2018 19:58:49 +0800 Subject: drm/amd/pp: Simplify the create of powerplay instance use adev as input parameter to create powerplay instance directly. delete cgs wrap layer for power play create. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c | 22 ----------------- drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c | 4 +-- drivers/gpu/drm/amd/include/cgs_common.h | 7 ------ drivers/gpu/drm/amd/include/kgd_pp_interface.h | 8 ------ drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 30 ++++++++++++++--------- drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h | 2 +- 6 files changed, 20 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index 72c9a7e2c373..9d6e1b08e148 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -42,27 +42,6 @@ struct amdgpu_cgs_device { struct amdgpu_device *adev = \ ((struct amdgpu_cgs_device *)cgs_device)->adev -static void *amdgpu_cgs_register_pp_handle(struct cgs_device *cgs_device, - int (*call_back_func)(struct amd_pp_init *, void **)) -{ - CGS_FUNC_ADEV; - struct amd_pp_init pp_init; - struct amd_powerplay *amd_pp; - - if (call_back_func == NULL) - return NULL; - - amd_pp = &(adev->powerplay); - pp_init.chip_family = adev->family; - pp_init.chip_id = adev->asic_type; - pp_init.pm_en = (amdgpu_dpm != 0 && !amdgpu_sriov_vf(adev)) ? true : false; - pp_init.feature_mask = amdgpu_pp_feature_mask; - pp_init.device = cgs_device; - if (call_back_func(&pp_init, &(amd_pp->pp_handle))) - return NULL; - - return adev->powerplay.pp_handle; -} static int amdgpu_cgs_alloc_gpu_mem(struct cgs_device *cgs_device, enum cgs_gpu_mem_type type, @@ -1233,7 +1212,6 @@ static const struct cgs_ops amdgpu_cgs_ops = { .is_virtualization_enabled = amdgpu_cgs_is_virtualization_enabled, .enter_safe_mode = amdgpu_cgs_enter_safe_mode, .lock_grbm_idx = amdgpu_cgs_lock_grbm_idx, - .register_pp_handle = amdgpu_cgs_register_pp_handle, .set_temperature_range = amdgpu_cgs_set_temperature_range, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c index 5f5aa5fddc16..5c2e2d5dc1ee 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c @@ -94,9 +94,7 @@ static int amdgpu_pp_early_init(void *handle) } if (adev->powerplay.ip_funcs->early_init) - ret = adev->powerplay.ip_funcs->early_init( - amd_pp->cgs_device ? amd_pp->cgs_device : - amd_pp->pp_handle); + ret = adev->powerplay.ip_funcs->early_init(adev); return ret; } diff --git a/drivers/gpu/drm/amd/include/cgs_common.h b/drivers/gpu/drm/amd/include/cgs_common.h index 98cf4cebff17..e5b4823d8ec1 100644 --- a/drivers/gpu/drm/amd/include/cgs_common.h +++ b/drivers/gpu/drm/amd/include/cgs_common.h @@ -424,10 +424,6 @@ typedef int (*cgs_enter_safe_mode)(struct cgs_device *cgs_device, bool en); typedef void (*cgs_lock_grbm_idx)(struct cgs_device *cgs_device, bool lock); -struct amd_pp_init; -typedef void* (*cgs_register_pp_handle)(struct cgs_device *cgs_device, - int (*call_back_func)(struct amd_pp_init *, void **)); - typedef int (*cgs_set_temperature_range)(struct cgs_device *cgs_device, int min_temperature, int max_temperature); @@ -467,7 +463,6 @@ struct cgs_ops { cgs_is_virtualization_enabled_t is_virtualization_enabled; cgs_enter_safe_mode enter_safe_mode; cgs_lock_grbm_idx lock_grbm_idx; - cgs_register_pp_handle register_pp_handle; cgs_set_temperature_range set_temperature_range; }; @@ -547,8 +542,6 @@ struct cgs_device #define cgs_lock_grbm_idx(cgs_device, lock) \ CGS_CALL(lock_grbm_idx, cgs_device, lock) -#define cgs_register_pp_handle(cgs_device, call_back_func) \ - CGS_CALL(register_pp_handle, cgs_device, call_back_func) #define cgs_set_temperature_range(dev, min_temp, max_temp) \ CGS_CALL(set_temperature_range, dev, min_temp, max_temp) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 22c2fa30731f..666a9e343270 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -136,14 +136,6 @@ enum amd_pp_task { AMD_PP_TASK_MAX }; -struct amd_pp_init { - struct cgs_device *device; - uint32_t chip_family; - uint32_t chip_id; - bool pm_en; - uint32_t feature_mask; -}; - enum PP_SMC_POWER_PROFILE { PP_SMC_POWER_PROFILE_FULLSCREEN3D = 0x0, PP_SMC_POWER_PROFILE_POWERSAVING = 0x1, diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 376ed2dd52c7..4e87cfc129b4 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -29,6 +29,7 @@ #include "amd_powerplay.h" #include "pp_instance.h" #include "power_state.h" +#include "amdgpu.h" #define PP_DPM_DISABLED 0xCCCC @@ -52,28 +53,30 @@ static inline int pp_check(struct pp_instance *handle) return 0; } -static int amd_powerplay_create(struct amd_pp_init *pp_init, - void **handle) +static int amd_powerplay_create(struct amdgpu_device *adev) { struct pp_instance *instance; - if (pp_init == NULL || handle == NULL) + if (adev == NULL) return -EINVAL; instance = kzalloc(sizeof(struct pp_instance), GFP_KERNEL); if (instance == NULL) return -ENOMEM; - instance->chip_family = pp_init->chip_family; - instance->chip_id = pp_init->chip_id; - instance->pm_en = pp_init->pm_en; - instance->feature_mask = pp_init->feature_mask; - instance->device = pp_init->device; + instance->chip_family = adev->family; + instance->chip_id = adev->asic_type; + instance->pm_en = (amdgpu_dpm != 0 && !amdgpu_sriov_vf(adev)) ? true : false; + instance->feature_mask = amdgpu_pp_feature_mask; + instance->device = adev->powerplay.cgs_device; mutex_init(&instance->pp_lock); - *handle = instance; + + adev->powerplay.pp_handle = instance; + return 0; } + static int amd_powerplay_destroy(void *handle) { struct pp_instance *instance = (struct pp_instance *)handle; @@ -93,11 +96,14 @@ static int pp_early_init(void *handle) { int ret; struct pp_instance *pp_handle = NULL; + struct amdgpu_device *adev = (struct amdgpu_device *)handle; - pp_handle = cgs_register_pp_handle(handle, amd_powerplay_create); + ret = amd_powerplay_create(adev); - if (!pp_handle) - return -EINVAL; + if (ret != 0) + return ret; + + pp_handle = adev->powerplay.pp_handle; ret = hwmgr_early_init(pp_handle); if (ret) diff --git a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h index 152e70db4a81..fe3665965416 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h +++ b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h @@ -30,6 +30,6 @@ #include "cgs_common.h" #include "dm_pp_interface.h" #include "kgd_pp_interface.h" - +#include "amdgpu.h" #endif /* _AMD_POWERPLAY_H_ */ -- cgit v1.2.3 From 65ad7cac3866f5fa80dcef3e5048a839046d6a46 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Tue, 27 Feb 2018 14:09:40 +0800 Subject: drm/amd/pp: Refine powerplay instance Include adev in powerplay instance. so can visit adev directly instand of through cgs interface. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 6 ++---- drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 7 ++++--- drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 1 + drivers/gpu/drm/amd/powerplay/inc/pp_instance.h | 8 +++----- 4 files changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 4e87cfc129b4..20ac0fc12483 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -30,6 +30,7 @@ #include "pp_instance.h" #include "power_state.h" #include "amdgpu.h" +#include "hwmgr.h" #define PP_DPM_DISABLED 0xCCCC @@ -64,13 +65,10 @@ static int amd_powerplay_create(struct amdgpu_device *adev) if (instance == NULL) return -ENOMEM; - instance->chip_family = adev->family; - instance->chip_id = adev->asic_type; + instance->parent = adev; instance->pm_en = (amdgpu_dpm != 0 && !amdgpu_sriov_vf(adev)) ? true : false; - instance->feature_mask = amdgpu_pp_feature_mask; instance->device = adev->powerplay.cgs_device; mutex_init(&instance->pp_lock); - adev->powerplay.pp_handle = instance; return 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index 33eabc18211d..7e1bd1144f5d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -146,10 +146,11 @@ int hwmgr_early_init(struct pp_instance *handle) return -ENOMEM; handle->hwmgr = hwmgr; + hwmgr->adev = handle->parent; hwmgr->device = handle->device; - hwmgr->chip_family = handle->chip_family; - hwmgr->chip_id = handle->chip_id; - hwmgr->feature_mask = handle->feature_mask; + hwmgr->chip_family = ((struct amdgpu_device *)handle->parent)->family; + hwmgr->chip_id = ((struct amdgpu_device *)handle->parent)->asic_type; + hwmgr->feature_mask = amdgpu_pp_feature_mask; hwmgr->usec_timeout = AMD_MAX_USEC_TIMEOUT; hwmgr->power_source = PP_PowerSource_AC; hwmgr->pp_table_version = PP_TABLE_V1; diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 77d7f49564c4..bb50cc2b4af1 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -700,6 +700,7 @@ enum PP_TABLE_VERSION { * The main hardware manager structure. */ struct pp_hwmgr { + void *adev; uint32_t chip_family; uint32_t chip_id; uint32_t smu_version; diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h b/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h index 7d1eec5d2e7a..6c2fa33bd63a 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h +++ b/drivers/gpu/drm/amd/powerplay/inc/pp_instance.h @@ -23,14 +23,12 @@ #ifndef _PP_INSTANCE_H_ #define _PP_INSTANCE_H_ -#include "hwmgr.h" +struct pp_hwmgr; struct pp_instance { - uint32_t chip_family; - uint32_t chip_id; + void *parent; /* e.g. amdgpu_device */ + void *device; /* e.g. cgs_device */ bool pm_en; - uint32_t feature_mask; - void *device; struct pp_hwmgr *hwmgr; struct mutex pp_lock; }; -- cgit v1.2.3 From 589941e1a2d65f5425c91a5859a5454df64b6982 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Tue, 27 Feb 2018 18:20:53 +0800 Subject: drm/amdgpu: Notify sbios device ready before send request it is required if a platform supports PCIe root complex core voltage reduction. After receiving this notification, SBIOS can apply default PCIe root complex power policy. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 57afad79f55d..8fa850a070e0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -540,6 +540,9 @@ int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, size_t size; u32 retry = 3; + if (amdgpu_acpi_pcie_notify_device_ready(adev)) + return -EINVAL; + /* Get the device handle */ handle = ACPI_HANDLE(&adev->pdev->dev); if (!handle) -- cgit v1.2.3 From e1deba285156fb4023bb48f22068de5b60e34e15 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Tue, 27 Feb 2018 18:27:54 +0800 Subject: drm/amd/pp: Use amdgpu acpi helper functions in powerplay Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 4 +--- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 7 +++---- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 1 - 3 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index 7e1bd1144f5d..28897882607e 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -33,7 +33,6 @@ #include "pppcielanes.h" #include "ppatomctrl.h" #include "ppsmc.h" -#include "pp_acpi.h" #include "amd_acpi.h" #include "pp_psm.h" @@ -895,8 +894,7 @@ void hwmgr_init_default_caps(struct pp_hwmgr *hwmgr) phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDDPM); phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEDPM); - if (acpi_atcs_functions_supported(hwmgr->device, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST) && - acpi_atcs_functions_supported(hwmgr->device, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION)) + if (amdgpu_acpi_is_pcie_performance_request_supported(hwmgr->adev)) phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PCIEPerformanceRequest); phm_cap_set(hwmgr->platform_descriptor.platformCaps, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index cb9e2f912311..928427d04ebd 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -27,7 +27,6 @@ #include #include #include -#include "pp_acpi.h" #include "ppatomctrl.h" #include "atombios.h" #include "pptable_v1_0.h" @@ -3615,13 +3614,13 @@ static int smu7_request_link_speed_change_before_state_change( if (target_link_speed > current_link_speed) { switch (target_link_speed) { case PP_PCIEGen3: - if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN3, false)) + if (0 == amdgpu_acpi_pcie_performance_request(hwmgr->adev, PCIE_PERF_REQ_GEN3, false)) break; data->force_pcie_gen = PP_PCIEGen2; if (current_link_speed == PP_PCIEGen2) break; case PP_PCIEGen2: - if (0 == acpi_pcie_perf_request(hwmgr->device, PCIE_PERF_REQ_GEN2, false)) + if (0 == amdgpu_acpi_pcie_performance_request(hwmgr->adev, PCIE_PERF_REQ_GEN2, false)) break; default: data->force_pcie_gen = smu7_get_current_pcie_speed(hwmgr); @@ -3843,7 +3842,7 @@ static int smu7_notify_link_speed_change_after_state_change( smu7_get_current_pcie_speed(hwmgr) > 0) return 0; - if (acpi_pcie_perf_request(hwmgr->device, request, false)) { + if (amdgpu_acpi_pcie_performance_request(hwmgr->adev, request, false)) { if (PP_PCIEGen2 == target_link_speed) pr_info("PSPP request to switch to Gen2 from Gen3 Failed!"); else diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index f5df20a22e97..a7c610a0e7e1 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -44,7 +44,6 @@ #include "vega10_pptable.h" #include "vega10_thermal.h" #include "pp_debug.h" -#include "pp_acpi.h" #include "amd_pcie_helpers.h" #include "cgs_linux.h" #include "ppinterrupt.h" -- cgit v1.2.3 From 6848d73e889bb29cfede51df8c1d0496c9787454 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Tue, 27 Feb 2018 18:28:54 +0800 Subject: drm/amd/pp: Remove the wrap functions for acpi in powerplay Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c | 212 -------------------------- drivers/gpu/drm/amd/include/cgs_common.h | 44 ------ drivers/gpu/drm/amd/powerplay/hwmgr/Makefile | 2 +- drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c | 114 -------------- drivers/gpu/drm/amd/powerplay/inc/pp_acpi.h | 26 ---- 5 files changed, 1 insertion(+), 397 deletions(-) delete mode 100644 drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c delete mode 100644 drivers/gpu/drm/amd/powerplay/inc/pp_acpi.h (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index 9d6e1b08e148..795be958cf5e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -964,216 +963,6 @@ static int amdgpu_cgs_notify_dpm_enabled(struct cgs_device *cgs_device, bool ena return 0; } -/** \brief evaluate acpi namespace object, handle or pathname must be valid - * \param cgs_device - * \param info input/output arguments for the control method - * \return status - */ - -#if defined(CONFIG_ACPI) -static int amdgpu_cgs_acpi_eval_object(struct cgs_device *cgs_device, - struct cgs_acpi_method_info *info) -{ - CGS_FUNC_ADEV; - acpi_handle handle; - struct acpi_object_list input; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *params, *obj; - uint8_t name[5] = {'\0'}; - struct cgs_acpi_method_argument *argument; - uint32_t i, count; - acpi_status status; - int result; - - handle = ACPI_HANDLE(&adev->pdev->dev); - if (!handle) - return -ENODEV; - - memset(&input, 0, sizeof(struct acpi_object_list)); - - /* validate input info */ - if (info->size != sizeof(struct cgs_acpi_method_info)) - return -EINVAL; - - input.count = info->input_count; - if (info->input_count > 0) { - if (info->pinput_argument == NULL) - return -EINVAL; - argument = info->pinput_argument; - for (i = 0; i < info->input_count; i++) { - if (((argument->type == ACPI_TYPE_STRING) || - (argument->type == ACPI_TYPE_BUFFER)) && - (argument->pointer == NULL)) - return -EINVAL; - argument++; - } - } - - if (info->output_count > 0) { - if (info->poutput_argument == NULL) - return -EINVAL; - argument = info->poutput_argument; - for (i = 0; i < info->output_count; i++) { - if (((argument->type == ACPI_TYPE_STRING) || - (argument->type == ACPI_TYPE_BUFFER)) - && (argument->pointer == NULL)) - return -EINVAL; - argument++; - } - } - - /* The path name passed to acpi_evaluate_object should be null terminated */ - if ((info->field & CGS_ACPI_FIELD_METHOD_NAME) != 0) { - strncpy(name, (char *)&(info->name), sizeof(uint32_t)); - name[4] = '\0'; - } - - /* parse input parameters */ - if (input.count > 0) { - input.pointer = params = - kzalloc(sizeof(union acpi_object) * input.count, GFP_KERNEL); - if (params == NULL) - return -EINVAL; - - argument = info->pinput_argument; - - for (i = 0; i < input.count; i++) { - params->type = argument->type; - switch (params->type) { - case ACPI_TYPE_INTEGER: - params->integer.value = argument->value; - break; - case ACPI_TYPE_STRING: - params->string.length = argument->data_length; - params->string.pointer = argument->pointer; - break; - case ACPI_TYPE_BUFFER: - params->buffer.length = argument->data_length; - params->buffer.pointer = argument->pointer; - break; - default: - break; - } - params++; - argument++; - } - } - - /* parse output info */ - count = info->output_count; - argument = info->poutput_argument; - - /* evaluate the acpi method */ - status = acpi_evaluate_object(handle, name, &input, &output); - - if (ACPI_FAILURE(status)) { - result = -EIO; - goto free_input; - } - - /* return the output info */ - obj = output.pointer; - - if (count > 1) { - if ((obj->type != ACPI_TYPE_PACKAGE) || - (obj->package.count != count)) { - result = -EIO; - goto free_obj; - } - params = obj->package.elements; - } else - params = obj; - - if (params == NULL) { - result = -EIO; - goto free_obj; - } - - for (i = 0; i < count; i++) { - if (argument->type != params->type) { - result = -EIO; - goto free_obj; - } - switch (params->type) { - case ACPI_TYPE_INTEGER: - argument->value = params->integer.value; - break; - case ACPI_TYPE_STRING: - if ((params->string.length != argument->data_length) || - (params->string.pointer == NULL)) { - result = -EIO; - goto free_obj; - } - strncpy(argument->pointer, - params->string.pointer, - params->string.length); - break; - case ACPI_TYPE_BUFFER: - if (params->buffer.pointer == NULL) { - result = -EIO; - goto free_obj; - } - memcpy(argument->pointer, - params->buffer.pointer, - argument->data_length); - break; - default: - break; - } - argument++; - params++; - } - - result = 0; -free_obj: - kfree(obj); -free_input: - kfree((void *)input.pointer); - return result; -} -#else -static int amdgpu_cgs_acpi_eval_object(struct cgs_device *cgs_device, - struct cgs_acpi_method_info *info) -{ - return -EIO; -} -#endif - -static int amdgpu_cgs_call_acpi_method(struct cgs_device *cgs_device, - uint32_t acpi_method, - uint32_t acpi_function, - void *pinput, void *poutput, - uint32_t output_count, - uint32_t input_size, - uint32_t output_size) -{ - struct cgs_acpi_method_argument acpi_input[2] = { {0}, {0} }; - struct cgs_acpi_method_argument acpi_output = {0}; - struct cgs_acpi_method_info info = {0}; - - acpi_input[0].type = CGS_ACPI_TYPE_INTEGER; - acpi_input[0].data_length = sizeof(uint32_t); - acpi_input[0].value = acpi_function; - - acpi_input[1].type = CGS_ACPI_TYPE_BUFFER; - acpi_input[1].data_length = input_size; - acpi_input[1].pointer = pinput; - - acpi_output.type = CGS_ACPI_TYPE_BUFFER; - acpi_output.data_length = output_size; - acpi_output.pointer = poutput; - - info.size = sizeof(struct cgs_acpi_method_info); - info.field = CGS_ACPI_FIELD_METHOD_NAME | CGS_ACPI_FIELD_INPUT_ARGUMENT_COUNT; - info.input_count = 2; - info.name = acpi_method; - info.pinput_argument = acpi_input; - info.output_count = output_count; - info.poutput_argument = &acpi_output; - - return amdgpu_cgs_acpi_eval_object(cgs_device, &info); -} - static int amdgpu_cgs_set_temperature_range(struct cgs_device *cgs_device, int min_temperature, int max_temperature) @@ -1207,7 +996,6 @@ static const struct cgs_ops amdgpu_cgs_ops = { .set_clockgating_state = amdgpu_cgs_set_clockgating_state, .get_active_displays_info = amdgpu_cgs_get_active_displays_info, .notify_dpm_enabled = amdgpu_cgs_notify_dpm_enabled, - .call_acpi_method = amdgpu_cgs_call_acpi_method, .query_system_info = amdgpu_cgs_query_system_info, .is_virtualization_enabled = amdgpu_cgs_is_virtualization_enabled, .enter_safe_mode = amdgpu_cgs_enter_safe_mode, diff --git a/drivers/gpu/drm/amd/include/cgs_common.h b/drivers/gpu/drm/amd/include/cgs_common.h index e5b4823d8ec1..851168b7b173 100644 --- a/drivers/gpu/drm/amd/include/cgs_common.h +++ b/drivers/gpu/drm/amd/include/cgs_common.h @@ -157,38 +157,6 @@ struct cgs_display_info { typedef unsigned long cgs_handle_t; -#define CGS_ACPI_METHOD_ATCS 0x53435441 -#define CGS_ACPI_METHOD_ATIF 0x46495441 -#define CGS_ACPI_METHOD_ATPX 0x58505441 -#define CGS_ACPI_FIELD_METHOD_NAME 0x00000001 -#define CGS_ACPI_FIELD_INPUT_ARGUMENT_COUNT 0x00000002 -#define CGS_ACPI_MAX_BUFFER_SIZE 256 -#define CGS_ACPI_TYPE_ANY 0x00 -#define CGS_ACPI_TYPE_INTEGER 0x01 -#define CGS_ACPI_TYPE_STRING 0x02 -#define CGS_ACPI_TYPE_BUFFER 0x03 -#define CGS_ACPI_TYPE_PACKAGE 0x04 - -struct cgs_acpi_method_argument { - uint32_t type; - uint32_t data_length; - union{ - uint32_t value; - void *pointer; - }; -}; - -struct cgs_acpi_method_info { - uint32_t size; - uint32_t field; - uint32_t input_count; - uint32_t name; - struct cgs_acpi_method_argument *pinput_argument; - uint32_t output_count; - struct cgs_acpi_method_argument *poutput_argument; - uint32_t padding[9]; -}; - /** * cgs_alloc_gpu_mem() - Allocate GPU memory * @cgs_device: opaque device handle @@ -407,14 +375,6 @@ typedef int(*cgs_get_active_displays_info)( typedef int (*cgs_notify_dpm_enabled)(struct cgs_device *cgs_device, bool enabled); -typedef int (*cgs_call_acpi_method)(struct cgs_device *cgs_device, - uint32_t acpi_method, - uint32_t acpi_function, - void *pinput, void *poutput, - uint32_t output_count, - uint32_t input_size, - uint32_t output_size); - typedef int (*cgs_query_system_info)(struct cgs_device *cgs_device, struct cgs_system_info *sys_info); @@ -456,8 +416,6 @@ struct cgs_ops { cgs_get_active_displays_info get_active_displays_info; /* notify dpm enabled */ cgs_notify_dpm_enabled notify_dpm_enabled; - /* ACPI */ - cgs_call_acpi_method call_acpi_method; /* get system info */ cgs_query_system_info query_system_info; cgs_is_virtualization_enabled_t is_virtualization_enabled; @@ -525,8 +483,6 @@ struct cgs_device #define cgs_get_active_displays_info(dev, info) \ CGS_CALL(get_active_displays_info, dev, info) -#define cgs_call_acpi_method(dev, acpi_method, acpi_function, pintput, poutput, output_count, input_size, output_size) \ - CGS_CALL(call_acpi_method, dev, acpi_method, acpi_function, pintput, poutput, output_count, input_size, output_size) #define cgs_query_system_info(dev, sys_info) \ CGS_CALL(query_system_info, dev, sys_info) #define cgs_get_pci_resource(cgs_device, resource_type, size, offset, \ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile index a212c27f2e17..e8c5a4f84324 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile @@ -24,7 +24,7 @@ # It provides the hardware management services for the driver. HARDWARE_MGR = hwmgr.o processpptables.o \ - hardwaremanager.o pp_acpi.o cz_hwmgr.o \ + hardwaremanager.o cz_hwmgr.o \ cz_clockpowergating.o pppcielanes.o\ process_pptables_v1_0.o ppatomctrl.o ppatomfwctrl.o \ smu7_hwmgr.o smu7_powertune.o smu7_thermal.o \ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c deleted file mode 100644 index f6b4dd96c0ec..000000000000 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_acpi.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include -#include "hwmgr.h" -#include "amd_acpi.h" -#include "pp_acpi.h" - -bool acpi_atcs_functions_supported(void *device, uint32_t index) -{ - int32_t result; - struct atcs_verify_interface output_buf = {0}; - - int32_t temp_buffer = 1; - - result = cgs_call_acpi_method(device, CGS_ACPI_METHOD_ATCS, - ATCS_FUNCTION_VERIFY_INTERFACE, - &temp_buffer, - &output_buf, - 1, - sizeof(temp_buffer), - sizeof(output_buf)); - - return result == 0 ? (output_buf.function_bits & (1 << (index - 1))) != 0 : false; -} - -bool acpi_atcs_notify_pcie_device_ready(void *device) -{ - int32_t temp_buffer = 1; - - return cgs_call_acpi_method(device, CGS_ACPI_METHOD_ATCS, - ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION, - &temp_buffer, - NULL, - 0, - sizeof(temp_buffer), - 0); -} - - -int acpi_pcie_perf_request(void *device, uint8_t perf_req, bool advertise) -{ - struct atcs_pref_req_input atcs_input; - struct atcs_pref_req_output atcs_output; - u32 retry = 3; - int result; - struct cgs_system_info info = {0}; - - if (acpi_atcs_notify_pcie_device_ready(device)) - return -EINVAL; - - info.size = sizeof(struct cgs_system_info); - info.info_id = CGS_SYSTEM_INFO_ADAPTER_BDF_ID; - result = cgs_query_system_info(device, &info); - if (result != 0) - return -EINVAL; - atcs_input.client_id = (uint16_t)info.value; - atcs_input.size = sizeof(struct atcs_pref_req_input); - atcs_input.valid_flags_mask = ATCS_VALID_FLAGS_MASK; - atcs_input.flags = ATCS_WAIT_FOR_COMPLETION; - if (advertise) - atcs_input.flags |= ATCS_ADVERTISE_CAPS; - atcs_input.req_type = ATCS_PCIE_LINK_SPEED; - atcs_input.perf_req = perf_req; - - atcs_output.size = sizeof(struct atcs_pref_req_input); - - while (retry--) { - result = cgs_call_acpi_method(device, - CGS_ACPI_METHOD_ATCS, - ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST, - &atcs_input, - &atcs_output, - 1, - sizeof(atcs_input), - sizeof(atcs_output)); - if (result != 0) - return -EIO; - - switch (atcs_output.ret_val) { - case ATCS_REQUEST_REFUSED: - default: - return -EINVAL; - case ATCS_REQUEST_COMPLETE: - return 0; - case ATCS_REQUEST_IN_PROGRESS: - udelay(10); - break; - } - } - - return 0; -} diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_acpi.h b/drivers/gpu/drm/amd/powerplay/inc/pp_acpi.h deleted file mode 100644 index 8fe8ba9434ff..000000000000 --- a/drivers/gpu/drm/amd/powerplay/inc/pp_acpi.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -bool acpi_atcs_functions_supported(void *device, uint32_t index); -int acpi_pcie_perf_request(void *device, uint8_t perf_req, bool advertise); -bool acpi_atcs_notify_pcie_device_ready(void *device); -- cgit v1.2.3 From ada6770e956b7f7d298bfef56fed457ade5bad9e Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Tue, 27 Feb 2018 19:15:08 +0800 Subject: drm/amd/pp: Remove cgs_query_system_info Get gpu info through adev directly in powerplay Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c | 59 ---------------------- drivers/gpu/drm/amd/include/cgs_common.h | 34 ------------- drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c | 22 ++++---- drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 54 ++++++-------------- .../amd/powerplay/hwmgr/smu7_clockpowergating.c | 17 ++----- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 57 ++++++--------------- .../gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c | 9 +--- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 18 ++----- .../gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c | 28 +++------- .../amd/powerplay/hwmgr/vega10_processpptables.c | 13 ++--- drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c | 14 ++--- .../gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c | 7 +-- .../gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c | 13 ++--- .../gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c | 13 ++--- 14 files changed, 72 insertions(+), 286 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index 795be958cf5e..f37482c76e20 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -835,64 +835,6 @@ static int amdgpu_cgs_is_virtualization_enabled(void *cgs_device) return amdgpu_sriov_vf(adev); } -static int amdgpu_cgs_query_system_info(struct cgs_device *cgs_device, - struct cgs_system_info *sys_info) -{ - CGS_FUNC_ADEV; - - if (NULL == sys_info) - return -ENODEV; - - if (sizeof(struct cgs_system_info) != sys_info->size) - return -ENODEV; - - switch (sys_info->info_id) { - case CGS_SYSTEM_INFO_ADAPTER_BDF_ID: - sys_info->value = adev->pdev->devfn | (adev->pdev->bus->number << 8); - break; - case CGS_SYSTEM_INFO_PCIE_GEN_INFO: - sys_info->value = adev->pm.pcie_gen_mask; - break; - case CGS_SYSTEM_INFO_PCIE_MLW: - sys_info->value = adev->pm.pcie_mlw_mask; - break; - case CGS_SYSTEM_INFO_PCIE_DEV: - sys_info->value = adev->pdev->device; - break; - case CGS_SYSTEM_INFO_PCIE_REV: - sys_info->value = adev->pdev->revision; - break; - case CGS_SYSTEM_INFO_CG_FLAGS: - sys_info->value = adev->cg_flags; - break; - case CGS_SYSTEM_INFO_PG_FLAGS: - sys_info->value = adev->pg_flags; - break; - case CGS_SYSTEM_INFO_GFX_CU_INFO: - sys_info->value = adev->gfx.cu_info.number; - break; - case CGS_SYSTEM_INFO_GFX_SE_INFO: - sys_info->value = adev->gfx.config.max_shader_engines; - break; - case CGS_SYSTEM_INFO_PCIE_SUB_SYS_ID: - sys_info->value = adev->pdev->subsystem_device; - break; - case CGS_SYSTEM_INFO_PCIE_SUB_SYS_VENDOR_ID: - sys_info->value = adev->pdev->subsystem_vendor; - break; - case CGS_SYSTEM_INFO_PCIE_BUS_DEVFN: - sys_info->value = adev->pdev->devfn; - break; - case CGS_SYSTEM_INFO_VRAM_WIDTH: - sys_info->value = adev->gmc.vram_width; - break; - default: - return -ENODEV; - } - - return 0; -} - static int amdgpu_cgs_get_active_displays_info(struct cgs_device *cgs_device, struct cgs_display_info *info) { @@ -996,7 +938,6 @@ static const struct cgs_ops amdgpu_cgs_ops = { .set_clockgating_state = amdgpu_cgs_set_clockgating_state, .get_active_displays_info = amdgpu_cgs_get_active_displays_info, .notify_dpm_enabled = amdgpu_cgs_notify_dpm_enabled, - .query_system_info = amdgpu_cgs_query_system_info, .is_virtualization_enabled = amdgpu_cgs_is_virtualization_enabled, .enter_safe_mode = amdgpu_cgs_enter_safe_mode, .lock_grbm_idx = amdgpu_cgs_lock_grbm_idx, diff --git a/drivers/gpu/drm/amd/include/cgs_common.h b/drivers/gpu/drm/amd/include/cgs_common.h index 851168b7b173..113ba6f07171 100644 --- a/drivers/gpu/drm/amd/include/cgs_common.h +++ b/drivers/gpu/drm/amd/include/cgs_common.h @@ -88,33 +88,6 @@ enum cgs_ucode_id { CGS_UCODE_ID_MAXIMUM, }; -enum cgs_system_info_id { - CGS_SYSTEM_INFO_ADAPTER_BDF_ID = 1, - CGS_SYSTEM_INFO_PCIE_GEN_INFO, - CGS_SYSTEM_INFO_PCIE_MLW, - CGS_SYSTEM_INFO_PCIE_DEV, - CGS_SYSTEM_INFO_PCIE_REV, - CGS_SYSTEM_INFO_CG_FLAGS, - CGS_SYSTEM_INFO_PG_FLAGS, - CGS_SYSTEM_INFO_GFX_CU_INFO, - CGS_SYSTEM_INFO_GFX_SE_INFO, - CGS_SYSTEM_INFO_PCIE_SUB_SYS_ID, - CGS_SYSTEM_INFO_PCIE_SUB_SYS_VENDOR_ID, - CGS_SYSTEM_INFO_PCIE_BUS_DEVFN, - CGS_SYSTEM_INFO_VRAM_WIDTH, - CGS_SYSTEM_INFO_ID_MAXIMUM, -}; - -struct cgs_system_info { - uint64_t size; - enum cgs_system_info_id info_id; - union { - void *ptr; - uint64_t value; - }; - uint64_t padding[13]; -}; - /* * enum cgs_resource_type - GPU resource type */ @@ -375,9 +348,6 @@ typedef int(*cgs_get_active_displays_info)( typedef int (*cgs_notify_dpm_enabled)(struct cgs_device *cgs_device, bool enabled); -typedef int (*cgs_query_system_info)(struct cgs_device *cgs_device, - struct cgs_system_info *sys_info); - typedef int (*cgs_is_virtualization_enabled_t)(void *cgs_device); typedef int (*cgs_enter_safe_mode)(struct cgs_device *cgs_device, bool en); @@ -416,8 +386,6 @@ struct cgs_ops { cgs_get_active_displays_info get_active_displays_info; /* notify dpm enabled */ cgs_notify_dpm_enabled notify_dpm_enabled; - /* get system info */ - cgs_query_system_info query_system_info; cgs_is_virtualization_enabled_t is_virtualization_enabled; cgs_enter_safe_mode enter_safe_mode; cgs_lock_grbm_idx lock_grbm_idx; @@ -483,8 +451,6 @@ struct cgs_device #define cgs_get_active_displays_info(dev, info) \ CGS_CALL(get_active_displays_info, dev, info) -#define cgs_query_system_info(dev, sys_info) \ - CGS_CALL(query_system_info, dev, sys_info) #define cgs_get_pci_resource(cgs_device, resource_type, size, offset, \ resource_base) \ CGS_CALL(get_pci_resource, cgs_device, resource_type, size, offset, \ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c index 2aa84c728e81..8c1f884ae555 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c @@ -173,8 +173,7 @@ static uint32_t cz_get_max_sclk_level(struct pp_hwmgr *hwmgr) static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) { struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); - struct cgs_system_info sys_info = {0}; - int result; + struct amdgpu_device *adev = hwmgr->adev; cz_hwmgr->gfx_ramp_step = 256*25/100; cz_hwmgr->gfx_ramp_delay = 1; /* by default, we delay 1us */ @@ -234,17 +233,14 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) PHM_PlatformCaps_UVDPowerGating); phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating); - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PG_FLAGS; - result = cgs_query_system_info(hwmgr->device, &sys_info); - if (!result) { - if (sys_info.value & AMD_PG_SUPPORT_UVD) - phm_cap_set(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_UVDPowerGating); - if (sys_info.value & AMD_PG_SUPPORT_VCE) - phm_cap_set(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_VCEPowerGating); - } + + if (adev->pg_flags & AMD_PG_SUPPORT_UVD) + phm_cap_set(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_UVDPowerGating); + if (adev->pg_flags & AMD_PG_SUPPORT_VCE) + phm_cap_set(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_VCEPowerGating); + return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index 28897882607e..2c7bb056e57d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -64,30 +64,16 @@ uint16_t convert_to_vddc(uint8_t vid) return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE); } -static int phm_get_pci_bus_devfn(struct pp_hwmgr *hwmgr, - struct cgs_system_info *sys_info) -{ - sys_info->size = sizeof(struct cgs_system_info); - sys_info->info_id = CGS_SYSTEM_INFO_PCIE_BUS_DEVFN; - - return cgs_query_system_info(hwmgr->device, sys_info); -} - static int phm_thermal_l2h_irq(void *private_data, unsigned src_id, const uint32_t *iv_entry) { struct pp_hwmgr *hwmgr = (struct pp_hwmgr *)private_data; - struct cgs_system_info sys_info = {0}; - int result; - - result = phm_get_pci_bus_devfn(hwmgr, &sys_info); - if (result) - return -EINVAL; + struct amdgpu_device *adev = hwmgr->adev; - pr_warn("GPU over temperature range detected on PCIe %lld:%lld.%lld!\n", - PCI_BUS_NUM(sys_info.value), - PCI_SLOT(sys_info.value), - PCI_FUNC(sys_info.value)); + pr_warn("GPU over temperature range detected on PCIe %d:%d.%d!\n", + PCI_BUS_NUM(adev->pdev->devfn), + PCI_SLOT(adev->pdev->devfn), + PCI_FUNC(adev->pdev->devfn)); return 0; } @@ -95,17 +81,12 @@ static int phm_thermal_h2l_irq(void *private_data, unsigned src_id, const uint32_t *iv_entry) { struct pp_hwmgr *hwmgr = (struct pp_hwmgr *)private_data; - struct cgs_system_info sys_info = {0}; - int result; - - result = phm_get_pci_bus_devfn(hwmgr, &sys_info); - if (result) - return -EINVAL; + struct amdgpu_device *adev = hwmgr->adev; - pr_warn("GPU under temperature range detected on PCIe %lld:%lld.%lld!\n", - PCI_BUS_NUM(sys_info.value), - PCI_SLOT(sys_info.value), - PCI_FUNC(sys_info.value)); + pr_warn("GPU under temperature range detected on PCIe %d:%d.%d!\n", + PCI_BUS_NUM(adev->pdev->devfn), + PCI_SLOT(adev->pdev->devfn), + PCI_FUNC(adev->pdev->devfn)); return 0; } @@ -113,17 +94,12 @@ static int phm_ctf_irq(void *private_data, unsigned src_id, const uint32_t *iv_entry) { struct pp_hwmgr *hwmgr = (struct pp_hwmgr *)private_data; - struct cgs_system_info sys_info = {0}; - int result; - - result = phm_get_pci_bus_devfn(hwmgr, &sys_info); - if (result) - return -EINVAL; + struct amdgpu_device *adev = hwmgr->adev; - pr_warn("GPU Critical Temperature Fault detected on PCIe %lld:%lld.%lld!\n", - PCI_BUS_NUM(sys_info.value), - PCI_SLOT(sys_info.value), - PCI_FUNC(sys_info.value)); + pr_warn("GPU Critical Temperature Fault detected on PCIe %d:%d.%d!\n", + PCI_BUS_NUM(adev->pdev->devfn), + PCI_SLOT(adev->pdev->devfn), + PCI_FUNC(adev->pdev->devfn)); return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c index 402aa9cb1f78..f4cbaee4e2ca 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c @@ -472,23 +472,12 @@ int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr, */ int smu7_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable) { - struct cgs_system_info sys_info = {0}; - uint32_t active_cus; - int result; - - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_GFX_CU_INFO; - - result = cgs_query_system_info(hwmgr->device, &sys_info); - - if (result) - return -EINVAL; - - active_cus = sys_info.value; + struct amdgpu_device *adev = hwmgr->adev; if (enable) return smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_GFX_CU_PG_ENABLE, active_cus); + PPSMC_MSG_GFX_CU_PG_ENABLE, + adev->gfx.cu_info.number); else return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GFX_CU_PG_DISABLE); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 928427d04ebd..f6e1196a6e55 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -1468,8 +1468,7 @@ static void smu7_init_dpm_defaults(struct pp_hwmgr *hwmgr) struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); struct phm_ppt_v1_information *table_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); - struct cgs_system_info sys_info = {0}; - int result; + struct amdgpu_device *adev = hwmgr->adev; data->dll_default_on = false; data->mclk_dpm0_activity_target = 0xa; @@ -1590,17 +1589,13 @@ static void smu7_init_dpm_defaults(struct pp_hwmgr *hwmgr) data->pcie_lane_power_saving.max = 0; data->pcie_lane_power_saving.min = 16; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PG_FLAGS; - result = cgs_query_system_info(hwmgr->device, &sys_info); - if (!result) { - if (sys_info.value & AMD_PG_SUPPORT_UVD) - phm_cap_set(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_UVDPowerGating); - if (sys_info.value & AMD_PG_SUPPORT_VCE) - phm_cap_set(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_VCEPowerGating); - } + + if (adev->pg_flags & AMD_PG_SUPPORT_UVD) + phm_cap_set(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_UVDPowerGating); + if (adev->pg_flags & AMD_PG_SUPPORT_VCE) + phm_cap_set(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_VCEPowerGating); } /** @@ -2035,7 +2030,7 @@ static int smu7_patch_voltage_workaround(struct pp_hwmgr *hwmgr) struct phm_ppt_v1_voltage_lookup_table *lookup_table; uint32_t i; uint32_t hw_revision, sub_vendor_id, sub_sys_id; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; if (table_info != NULL) { dep_mclk_table = table_info->vdd_dep_on_mclk; @@ -2043,19 +2038,9 @@ static int smu7_patch_voltage_workaround(struct pp_hwmgr *hwmgr) } else return 0; - sys_info.size = sizeof(struct cgs_system_info); - - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_REV; - cgs_query_system_info(hwmgr->device, &sys_info); - hw_revision = (uint32_t)sys_info.value; - - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_SUB_SYS_ID; - cgs_query_system_info(hwmgr->device, &sys_info); - sub_sys_id = (uint32_t)sys_info.value; - - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_SUB_SYS_VENDOR_ID; - cgs_query_system_info(hwmgr->device, &sys_info); - sub_vendor_id = (uint32_t)sys_info.value; + hw_revision = adev->pdev->revision; + sub_sys_id = adev->pdev->subsystem_device; + sub_vendor_id = adev->pdev->subsystem_vendor; if (hwmgr->chip_id == CHIP_POLARIS10 && hw_revision == 0xC7 && ((sub_sys_id == 0xb37 && sub_vendor_id == 0x1002) || @@ -2498,7 +2483,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) result = phm_initializa_dynamic_state_adjustment_rule_settings(hwmgr); if (0 == result) { - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; data->is_tlu_enabled = false; @@ -2507,22 +2492,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) hwmgr->platform_descriptor.hardwarePerformanceLevels = 2; hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO; - result = cgs_query_system_info(hwmgr->device, &sys_info); - if (result) - data->pcie_gen_cap = AMDGPU_DEFAULT_PCIE_GEN_MASK; - else - data->pcie_gen_cap = (uint32_t)sys_info.value; + data->pcie_gen_cap = adev->pm.pcie_gen_mask; if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) data->pcie_spc_cap = 20; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW; - result = cgs_query_system_info(hwmgr->device, &sys_info); - if (result) - data->pcie_lane_cap = AMDGPU_DEFAULT_PCIE_MLW_MASK; - else - data->pcie_lane_cap = (uint32_t)sys_info.value; + data->pcie_lane_cap = adev->pm.pcie_mlw_mask; hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */ /* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c index a93829dfd730..03bc7453f3b1 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c @@ -731,14 +731,9 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr) int result; uint32_t num_se = 0; uint32_t count, value, value2; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_GFX_SE_INFO; - result = cgs_query_system_info(hwmgr->device, &sys_info); - - if (result == 0) - num_se = sys_info.value; + num_se = adev->gfx.config.max_shader_engines; if (PP_CAP(PHM_PlatformCaps_SQRamping) || PP_CAP(PHM_PlatformCaps_DBRamping) || diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index a7c610a0e7e1..26a5bc070989 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -190,8 +190,7 @@ static int vega10_set_features_platform_caps(struct pp_hwmgr *hwmgr) (struct vega10_hwmgr *)(hwmgr->backend); struct phm_ppt_v2_information *table_info = (struct phm_ppt_v2_information *)hwmgr->pptable; - struct cgs_system_info sys_info = {0}; - int result; + struct amdgpu_device *adev = hwmgr->adev; phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep); @@ -206,15 +205,11 @@ static int vega10_set_features_platform_caps(struct pp_hwmgr *hwmgr) phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EnableSMU7ThermalManagement); - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PG_FLAGS; - result = cgs_query_system_info(hwmgr->device, &sys_info); - - if (!result && (sys_info.value & AMD_PG_SUPPORT_UVD)) + if (adev->pg_flags & AMD_PG_SUPPORT_UVD) phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDPowerGating); - if (!result && (sys_info.value & AMD_PG_SUPPORT_VCE)) + if (adev->pg_flags & AMD_PG_SUPPORT_VCE) phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating); @@ -750,7 +745,7 @@ static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) struct vega10_hwmgr *data; uint32_t config_telemetry = 0; struct pp_atomfwctrl_voltage_table vol_table; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t reg; data = kzalloc(sizeof(struct vega10_hwmgr), GFP_KERNEL); @@ -843,10 +838,7 @@ static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) hwmgr->platform_descriptor.clockStep.engineClock = 500; hwmgr->platform_descriptor.clockStep.memoryClock = 500; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_GFX_CU_INFO; - result = cgs_query_system_info(hwmgr->device, &sys_info); - data->total_active_cus = sys_info.value; + data->total_active_cus = adev->gfx.cu_info.number; /* Setup default Overdrive Fan control settings */ data->odn_fan_table.target_fan_speed = hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c index f5ed171d6940..b1f74c7f0943 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c @@ -933,13 +933,10 @@ static int vega10_enable_cac_driving_se_didt_config(struct pp_hwmgr *hwmgr) { int result; uint32_t num_se = 0, count, data; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t reg; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_GFX_SE_INFO; - if (cgs_query_system_info(hwmgr->device, &sys_info) == 0) - num_se = sys_info.value; + num_se = adev->gfx.config.max_shader_engines; cgs_enter_safe_mode(hwmgr->device, true); @@ -987,13 +984,10 @@ static int vega10_enable_psm_gc_didt_config(struct pp_hwmgr *hwmgr) { int result; uint32_t num_se = 0, count, data; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t reg; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_GFX_SE_INFO; - if (cgs_query_system_info(hwmgr->device, &sys_info) == 0) - num_se = sys_info.value; + num_se = adev->gfx.config.max_shader_engines; cgs_enter_safe_mode(hwmgr->device, true); @@ -1052,13 +1046,10 @@ static int vega10_enable_se_edc_config(struct pp_hwmgr *hwmgr) { int result; uint32_t num_se = 0, count, data; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t reg; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_GFX_SE_INFO; - if (cgs_query_system_info(hwmgr->device, &sys_info) == 0) - num_se = sys_info.value; + num_se = adev->gfx.config.max_shader_engines; cgs_enter_safe_mode(hwmgr->device, true); @@ -1103,13 +1094,10 @@ static int vega10_enable_psm_gc_edc_config(struct pp_hwmgr *hwmgr) int result; uint32_t num_se = 0; uint32_t count, data; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t reg; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_GFX_SE_INFO; - if (cgs_query_system_info(hwmgr->device, &sys_info) == 0) - num_se = sys_info.value; + num_se = adev->gfx.config.max_shader_engines; cgs_enter_safe_mode(hwmgr->device, true); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c index 6d44cf043618..c61d0744860d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c @@ -688,9 +688,9 @@ static int get_dcefclk_voltage_dependency_table( uint8_t num_entries; struct phm_ppt_v1_clock_voltage_dependency_table *clk_table; - struct cgs_system_info sys_info = {0}; uint32_t dev_id; uint32_t rev_id; + struct amdgpu_device *adev = hwmgr->adev; PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), "Invalid PowerPlay Table!", return -1); @@ -701,15 +701,8 @@ static int get_dcefclk_voltage_dependency_table( * This DPM level was added to support 3DPM monitors @ 4K120Hz * */ - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; - cgs_query_system_info(hwmgr->device, &sys_info); - dev_id = (uint32_t)sys_info.value; - - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_REV; - cgs_query_system_info(hwmgr->device, &sys_info); - rev_id = (uint32_t)sys_info.value; + dev_id = adev->pdev->device; + rev_id = adev->pdev->revision; if (dev_id == 0x6863 && rev_id == 0 && clk_dep_table->entries[clk_dep_table->ucNumEntries - 1].ulClk < 90000) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c index 6cdaed06da0b..76f700fe7491 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c @@ -236,13 +236,10 @@ static int ci_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) { struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t dev_id; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; - cgs_query_system_info(hwmgr->device, &sys_info); - dev_id = (uint32_t)sys_info.value; + dev_id = adev->pdev->device; switch (dev_id) { case 0x67BA: @@ -1309,7 +1306,7 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); struct smu7_dpm_table *dpm_table = &data->dpm_table; int result; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t dev_id; uint32_t level_array_address = smu_data->dpm_table_start + offsetof(SMU7_Discrete_DpmTable, MemoryLevel); @@ -1330,10 +1327,7 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; - cgs_query_system_info(hwmgr->device, &sys_info); - dev_id = (uint32_t)sys_info.value; + dev_id = adev->pdev->device; if ((dpm_table->mclk_table.count >= 2) && ((dev_id == 0x67B0) || (dev_id == 0x67B1))) { diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c index 11aeb150a97f..6255edf58721 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c @@ -281,13 +281,10 @@ static int iceland_smu_init(struct pp_hwmgr *hwmgr) static void iceland_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) { struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smu_backend); - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t dev_id; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; - cgs_query_system_info(hwmgr->device, &sys_info); - dev_id = (uint32_t)sys_info.value; + dev_id = adev->pdev->device; switch (dev_id) { case DEVICE_ID_VI_ICELAND_M_6900: diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c index 9e98c1dff5c4..a268b98abb8e 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c @@ -1623,19 +1623,12 @@ static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table = table_info->vdd_dep_on_sclk; uint32_t hw_revision, dev_id; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount; - sys_info.size = sizeof(struct cgs_system_info); - - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_REV; - cgs_query_system_info(hwmgr->device, &sys_info); - hw_revision = (uint32_t)sys_info.value; - - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; - cgs_query_system_info(hwmgr->device, &sys_info); - dev_id = (uint32_t)sys_info.value; + hw_revision = adev->pdev->revision; + dev_id = adev->pdev->device; /* Read SMU_Eefuse to read and calculate RO and determine * if the part is SS or FF. if RO >= 1660MHz, part is FF. diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c index 99ad0a25300c..68db5824de2d 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c @@ -349,7 +349,7 @@ int vega10_set_tools_address(struct pp_hwmgr *hwmgr) static int vega10_verify_smc_interface(struct pp_hwmgr *hwmgr) { uint32_t smc_driver_if_version; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t dev_id; uint32_t rev_id; @@ -359,15 +359,8 @@ static int vega10_verify_smc_interface(struct pp_hwmgr *hwmgr) return -EINVAL); vega10_read_arg_from_smc(hwmgr, &smc_driver_if_version); - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; - cgs_query_system_info(hwmgr->device, &sys_info); - dev_id = (uint32_t)sys_info.value; - - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_REV; - cgs_query_system_info(hwmgr->device, &sys_info); - rev_id = (uint32_t)sys_info.value; + dev_id = adev->pdev->device; + rev_id = adev->pdev->revision; if (!((dev_id == 0x687f) && ((rev_id == 0xc0) || -- cgit v1.2.3 From cc1bb66fbc26c29d360fab4b8d66fb7f278a2564 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Fri, 2 Mar 2018 10:52:25 +0800 Subject: drm/amd/pp: Export new smu message for PCC feature on Vega10 used to set PccThrottleLevel and PccResidencyThreshold Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/inc/smu9.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu9.h b/drivers/gpu/drm/amd/powerplay/inc/smu9.h index 550ed675027a..70ac4d477be2 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu9.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu9.h @@ -58,7 +58,7 @@ #define FEATURE_FAST_PPT_BIT 26 #define FEATURE_GFX_EDC_BIT 27 #define FEATURE_ACG_BIT 28 -#define FEATURE_SPARE_29_BIT 29 +#define FEATURE_PCC_LIMIT_CONTROL_BIT 29 #define FEATURE_SPARE_30_BIT 30 #define FEATURE_SPARE_31_BIT 31 @@ -94,7 +94,7 @@ #define FEATURE_FAST_PPT_MASK (1 << FAST_PPT_BIT ) #define FEATURE_GFX_EDC_MASK (1 << FEATURE_GFX_EDC_BIT ) #define FEATURE_ACG_MASK (1 << FEATURE_ACG_BIT ) -#define FFEATURE_SPARE_29_MASK (1 << FEATURE_SPARE_29_BIT ) +#define FEATURE_PCC_LIMIT_CONTROL_MASK (1 << FEATURE_PCC_LIMIT_CONTROL_BIT ) #define FFEATURE_SPARE_30_MASK (1 << FEATURE_SPARE_30_BIT ) #define FFEATURE_SPARE_31_MASK (1 << FEATURE_SPARE_31_BIT ) /* Workload types */ -- cgit v1.2.3 From 15826fbfef16a20799fa7c990df758b455bf7b62 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Fri, 2 Mar 2018 13:50:59 +0800 Subject: drm/amd/pp: Add PCC feature support on Vega This features controls vega peak current protection to allow for a wider compatibility with power supplies. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 34 ++++++++++++++++++++++ drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h | 1 + drivers/gpu/drm/amd/powerplay/inc/vega10_ppsmc.h | 1 + 3 files changed, 36 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 26a5bc070989..1596fd84627a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -299,6 +299,8 @@ static void vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr) { struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); int i; + uint32_t sub_vendor_id, hw_revision; + struct amdgpu_device *adev = hwmgr->adev; vega10_initialize_power_tune_defaults(hwmgr); @@ -363,6 +365,7 @@ static void vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr) FEATURE_FAN_CONTROL_BIT; data->smu_features[GNLD_ACG].smu_feature_id = FEATURE_ACG_BIT; data->smu_features[GNLD_DIDT].smu_feature_id = FEATURE_GFX_EDC_BIT; + data->smu_features[GNLD_PCC_LIMIT].smu_feature_id = FEATURE_PCC_LIMIT_CONTROL_BIT; if (!data->registry_data.prefetcher_dpm_key_disabled) data->smu_features[GNLD_DPM_PREFETCHER].supported = true; @@ -432,6 +435,15 @@ static void vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr) if (data->registry_data.didt_support) data->smu_features[GNLD_DIDT].supported = true; + hw_revision = adev->pdev->revision; + sub_vendor_id = adev->pdev->subsystem_vendor; + + if ((hwmgr->chip_id == 0x6862 || + hwmgr->chip_id == 0x6861 || + hwmgr->chip_id == 0x6868) && + (hw_revision == 0) && + (sub_vendor_id != 0x1002)) + data->smu_features[GNLD_PCC_LIMIT].supported = true; } #ifdef PPLIB_VEGA10_EVV_SUPPORT @@ -2844,12 +2856,32 @@ static int vega10_start_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap) return 0; } +static int vega10_enable_disable_PCC_limit_feature(struct pp_hwmgr *hwmgr, bool enable) +{ + struct vega10_hwmgr *data = + (struct vega10_hwmgr *)(hwmgr->backend); + + if (data->smu_features[GNLD_PCC_LIMIT].supported) { + if (enable == data->smu_features[GNLD_PCC_LIMIT].enabled) + pr_info("GNLD_PCC_LIMIT has been %s \n", enable ? "enabled" : "disabled"); + PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr, + enable, data->smu_features[GNLD_PCC_LIMIT].smu_feature_bitmap), + "Attempt to Enable PCC Limit feature Failed!", + return -EINVAL); + data->smu_features[GNLD_PCC_LIMIT].enabled = enable; + } + + return 0; +} + static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); int tmp_result, result = 0; + vega10_enable_disable_PCC_limit_feature(hwmgr, true); + if ((hwmgr->smu_version == 0x001c2c00) || (hwmgr->smu_version == 0x001c2d00)) smum_send_msg_to_smc_with_parameter(hwmgr, @@ -4703,6 +4735,8 @@ static int vega10_disable_dpm_tasks(struct pp_hwmgr *hwmgr) tmp_result = vega10_acg_disable(hwmgr); PP_ASSERT_WITH_CODE((tmp_result == 0), "Failed to disable acg!", result = tmp_result); + + vega10_enable_disable_PCC_limit_feature(hwmgr, false); return result; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h index ab3e8798bee8..de3219fff2db 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h @@ -66,6 +66,7 @@ enum { GNLD_FEATURE_FAST_PPT_BIT, GNLD_DIDT, GNLD_ACG, + GNLD_PCC_LIMIT, GNLD_FEATURES_MAX }; diff --git a/drivers/gpu/drm/amd/powerplay/inc/vega10_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/vega10_ppsmc.h index 247c97397a27..c3ed737ab951 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/vega10_ppsmc.h +++ b/drivers/gpu/drm/amd/powerplay/inc/vega10_ppsmc.h @@ -131,6 +131,7 @@ typedef uint16_t PPSMC_Result; #define PPSMC_MSG_RunAcgInOpenLoop 0x5E #define PPSMC_MSG_InitializeAcg 0x5F #define PPSMC_MSG_GetCurrPkgPwr 0x61 +#define PPSMC_MSG_SetPccThrottleLevel 0x67 #define PPSMC_MSG_UpdatePkgPwrPidAlpha 0x68 #define PPSMC_Message_Count 0x69 -- cgit v1.2.3 From 31bc45de132a2af9861622eb36764bf375c68cb4 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Wed, 24 Jan 2018 14:48:17 +0800 Subject: drm/amd/pp: Add common interface in smu for update dpm setting it is used for adjust part of dpm settigs per workloads to change the natural dpm behavior for better perf or perf/watt. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 1 + drivers/gpu/drm/amd/powerplay/inc/smumgr.h | 1 + drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c | 8 ++++++++ 3 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index bb50cc2b4af1..ae73956de533 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -239,6 +239,7 @@ struct pp_smumgr_func { int (*populate_requested_graphic_levels)(struct pp_hwmgr *hwmgr, struct amd_pp_profile *request); bool (*is_hw_avfs_present)(struct pp_hwmgr *hwmgr); + int (*update_dpm_settings)(struct pp_hwmgr *hwmgr, void *profile_setting); }; struct pp_hwmgr_func { diff --git a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h index b1b27b2128f6..e05a57e2eedc 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h @@ -134,5 +134,6 @@ extern int smum_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, extern bool smum_is_hw_avfs_present(struct pp_hwmgr *hwmgr); +extern int smum_update_dpm_settings(struct pp_hwmgr *hwmgr, void *profile_setting); #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c index 867388456530..1ce4959cba6e 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c @@ -253,3 +253,11 @@ bool smum_is_hw_avfs_present(struct pp_hwmgr *hwmgr) return false; } + +int smum_update_dpm_settings(struct pp_hwmgr *hwmgr, void *profile_setting) +{ + if (hwmgr->smumgr_funcs->update_dpm_settings) + return hwmgr->smumgr_funcs->update_dpm_settings(hwmgr, profile_setting); + + return -EINVAL; +} -- cgit v1.2.3 From 40cee3b9e50fd725e4fb3338814762cbf5013fbc Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Fri, 23 Feb 2018 16:32:55 +0800 Subject: drm/amd/pp: Add a helper to set field in u32 Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 16 ++++++++++++++++ drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 2 ++ 2 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index 2c7bb056e57d..aea107643859 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -64,6 +64,22 @@ uint16_t convert_to_vddc(uint8_t vid) return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE); } +uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size) +{ + u32 mask = 0; + u32 shift = 0; + + shift = (offset % 4) << 3; + if (size == sizeof(uint8_t)) + mask = 0xFF << shift; + else if (size == sizeof(uint16_t)) + mask = 0xFFFF << shift; + + original_data &= ~mask; + original_data |= (field << shift); + return original_data; +} + static int phm_thermal_l2h_irq(void *private_data, unsigned src_id, const uint32_t *iv_entry) { diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index ae73956de533..2dc2e2c20a3a 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -829,6 +829,8 @@ extern int rv_init_function_pointers(struct pp_hwmgr *hwmgr); extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint32_t sclk, uint16_t id, uint16_t *voltage); +extern uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size); + #define PHM_ENTIRE_REGISTER_MASK 0xFFFFFFFFU #define PHM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT -- cgit v1.2.3 From 2107f580909f96abe82df0ca164006b3454e983b Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Wed, 24 Jan 2018 17:15:37 +0800 Subject: drm/amd/pp: Implement update_dpm_settings on Polaris v2: lock dpm level when update pptable by SW method use SW method to update DPM settings by updating SRAM directly on Polaris. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- .../drm/amd/powerplay/smumgr/polaris10_smumgr.c | 97 ++++++++++++++++++++++ 1 file changed, 97 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c index 1f4e90c41456..757824875935 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c @@ -2575,6 +2575,102 @@ static int polaris10_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, array_size, SMC_RAM_END); } +static int polaris10_update_dpm_settings(struct pp_hwmgr *hwmgr, + void *profile_setting) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *) + (hwmgr->smu_backend); + struct profile_mode_setting *setting; + struct SMU74_Discrete_GraphicsLevel *levels = + smu_data->smc_state_table.GraphicsLevel; + uint32_t array = smu_data->smu7_data.dpm_table_start + + offsetof(SMU74_Discrete_DpmTable, GraphicsLevel); + + uint32_t mclk_array = smu_data->smu7_data.dpm_table_start + + offsetof(SMU74_Discrete_DpmTable, MemoryLevel); + struct SMU74_Discrete_MemoryLevel *mclk_levels = + smu_data->smc_state_table.MemoryLevel; + uint32_t i; + uint32_t offset, up_hyst_offset, down_hyst_offset, clk_activity_offset, tmp; + + if (profile_setting == NULL) + return -EINVAL; + + setting = (struct profile_mode_setting *)profile_setting; + + if (setting->bupdate_sclk) { + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { + if (levels[i].ActivityLevel != + cpu_to_be16(setting->sclk_activity)) { + levels[i].ActivityLevel = cpu_to_be16(setting->sclk_activity); + + clk_activity_offset = array + (sizeof(SMU74_Discrete_GraphicsLevel) * i) + + offsetof(SMU74_Discrete_GraphicsLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (levels[i].UpHyst != setting->sclk_up_hyst || + levels[i].DownHyst != setting->sclk_down_hyst) { + levels[i].UpHyst = setting->sclk_up_hyst; + levels[i].DownHyst = setting->sclk_down_hyst; + up_hyst_offset = array + (sizeof(SMU74_Discrete_GraphicsLevel) * i) + + offsetof(SMU74_Discrete_GraphicsLevel, UpHyst); + down_hyst_offset = array + (sizeof(SMU74_Discrete_GraphicsLevel) * i) + + offsetof(SMU74_Discrete_GraphicsLevel, DownHyst); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, levels[i].UpHyst, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, levels[i].DownHyst, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel); + } + + if (setting->bupdate_mclk) { + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.MemoryDpmLevelCount; i++) { + if (mclk_levels[i].ActivityLevel != + cpu_to_be16(setting->mclk_activity)) { + mclk_levels[i].ActivityLevel = cpu_to_be16(setting->mclk_activity); + + clk_activity_offset = mclk_array + (sizeof(SMU74_Discrete_MemoryLevel) * i) + + offsetof(SMU74_Discrete_MemoryLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, mclk_levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (mclk_levels[i].UpHyst != setting->mclk_up_hyst || + mclk_levels[i].DownHyst != setting->mclk_down_hyst) { + mclk_levels[i].UpHyst = setting->mclk_up_hyst; + mclk_levels[i].DownHyst = setting->mclk_down_hyst; + up_hyst_offset = mclk_array + (sizeof(SMU74_Discrete_MemoryLevel) * i) + + offsetof(SMU74_Discrete_MemoryLevel, UpHyst); + down_hyst_offset = mclk_array + (sizeof(SMU74_Discrete_MemoryLevel) * i) + + offsetof(SMU74_Discrete_MemoryLevel, DownHyst); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, mclk_levels[i].UpHyst, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, mclk_levels[i].DownHyst, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel); + } + return 0; +} + const struct pp_smumgr_func polaris10_smu_funcs = { .smu_init = polaris10_smu_init, .smu_fini = smu7_smu_fini, @@ -2599,4 +2695,5 @@ const struct pp_smumgr_func polaris10_smu_funcs = { .is_dpm_running = polaris10_is_dpm_running, .populate_requested_graphic_levels = polaris10_populate_requested_graphic_levels, .is_hw_avfs_present = polaris10_is_hw_avfs_present, + .update_dpm_settings = polaris10_update_dpm_settings, }; -- cgit v1.2.3 From dcd9f100071799416a5bc9d2bc4d66837810306b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 1 Mar 2018 11:03:27 -0500 Subject: drm/radeon: fix KV harvesting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always set the graphics values to the max for the asic type. E.g., some 1 RB chips are actually 1 RB chips, others are actually harvested 2 RB chips. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=99353 Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/cik.c | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index d3045a371a55..7c73bc7e2f85 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -3221,35 +3221,8 @@ static void cik_gpu_init(struct radeon_device *rdev) case CHIP_KAVERI: rdev->config.cik.max_shader_engines = 1; rdev->config.cik.max_tile_pipes = 4; - if ((rdev->pdev->device == 0x1304) || - (rdev->pdev->device == 0x1305) || - (rdev->pdev->device == 0x130C) || - (rdev->pdev->device == 0x130F) || - (rdev->pdev->device == 0x1310) || - (rdev->pdev->device == 0x1311) || - (rdev->pdev->device == 0x131C)) { - rdev->config.cik.max_cu_per_sh = 8; - rdev->config.cik.max_backends_per_se = 2; - } else if ((rdev->pdev->device == 0x1309) || - (rdev->pdev->device == 0x130A) || - (rdev->pdev->device == 0x130D) || - (rdev->pdev->device == 0x1313) || - (rdev->pdev->device == 0x131D)) { - rdev->config.cik.max_cu_per_sh = 6; - rdev->config.cik.max_backends_per_se = 2; - } else if ((rdev->pdev->device == 0x1306) || - (rdev->pdev->device == 0x1307) || - (rdev->pdev->device == 0x130B) || - (rdev->pdev->device == 0x130E) || - (rdev->pdev->device == 0x1315) || - (rdev->pdev->device == 0x1318) || - (rdev->pdev->device == 0x131B)) { - rdev->config.cik.max_cu_per_sh = 4; - rdev->config.cik.max_backends_per_se = 1; - } else { - rdev->config.cik.max_cu_per_sh = 3; - rdev->config.cik.max_backends_per_se = 1; - } + rdev->config.cik.max_cu_per_sh = 8; + rdev->config.cik.max_backends_per_se = 2; rdev->config.cik.max_sh_per_se = 1; rdev->config.cik.max_texture_channel_caches = 4; rdev->config.cik.max_gprs = 256; -- cgit v1.2.3 From a97fc4e4524cda15e0176ee8853038f6b3920a9a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 1 Mar 2018 11:05:31 -0500 Subject: drm/amdgpu: fix KV harvesting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always set the graphics values to the max for the asic type. E.g., some 1 RB chips are actually 1 RB chips, others are actually harvested 2 RB chips. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=99353 Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 972d421caada..e13d9d83767b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -4358,34 +4358,8 @@ static void gfx_v7_0_gpu_early_init(struct amdgpu_device *adev) case CHIP_KAVERI: adev->gfx.config.max_shader_engines = 1; adev->gfx.config.max_tile_pipes = 4; - if ((adev->pdev->device == 0x1304) || - (adev->pdev->device == 0x1305) || - (adev->pdev->device == 0x130C) || - (adev->pdev->device == 0x130F) || - (adev->pdev->device == 0x1310) || - (adev->pdev->device == 0x1311) || - (adev->pdev->device == 0x131C)) { - adev->gfx.config.max_cu_per_sh = 8; - adev->gfx.config.max_backends_per_se = 2; - } else if ((adev->pdev->device == 0x1309) || - (adev->pdev->device == 0x130A) || - (adev->pdev->device == 0x130D) || - (adev->pdev->device == 0x1313) || - (adev->pdev->device == 0x131D)) { - adev->gfx.config.max_cu_per_sh = 6; - adev->gfx.config.max_backends_per_se = 2; - } else if ((adev->pdev->device == 0x1306) || - (adev->pdev->device == 0x1307) || - (adev->pdev->device == 0x130B) || - (adev->pdev->device == 0x130E) || - (adev->pdev->device == 0x1315) || - (adev->pdev->device == 0x131B)) { - adev->gfx.config.max_cu_per_sh = 4; - adev->gfx.config.max_backends_per_se = 1; - } else { - adev->gfx.config.max_cu_per_sh = 3; - adev->gfx.config.max_backends_per_se = 1; - } + adev->gfx.config.max_cu_per_sh = 8; + adev->gfx.config.max_backends_per_se = 2; adev->gfx.config.max_sh_per_se = 1; adev->gfx.config.max_texture_channel_caches = 4; adev->gfx.config.max_gprs = 256; -- cgit v1.2.3 From a8d0fb2fa3e71d73d5cebcd0fe10e18d3b2264e9 Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Thu, 1 Mar 2018 09:39:57 -0500 Subject: drm/amd/amdgpu: Mask rptr as well in ring debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The read/write pointers on sdma4 devices increment beyond the ring size and should be masked. Tested on my Ryzen 2400G. Signed-off-by: Tom St Denis Reviewed-by: Alex Deucher Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 13044e66dcaf..561d3312af32 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -481,7 +481,7 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf, result = 0; if (*pos < 12) { - early[0] = amdgpu_ring_get_rptr(ring); + early[0] = amdgpu_ring_get_rptr(ring) & ring->buf_mask; early[1] = amdgpu_ring_get_wptr(ring) & ring->buf_mask; early[2] = ring->wptr & ring->buf_mask; for (i = *pos / 4; i < 3 && size; i++) { -- cgit v1.2.3 From 05656e5e4917a08296300dc0530aed1539202c25 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 26 Feb 2018 11:05:10 -0500 Subject: drm/amdgpu: used cached pcie gen info for SI (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than querying it every time we need it. Also fixes a crash in VM pass through if there is no root bridge because the cached value fetch already checks this properly. v2: fix includes Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=105244 Acked-by: Christian König Reviewed-by: Rex Zhu Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/si.c | 22 ++++++++-------- drivers/gpu/drm/amd/amdgpu/si_dpm.c | 50 ++++++++++--------------------------- 2 files changed, 23 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 543101d5a5ed..2095173aaabf 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -31,6 +31,7 @@ #include "amdgpu_uvd.h" #include "amdgpu_vce.h" #include "atom.h" +#include "amd_pcie.h" #include "amdgpu_powerplay.h" #include "sid.h" #include "si_ih.h" @@ -1461,8 +1462,8 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) { struct pci_dev *root = adev->pdev->bus->self; int bridge_pos, gpu_pos; - u32 speed_cntl, mask, current_data_rate; - int ret, i; + u32 speed_cntl, current_data_rate; + int i; u16 tmp16; if (pci_is_root_bus(adev->pdev->bus)) @@ -1474,23 +1475,20 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) if (adev->flags & AMD_IS_APU) return; - ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask); - if (ret != 0) - return; - - if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) + if (!(adev->pm.pcie_gen_mask & (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3))) return; speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >> LC_CURRENT_DATA_RATE_SHIFT; - if (mask & DRM_PCIE_SPEED_80) { + if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) { if (current_data_rate == 2) { DRM_INFO("PCIE gen 3 link speeds already enabled\n"); return; } DRM_INFO("enabling PCIE gen 3 link speeds, disable with amdgpu.pcie_gen2=0\n"); - } else if (mask & DRM_PCIE_SPEED_50) { + } else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) { if (current_data_rate == 1) { DRM_INFO("PCIE gen 2 link speeds already enabled\n"); return; @@ -1506,7 +1504,7 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) if (!gpu_pos) return; - if (mask & DRM_PCIE_SPEED_80) { + if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) { if (current_data_rate != 2) { u16 bridge_cfg, gpu_cfg; u16 bridge_cfg2, gpu_cfg2; @@ -1589,9 +1587,9 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); tmp16 &= ~0xf; - if (mask & DRM_PCIE_SPEED_80) + if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) tmp16 |= 3; - else if (mask & DRM_PCIE_SPEED_50) + else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) tmp16 |= 2; else tmp16 |= 1; diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index ce675a7f179a..22f0b7ff3ac9 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -26,6 +26,7 @@ #include "amdgpu_pm.h" #include "amdgpu_dpm.h" #include "amdgpu_atombios.h" +#include "amd_pcie.h" #include "sid.h" #include "r600_dpm.h" #include "si_dpm.h" @@ -3331,29 +3332,6 @@ static void btc_apply_voltage_delta_rules(struct amdgpu_device *adev, } } -static enum amdgpu_pcie_gen r600_get_pcie_gen_support(struct amdgpu_device *adev, - u32 sys_mask, - enum amdgpu_pcie_gen asic_gen, - enum amdgpu_pcie_gen default_gen) -{ - switch (asic_gen) { - case AMDGPU_PCIE_GEN1: - return AMDGPU_PCIE_GEN1; - case AMDGPU_PCIE_GEN2: - return AMDGPU_PCIE_GEN2; - case AMDGPU_PCIE_GEN3: - return AMDGPU_PCIE_GEN3; - default: - if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == AMDGPU_PCIE_GEN3)) - return AMDGPU_PCIE_GEN3; - else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == AMDGPU_PCIE_GEN2)) - return AMDGPU_PCIE_GEN2; - else - return AMDGPU_PCIE_GEN1; - } - return AMDGPU_PCIE_GEN1; -} - static void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b, u32 *p, u32 *u) { @@ -5028,10 +5006,11 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev, table->ACPIState.levels[0].vddc.index, &table->ACPIState.levels[0].std_vddc); } - table->ACPIState.levels[0].gen2PCIE = (u8)r600_get_pcie_gen_support(adev, - si_pi->sys_pcie_mask, - si_pi->boot_pcie_gen, - AMDGPU_PCIE_GEN1); + table->ACPIState.levels[0].gen2PCIE = + (u8)amdgpu_get_pcie_gen_support(adev, + si_pi->sys_pcie_mask, + si_pi->boot_pcie_gen, + AMDGPU_PCIE_GEN1); if (si_pi->vddc_phase_shed_control) si_populate_phase_shedding_value(adev, @@ -7168,10 +7147,10 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev, pl->vddc = le16_to_cpu(clock_info->si.usVDDC); pl->vddci = le16_to_cpu(clock_info->si.usVDDCI); pl->flags = le32_to_cpu(clock_info->si.ulFlags); - pl->pcie_gen = r600_get_pcie_gen_support(adev, - si_pi->sys_pcie_mask, - si_pi->boot_pcie_gen, - clock_info->si.ucPCIEGen); + pl->pcie_gen = amdgpu_get_pcie_gen_support(adev, + si_pi->sys_pcie_mask, + si_pi->boot_pcie_gen, + clock_info->si.ucPCIEGen); /* patch up vddc if necessary */ ret = si_get_leakage_voltage_from_leakage_index(adev, pl->vddc, @@ -7326,7 +7305,6 @@ static int si_dpm_init(struct amdgpu_device *adev) struct si_power_info *si_pi; struct atom_clock_dividers dividers; int ret; - u32 mask; si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL); if (si_pi == NULL) @@ -7336,11 +7314,9 @@ static int si_dpm_init(struct amdgpu_device *adev) eg_pi = &ni_pi->eg; pi = &eg_pi->rv7xx; - ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask); - if (ret) - si_pi->sys_pcie_mask = 0; - else - si_pi->sys_pcie_mask = mask; + si_pi->sys_pcie_mask = + (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK) >> + CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT; si_pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID; si_pi->boot_pcie_gen = si_get_current_pcie_speed(adev); -- cgit v1.2.3 From c36aaba6d0f1c84921c07f036202af55fb86b9c1 Mon Sep 17 00:00:00 2001 From: Roman Li Date: Fri, 9 Feb 2018 16:57:38 -0500 Subject: drm/amd/display: Fix active dongle hotplug Clean fake sink flag after detecting link on downstream port. Fixing display light-up after "hot-unplug&plug again" downstream of an active dongle. Signed-off-by: Roman Li Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') 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 862835dc054e..bf7c378818fc 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1037,6 +1037,10 @@ static void handle_hpd_rx_irq(void *param) !is_mst_root_connector) { /* Downstream Port status changed. */ if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) { + + if (aconnector->fake_enable) + aconnector->fake_enable = false; + amdgpu_dm_update_connector_after_detect(aconnector); -- cgit v1.2.3 From aea3fca005fb45f80869f2e8d56fd4e64c1d1fdb Mon Sep 17 00:00:00 2001 From: Pierre-Yves Kerbrat Date: Fri, 26 Jan 2018 11:24:12 +0100 Subject: e1000e: allocate ring descriptors with dma_zalloc_coherent Descriptor rings were not initialized at zero when allocated When area contained garbage data, it caused skb_over_panic in e1000_clean_rx_irq (if data had E1000_RXD_STAT_DD bit set) This patch makes use of dma_zalloc_coherent to make sure the ring is memset at 0 to prevent the area from containing garbage. Following is the signature of the panic: IODDR0@0.0: skbuff: skb_over_panic: text:80407b20 len:64010 put:64010 head:ab46d800 data:ab46d842 tail:0xab47d24c end:0xab46df40 dev:eth0 IODDR0@0.0: BUG: failure at net/core/skbuff.c:105/skb_panic()! IODDR0@0.0: Kernel panic - not syncing: BUG! IODDR0@0.0: IODDR0@0.0: Process swapper/0 (pid: 0, threadinfo=81728000, task=8173cc00 ,cpu: 0) IODDR0@0.0: SP = <815a1c0c> IODDR0@0.0: Stack: 00000001 IODDR0@0.0: b2d89800 815e33ac IODDR0@0.0: ea73c040 00000001 IODDR0@0.0: 60040003 0000fa0a IODDR0@0.0: 00000002 IODDR0@0.0: IODDR0@0.0: 804540c0 815a1c70 IODDR0@0.0: b2744000 602ac070 IODDR0@0.0: 815a1c44 b2d89800 IODDR0@0.0: 8173cc00 815a1c08 IODDR0@0.0: IODDR0@0.0: 00000006 IODDR0@0.0: 815a1b50 00000000 IODDR0@0.0: 80079434 00000001 IODDR0@0.0: ab46df40 b2744000 IODDR0@0.0: b2d89800 IODDR0@0.0: IODDR0@0.0: 0000fa0a 8045745c IODDR0@0.0: 815a1c88 0000fa0a IODDR0@0.0: 80407b20 b2789f80 IODDR0@0.0: 00000005 80407b20 IODDR0@0.0: IODDR0@0.0: IODDR0@0.0: Call Trace: IODDR0@0.0: [<804540bc>] skb_panic+0xa4/0xa8 IODDR0@0.0: [<80079430>] console_unlock+0x2f8/0x6d0 IODDR0@0.0: [<80457458>] skb_put+0xa0/0xc0 IODDR0@0.0: [<80407b1c>] e1000_clean_rx_irq+0x2dc/0x3e8 IODDR0@0.0: [<80407b1c>] e1000_clean_rx_irq+0x2dc/0x3e8 IODDR0@0.0: [<804079c8>] e1000_clean_rx_irq+0x188/0x3e8 IODDR0@0.0: [<80407b1c>] e1000_clean_rx_irq+0x2dc/0x3e8 IODDR0@0.0: [<80468b48>] __dev_kfree_skb_any+0x88/0xa8 IODDR0@0.0: [<804101ac>] e1000e_poll+0x94/0x288 IODDR0@0.0: [<8046e9d4>] net_rx_action+0x19c/0x4e8 IODDR0@0.0: ... IODDR0@0.0: Maximum depth to print reached. Use kstack= To specify a custom value (where 0 means to display the full backtrace) IODDR0@0.0: ---[ end Kernel panic - not syncing: BUG! Signed-off-by: Pierre-Yves Kerbrat Signed-off-by: Marius Gligor Tested-by: Aaron Brown Reviewed-by: Alexander Duyck Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 9fd4050a91ca..c0f23446bf26 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -2323,8 +2323,8 @@ static int e1000_alloc_ring_dma(struct e1000_adapter *adapter, { struct pci_dev *pdev = adapter->pdev; - ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma, - GFP_KERNEL); + ring->desc = dma_zalloc_coherent(&pdev->dev, ring->size, &ring->dma, + GFP_KERNEL); if (!ring->desc) return -ENOMEM; -- cgit v1.2.3 From cc40daf91bdddbba72a4a8cd0860640e06668309 Mon Sep 17 00:00:00 2001 From: Tang Junhui Date: Mon, 5 Mar 2018 13:41:54 -0800 Subject: bcache: fix crashes in duplicate cache device register Kernel crashed when register a duplicate cache device, the call trace is bellow: [ 417.643790] CPU: 1 PID: 16886 Comm: bcache-register Tainted: G W OE 4.15.5-amd64-preempt-sysrq-20171018 #2 [ 417.643861] Hardware name: LENOVO 20ERCTO1WW/20ERCTO1WW, BIOS N1DET41W (1.15 ) 12/31/2015 [ 417.643870] RIP: 0010:bdevname+0x13/0x1e [ 417.643876] RSP: 0018:ffffa3aa9138fd38 EFLAGS: 00010282 [ 417.643884] RAX: 0000000000000000 RBX: ffff8c8f2f2f8000 RCX: ffffd6701f8 c7edf [ 417.643890] RDX: ffffa3aa9138fd88 RSI: ffffa3aa9138fd88 RDI: 00000000000 00000 [ 417.643895] RBP: ffffa3aa9138fde0 R08: ffffa3aa9138fae8 R09: 00000000000 1850e [ 417.643901] R10: ffff8c8eed34b271 R11: ffff8c8eed34b250 R12: 00000000000 00000 [ 417.643906] R13: ffffd6701f78f940 R14: ffff8c8f38f80000 R15: ffff8c8ea7d 90000 [ 417.643913] FS: 00007fde7e66f500(0000) GS:ffff8c8f61440000(0000) knlGS: 0000000000000000 [ 417.643919] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 417.643925] CR2: 0000000000000314 CR3: 00000007e6fa0001 CR4: 00000000003 606e0 [ 417.643931] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 00000000000 00000 [ 417.643938] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 00000000000 00400 [ 417.643946] Call Trace: [ 417.643978] register_bcache+0x1117/0x1270 [bcache] [ 417.643994] ? slab_pre_alloc_hook+0x15/0x3c [ 417.644001] ? slab_post_alloc_hook.isra.44+0xa/0x1a [ 417.644013] ? kernfs_fop_write+0xf6/0x138 [ 417.644020] kernfs_fop_write+0xf6/0x138 [ 417.644031] __vfs_write+0x31/0xcc [ 417.644043] ? current_kernel_time64+0x10/0x36 [ 417.644115] ? __audit_syscall_entry+0xbf/0xe3 [ 417.644124] vfs_write+0xa5/0xe2 [ 417.644133] SyS_write+0x5c/0x9f [ 417.644144] do_syscall_64+0x72/0x81 [ 417.644161] entry_SYSCALL_64_after_hwframe+0x3d/0xa2 [ 417.644169] RIP: 0033:0x7fde7e1c1974 [ 417.644175] RSP: 002b:00007fff13009a38 EFLAGS: 00000246 ORIG_RAX: 0000000 000000001 [ 417.644183] RAX: ffffffffffffffda RBX: 0000000001658280 RCX: 00007fde7e1c 1974 [ 417.644188] RDX: 000000000000000a RSI: 0000000001658280 RDI: 000000000000 0001 [ 417.644193] RBP: 000000000000000a R08: 0000000000000003 R09: 000000000000 0077 [ 417.644198] R10: 000000000000089e R11: 0000000000000246 R12: 000000000000 0001 [ 417.644203] R13: 000000000000000a R14: 7fffffffffffffff R15: 000000000000 0000 [ 417.644213] Code: c7 c2 83 6f ee 98 be 20 00 00 00 48 89 df e8 6c 27 3b 0 0 48 89 d8 5b c3 0f 1f 44 00 00 48 8b 47 70 48 89 f2 48 8b bf 80 00 00 00 <8 b> b0 14 03 00 00 e9 73 ff ff ff 0f 1f 44 00 00 48 8b 47 40 39 [ 417.644302] RIP: bdevname+0x13/0x1e RSP: ffffa3aa9138fd38 [ 417.644306] CR2: 0000000000000314 When registering duplicate cache device in register_cache(), after failure on calling register_cache_set(), bch_cache_release() will be called, then bdev will be freed, so bdevname(bdev, name) caused kernel crash. Since bch_cache_release() will free bdev, so in this patch we make sure bdev being freed if register_cache() fail, and do not free bdev again in register_bcache() when register_cache() fail. Signed-off-by: Tang Junhui Reported-by: Marc MERLIN Tested-by: Michael Lyle Reviewed-by: Michael Lyle Cc: Signed-off-by: Jens Axboe --- drivers/md/bcache/super.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 4d1d8dfb2d2a..58d8998529de 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1204,7 +1204,7 @@ static void register_bdev(struct cache_sb *sb, struct page *sb_page, return; err: - pr_notice("error opening %s: %s", bdevname(bdev, name), err); + pr_notice("error %s: %s", bdevname(bdev, name), err); bcache_device_stop(&dc->disk); } @@ -1883,6 +1883,8 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, const char *err = NULL; /* must be set for any error case */ int ret = 0; + bdevname(bdev, name); + memcpy(&ca->sb, sb, sizeof(struct cache_sb)); ca->bdev = bdev; ca->bdev->bd_holder = ca; @@ -1891,11 +1893,12 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, bio_first_bvec_all(&ca->sb_bio)->bv_page = sb_page; get_page(sb_page); - if (blk_queue_discard(bdev_get_queue(ca->bdev))) + if (blk_queue_discard(bdev_get_queue(bdev))) ca->discard = CACHE_DISCARD(&ca->sb); ret = cache_alloc(ca); if (ret != 0) { + blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); if (ret == -ENOMEM) err = "cache_alloc(): -ENOMEM"; else @@ -1918,14 +1921,14 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, goto out; } - pr_info("registered cache device %s", bdevname(bdev, name)); + pr_info("registered cache device %s", name); out: kobject_put(&ca->kobj); err: if (err) - pr_notice("error opening %s: %s", bdevname(bdev, name), err); + pr_notice("error %s: %s", name, err); return ret; } @@ -2014,6 +2017,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, if (err) goto err_close; + err = "failed to register device"; if (SB_IS_BDEV(sb)) { struct cached_dev *dc = kzalloc(sizeof(*dc), GFP_KERNEL); if (!dc) @@ -2028,7 +2032,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, goto err_close; if (register_cache(sb, sb_page, bdev, ca) != 0) - goto err_close; + goto err; } out: if (sb_page) @@ -2041,7 +2045,7 @@ out: err_close: blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); err: - pr_info("error opening %s: %s", path, err); + pr_info("error %s: %s", path, err); ret = -EINVAL; goto out; } -- cgit v1.2.3 From 86755b7a96faed57f910f9e6b8061e019ac1ec08 Mon Sep 17 00:00:00 2001 From: Michael Lyle Date: Mon, 5 Mar 2018 13:41:55 -0800 Subject: bcache: don't attach backing with duplicate UUID This can happen e.g. during disk cloning. This is an incomplete fix: it does not catch duplicate UUIDs earlier when things are still unattached. It does not unregister the device. Further changes to cope better with this are planned but conflict with Coly's ongoing improvements to handling device errors. In the meantime, one can manually stop the device after this has happened. Attempts to attach a duplicate device result in: [ 136.372404] loop: module loaded [ 136.424461] bcache: register_bdev() registered backing device loop0 [ 136.424464] bcache: bch_cached_dev_attach() Tried to attach loop0 but duplicate UUID already attached My test procedure is: dd if=/dev/sdb1 of=imgfile bs=1024 count=262144 losetup -f imgfile Signed-off-by: Michael Lyle Reviewed-by: Tang Junhui Cc: Signed-off-by: Jens Axboe --- drivers/md/bcache/super.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 58d8998529de..f2273143b3cb 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -963,6 +963,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, uint32_t rtime = cpu_to_le32(get_seconds()); struct uuid_entry *u; char buf[BDEVNAME_SIZE]; + struct cached_dev *exist_dc, *t; bdevname(dc->bdev, buf); @@ -987,6 +988,16 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, return -EINVAL; } + /* Check whether already attached */ + list_for_each_entry_safe(exist_dc, t, &c->cached_devs, list) { + if (!memcmp(dc->sb.uuid, exist_dc->sb.uuid, 16)) { + pr_err("Tried to attach %s but duplicate UUID already attached", + buf); + + return -EINVAL; + } + } + u = uuid_find(c, dc->sb.uuid); if (u && -- cgit v1.2.3 From f616f2830c1ed79245cfeca900f7e8a3b3c08c06 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Thu, 1 Mar 2018 11:06:13 +0000 Subject: drm/i915/perf: fix perf stream opening lock We're seeing on CI that some contexts don't have the programmed OA period timer that directs the OA unit on how often to write reports. The issue is that we're not holding the drm lock from when we edit the context images down to when we set the exclusive_stream variable. This leaves a window for the deferred context allocation to call i915_oa_init_reg_state() that will not program the expected OA timer value, because we haven't set the exclusive_stream yet. v2: Drop need_lock from gen8_configure_all_contexts() (Matt) Signed-off-by: Lionel Landwerlin Reviewed-by: Matthew Auld Reviewed-by: Chris Wilson Fixes: 701f8231a2f ("drm/i915/perf: prune OA configs") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=102254 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103715 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103755 Link: https://patchwork.freedesktop.org/patch/msgid/20180301110613.1737-1-lionel.g.landwerlin@intel.com Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: intel-gfx@lists.freedesktop.org Cc: # v4.14+ (cherry picked from commit 41d3fdcd15d5ecf29cc73e8b79c2327ebb54b960) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_perf.c | 40 +++++++++++++--------------------------- 1 file changed, 13 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 0be50e43507d..f8fe5ffcdcff 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1303,9 +1303,8 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream) */ mutex_lock(&dev_priv->drm.struct_mutex); dev_priv->perf.oa.exclusive_stream = NULL; - mutex_unlock(&dev_priv->drm.struct_mutex); - dev_priv->perf.oa.ops.disable_metric_set(dev_priv); + mutex_unlock(&dev_priv->drm.struct_mutex); free_oa_buffer(dev_priv); @@ -1756,22 +1755,13 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr * Note: it's only the RCS/Render context that has any OA state. */ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, - const struct i915_oa_config *oa_config, - bool interruptible) + const struct i915_oa_config *oa_config) { struct i915_gem_context *ctx; int ret; unsigned int wait_flags = I915_WAIT_LOCKED; - if (interruptible) { - ret = i915_mutex_lock_interruptible(&dev_priv->drm); - if (ret) - return ret; - - wait_flags |= I915_WAIT_INTERRUPTIBLE; - } else { - mutex_lock(&dev_priv->drm.struct_mutex); - } + lockdep_assert_held(&dev_priv->drm.struct_mutex); /* Switch away from any user context. */ ret = gen8_switch_to_updated_kernel_context(dev_priv, oa_config); @@ -1819,8 +1809,6 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, } out: - mutex_unlock(&dev_priv->drm.struct_mutex); - return ret; } @@ -1863,7 +1851,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv, * to make sure all slices/subslices are ON before writing to NOA * registers. */ - ret = gen8_configure_all_contexts(dev_priv, oa_config, true); + ret = gen8_configure_all_contexts(dev_priv, oa_config); if (ret) return ret; @@ -1878,7 +1866,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv, static void gen8_disable_metric_set(struct drm_i915_private *dev_priv) { /* Reset all contexts' slices/subslices configurations. */ - gen8_configure_all_contexts(dev_priv, NULL, false); + gen8_configure_all_contexts(dev_priv, NULL); I915_WRITE(GDT_CHICKEN_BITS, (I915_READ(GDT_CHICKEN_BITS) & ~GT_NOA_ENABLE)); @@ -1888,7 +1876,7 @@ static void gen8_disable_metric_set(struct drm_i915_private *dev_priv) static void gen10_disable_metric_set(struct drm_i915_private *dev_priv) { /* Reset all contexts' slices/subslices configurations. */ - gen8_configure_all_contexts(dev_priv, NULL, false); + gen8_configure_all_contexts(dev_priv, NULL); /* Make sure we disable noa to save power. */ I915_WRITE(RPM_CONFIG1, @@ -2138,6 +2126,10 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, if (ret) goto err_oa_buf_alloc; + ret = i915_mutex_lock_interruptible(&dev_priv->drm); + if (ret) + goto err_lock; + ret = dev_priv->perf.oa.ops.enable_metric_set(dev_priv, stream->oa_config); if (ret) @@ -2145,23 +2137,17 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, stream->ops = &i915_oa_stream_ops; - /* Lock device for exclusive_stream access late because - * enable_metric_set() might lock as well on gen8+. - */ - ret = i915_mutex_lock_interruptible(&dev_priv->drm); - if (ret) - goto err_lock; - dev_priv->perf.oa.exclusive_stream = stream; mutex_unlock(&dev_priv->drm.struct_mutex); return 0; -err_lock: +err_enable: dev_priv->perf.oa.ops.disable_metric_set(dev_priv); + mutex_unlock(&dev_priv->drm.struct_mutex); -err_enable: +err_lock: free_oa_buffer(dev_priv); err_oa_buf_alloc: -- cgit v1.2.3 From 88d3dfb6a69042381161290c7ce19e1f53fc2a66 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 2 Mar 2018 11:33:24 +0000 Subject: drm/i915: Suspend submission tasklets around wedging After staring hard at sequences like [ 28.199013] systemd-1 2..s. 26062228us : execlists_submission_tasklet: rcs0 cs-irq head=0 [0?], tail=1 [1?] [ 28.199095] systemd-1 2..s. 26062229us : execlists_submission_tasklet: rcs0 csb[1]: status=0x00000018:0x00000000, active=0x1 [ 28.199177] systemd-1 2..s. 26062230us : execlists_submission_tasklet: rcs0 out[0]: ctx=0.1, seqno=3, prio=-1024 [ 28.199258] systemd-1 2..s. 26062231us : execlists_submission_tasklet: rcs0 completed ctx=0 [ 28.199340] gem_eio-829 1..s1 26066853us : execlists_submission_tasklet: rcs0 in[0]: ctx=1.1, seqno=1, prio=0 [ 28.199421] -0 2..s. 26066863us : execlists_submission_tasklet: rcs0 cs-irq head=1 [1?], tail=2 [2?] [ 28.199503] -0 2..s. 26066865us : execlists_submission_tasklet: rcs0 csb[2]: status=0x00000001:0x00000000, active=0x1 [ 28.199585] gem_eio-829 1..s1 26067077us : execlists_submission_tasklet: rcs0 in[1]: ctx=3.1, seqno=2, prio=0 [ 28.199667] gem_eio-829 1..s1 26067078us : execlists_submission_tasklet: rcs0 in[0]: ctx=1.2, seqno=1, prio=0 [ 28.199749] -0 2..s. 26067084us : execlists_submission_tasklet: rcs0 cs-irq head=2 [2?], tail=3 [3?] [ 28.199830] -0 2..s. 26067085us : execlists_submission_tasklet: rcs0 csb[3]: status=0x00008002:0x00000001, active=0x1 [ 28.199912] -0 2..s. 26067086us : execlists_submission_tasklet: rcs0 out[0]: ctx=1.2, seqno=1, prio=0 [ 28.199994] gem_eio-829 2..s. 28246084us : execlists_submission_tasklet: rcs0 cs-irq head=3 [3?], tail=4 [4?] [ 28.200096] gem_eio-829 2..s. 28246088us : execlists_submission_tasklet: rcs0 csb[4]: status=0x00000014:0x00000001, active=0x5 [ 28.200178] gem_eio-829 2..s. 28246089us : execlists_submission_tasklet: rcs0 out[0]: ctx=0.0, seqno=0, prio=0 [ 28.200260] gem_eio-829 2..s. 28246127us : execlists_submission_tasklet: execlists_submission_tasklet:886 GEM_BUG_ON(buf[2 * head + 1] != port->context_id) the conclusion is that the only place where the ports are reset to zero, is from engine->cancel_requests called during i915_gem_set_wedged(). The race is horrible as it results from calling set-wedged on active HW (the GPU reset failed) and as such we need to be careful as the HW state changes beneath us. Fortunately, it's the same scary conditions as affect normal reset, so we can reuse the same machinery to disable state tracking as we clobber it. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104945 Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Michel Thierry Fixes: af7a8ffad9c5 ("drm/i915: Use rcu instead of stop_machine in set_wedged") Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180302113324.23189-2-chris@chris-wilson.co.uk (cherry picked from commit 963ddd63c314e9b5d9cd999873d473a93aed5380) Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_gem.c | 6 +++++- drivers/gpu/drm/i915/intel_lrc.c | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index dd89abd2263d..66ee9d888d16 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3205,8 +3205,10 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) * rolling the global seqno forward (since this would complete requests * for which we haven't set the fence error to EIO yet). */ - for_each_engine(engine, i915, id) + for_each_engine(engine, i915, id) { + i915_gem_reset_prepare_engine(engine); engine->submit_request = nop_submit_request; + } /* * Make sure no one is running the old callback before we proceed with @@ -3244,6 +3246,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) intel_engine_init_global_seqno(engine, intel_engine_last_submit(engine)); spin_unlock_irqrestore(&engine->timeline->lock, flags); + + i915_gem_reset_finish_engine(engine); } set_bit(I915_WEDGED, &i915->gpu_error.flags); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7ece2f061b9e..e0fca035ff78 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -719,6 +719,8 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) struct rb_node *rb; unsigned long flags; + GEM_TRACE("%s\n", engine->name); + spin_lock_irqsave(&engine->timeline->lock, flags); /* Cancel the requests on the HW and clear the ELSP tracker. */ @@ -765,6 +767,9 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) */ clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); + /* Mark all CS interrupts as complete */ + execlists->active = 0; + spin_unlock_irqrestore(&engine->timeline->lock, flags); } -- cgit v1.2.3 From 4ffb8deeed58b75dd1a23580845233b6ce0dca6c Mon Sep 17 00:00:00 2001 From: Joe Moriarty Date: Tue, 20 Feb 2018 14:11:56 -0500 Subject: drm: NULL pointer dereference [null-pointer-deref] (CWE 476) problem The Parfait (version 2.1.0) static code analysis tool found the following NULL pointer derefernce problem. - drivers/gpu/drm/drm_vblank.c Null pointer checks were added to return values from calls to drm_crtc_from_index(). There is a possibility, however minute, that crtc->index may not be found when trying to find the struct crtc from it's assigned index given in drm_crtc_init_with_planes(). 3 return checks for NULL where added with a call to WARN_ON(!crtc). Signed-off-by: Joe Moriarty Reviewed-by: Steven Sistare Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180220191157.100960-2-joe.moriarty@oracle.com --- drivers/gpu/drm/drm_vblank.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 32d9bcf5be7f..03b431eb47ae 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -120,6 +120,9 @@ static u32 __get_vblank_counter(struct drm_device *dev, unsigned int pipe) if (drm_core_check_feature(dev, DRIVER_MODESET)) { struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); + if (WARN_ON(!crtc)) + return 0; + if (crtc->funcs->get_vblank_counter) return crtc->funcs->get_vblank_counter(crtc); } @@ -318,6 +321,9 @@ static void __disable_vblank(struct drm_device *dev, unsigned int pipe) if (drm_core_check_feature(dev, DRIVER_MODESET)) { struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); + if (WARN_ON(!crtc)) + return; + if (crtc->funcs->disable_vblank) { crtc->funcs->disable_vblank(crtc); return; @@ -918,6 +924,9 @@ static int __enable_vblank(struct drm_device *dev, unsigned int pipe) if (drm_core_check_feature(dev, DRIVER_MODESET)) { struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); + if (WARN_ON(!crtc)) + return 0; + if (crtc->funcs->enable_vblank) return crtc->funcs->enable_vblank(crtc); } -- cgit v1.2.3 From 3bd07ccd27622d598fd9d87f3032dd457ad62083 Mon Sep 17 00:00:00 2001 From: Joe Moriarty Date: Tue, 20 Feb 2018 14:11:57 -0500 Subject: drm: NULL pointer dereference [null-pointer-deref] (CWE 476) problem The Parfait (version 2.1.0) static code analysis tool found the following NULL pointer dereference problem. - drivers/gpu/drm/drm_drv.c Any calls to drm_minor_get_slot() could result in the return of a NULL pointer when an invalid DRM device type is encountered. The return of NULL was removed with BUG() from drm_minor_get_slot(). Signed-off-by: Joe Moriarty Reviewed-by: Steven Sistare Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180220191157.100960-3-joe.moriarty@oracle.com --- drivers/gpu/drm/drm_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 9acc1e157813..a1b9338736e3 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -99,7 +99,7 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev, case DRM_MINOR_CONTROL: return &dev->control; default: - return NULL; + BUG(); } } -- cgit v1.2.3 From 2efa83920c7f4fb214517437c730afdaa4e28391 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Thu, 22 Feb 2018 21:22:50 +0200 Subject: drm: of: simplify component probe code Use positive logic for better readability. This also eliminates one of_node_put() call, making the code shorter. Signed-off-by: Baruch Siach Reviewed-by: Philipp Zabel Tested-by: Philipp Zabel Signed-off-by: Archit Taneja Link: https://patchwork.freedesktop.org/patch/msgid/61c56895d44117d80e7d82f04e729e29c60fadbd.1519327370.git.baruch@tkos.co.il --- drivers/gpu/drm/drm_of.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 4c191c050e7d..1fe122461298 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -122,12 +122,10 @@ int drm_of_component_probe(struct device *dev, if (!port) break; - if (!of_device_is_available(port->parent)) { - of_node_put(port); - continue; - } + if (of_device_is_available(port->parent)) + drm_of_component_match_add(dev, &match, compare_of, + port); - drm_of_component_match_add(dev, &match, compare_of, port); of_node_put(port); } -- cgit v1.2.3 From 9c305eb442f3b371fc722ade827bbf673514123e Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 23 Feb 2018 12:44:37 +0100 Subject: drm: bridge: dw-hdmi: Fix overflow workaround for Amlogic Meson GX SoCs The Amlogic Meson GX SoCs, embedded the v2.01a controller, has been also identified needing this workaround. This patch adds the corresponding version to enable a single iteration for this specific version. Fixes: be41fc55f1aa ("drm: bridge: dw-hdmi: Handle overflow workaround based on device version") Acked-by: Archit Taneja [narmstrong: s/identifies/identified and rebased against Jernej's change] Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/1519386277-25902-1-git-send-email-narmstrong@baylibre.com --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index f9802399cc0d..53ebbe2904b6 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1654,6 +1654,8 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) * (v1.31a) and multiple Allwinner SoCs (v1.32a) have been identified * as needing the workaround, with 4 iterations for v1.30a and 1 * iteration for others. + * The Amlogic Meson GX SoCs (v2.01a) have been identified as needing + * the workaround with a single iteration. */ switch (hdmi->version) { @@ -1662,6 +1664,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) break; case 0x131a: case 0x132a: + case 0x201a: count = 1; break; default: -- cgit v1.2.3 From a42ae5905140c324362fe5036ae1dbb16e4d359c Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Thu, 15 Feb 2018 15:13:42 -0500 Subject: staging: comedi: fix comedi_nsamples_left. A rounding error was causing comedi_nsamples_left to return the wrong value when nsamples was not a multiple of the scan length. Cc: # v4.4+ Signed-off-by: Frank Mori Hess Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index e618a87521a3..9d733471ca2e 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -475,8 +475,7 @@ unsigned int comedi_nsamples_left(struct comedi_subdevice *s, struct comedi_cmd *cmd = &async->cmd; if (cmd->stop_src == TRIG_COUNT) { - unsigned int nscans = nsamples / cmd->scan_end_arg; - unsigned int scans_left = __comedi_nscans_left(s, nscans); + unsigned int scans_left = __comedi_nscans_left(s, cmd->stop_arg); unsigned int scan_pos = comedi_bytes_to_samples(s, async->scan_progress); unsigned long long samples_left = 0; -- cgit v1.2.3 From 740a5759bf222332fbb5eda42f89aa25ba38f9b2 Mon Sep 17 00:00:00 2001 From: Yisheng Xie Date: Wed, 28 Feb 2018 14:59:22 +0800 Subject: staging: android: ashmem: Fix possible deadlock in ashmem_ioctl ashmem_mutex may create a chain of dependencies like: CPU0 CPU1 mmap syscall ioctl syscall -> mmap_sem (acquired) -> ashmem_ioctl -> ashmem_mmap -> ashmem_mutex (acquired) -> ashmem_mutex (try to acquire) -> copy_from_user -> mmap_sem (try to acquire) There is a lock odering problem between mmap_sem and ashmem_mutex causing a lockdep splat[1] during a syzcaller test. This patch fixes the problem by move copy_from_user out of ashmem_mutex. [1] https://www.spinics.net/lists/kernel/msg2733200.html Fixes: ce8a3a9e76d0 (staging: android: ashmem: Fix a race condition in pin ioctls) Reported-by: syzbot+d7a918a7a8e1c952bc36@syzkaller.appspotmail.com Signed-off-by: Yisheng Xie Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ashmem.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index d5450365769c..86580b6df33d 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -701,16 +701,14 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd, size_t pgstart, pgend; int ret = -EINVAL; + if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) + return -EFAULT; + mutex_lock(&ashmem_mutex); if (unlikely(!asma->file)) goto out_unlock; - if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) { - ret = -EFAULT; - goto out_unlock; - } - /* per custom, you can pass zero for len to mean "everything onward" */ if (!pin.len) pin.len = PAGE_ALIGN(asma->size) - pin.offset; -- cgit v1.2.3 From e742a17cd360fbd64425a3c861c59062ec837f23 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 21 Feb 2018 13:57:01 +0100 Subject: drm/sun4i: tcon: Reduce the scope of the LVDS error a bit The current logic to deal with old DT missing the LVDS properties doesn't take into account whether the LVDS output is supported in the first place, resulting in spurious error messages on SoCs where it doesn't even matter. Introduce a new TCON flag to list if LVDS is supported at all to prevent this from happening. Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180221125703.4595-1-maxime.ripard@bootlin.com --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 86 ++++++++++++++++++++------------------ drivers/gpu/drm/sun4i/sun4i_tcon.h | 1 + 2 files changed, 46 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index ade197b1a9ac..2de586b7c98b 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -875,52 +875,56 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, return ret; } - /* - * This can only be made optional since we've had DT nodes - * without the LVDS reset properties. - * - * If the property is missing, just disable LVDS, and print a - * warning. - */ - tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds"); - if (IS_ERR(tcon->lvds_rst)) { - dev_err(dev, "Couldn't get our reset line\n"); - return PTR_ERR(tcon->lvds_rst); - } else if (tcon->lvds_rst) { - has_lvds_rst = true; - reset_control_reset(tcon->lvds_rst); - } else { - has_lvds_rst = false; - } + if (tcon->quirks->supports_lvds) { + /* + * This can only be made optional since we've had DT + * nodes without the LVDS reset properties. + * + * If the property is missing, just disable LVDS, and + * print a warning. + */ + tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds"); + if (IS_ERR(tcon->lvds_rst)) { + dev_err(dev, "Couldn't get our reset line\n"); + return PTR_ERR(tcon->lvds_rst); + } else if (tcon->lvds_rst) { + has_lvds_rst = true; + reset_control_reset(tcon->lvds_rst); + } else { + has_lvds_rst = false; + } - /* - * This can only be made optional since we've had DT nodes - * without the LVDS reset properties. - * - * If the property is missing, just disable LVDS, and print a - * warning. - */ - if (tcon->quirks->has_lvds_alt) { - tcon->lvds_pll = devm_clk_get(dev, "lvds-alt"); - if (IS_ERR(tcon->lvds_pll)) { - if (PTR_ERR(tcon->lvds_pll) == -ENOENT) { - has_lvds_alt = false; + /* + * This can only be made optional since we've had DT + * nodes without the LVDS reset properties. + * + * If the property is missing, just disable LVDS, and + * print a warning. + */ + if (tcon->quirks->has_lvds_alt) { + tcon->lvds_pll = devm_clk_get(dev, "lvds-alt"); + if (IS_ERR(tcon->lvds_pll)) { + if (PTR_ERR(tcon->lvds_pll) == -ENOENT) { + has_lvds_alt = false; + } else { + dev_err(dev, "Couldn't get the LVDS PLL\n"); + return PTR_ERR(tcon->lvds_pll); + } } else { - dev_err(dev, "Couldn't get the LVDS PLL\n"); - return PTR_ERR(tcon->lvds_pll); + has_lvds_alt = true; } - } else { - has_lvds_alt = true; } - } - if (!has_lvds_rst || (tcon->quirks->has_lvds_alt && !has_lvds_alt)) { - dev_warn(dev, - "Missing LVDS properties, Please upgrade your DT\n"); - dev_warn(dev, "LVDS output disabled\n"); - can_lvds = false; + if (!has_lvds_rst || + (tcon->quirks->has_lvds_alt && !has_lvds_alt)) { + dev_warn(dev, "Missing LVDS properties, Please upgrade your DT\n"); + dev_warn(dev, "LVDS output disabled\n"); + can_lvds = false; + } else { + can_lvds = true; + } } else { - can_lvds = true; + can_lvds = false; } ret = sun4i_tcon_init_clocks(dev, tcon); @@ -1139,7 +1143,7 @@ static const struct sun4i_tcon_quirks sun8i_a33_quirks = { }; static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = { - /* nothing is supported */ + .supports_lvds = true, }; static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index b761c7b823c5..278700c7bf9f 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -175,6 +175,7 @@ struct sun4i_tcon_quirks { bool has_channel_1; /* a33 does not have channel 1 */ bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */ bool needs_de_be_mux; /* sun6i needs mux to select backend */ + bool supports_lvds; /* Does the TCON support an LVDS output? */ /* callback to handle tcon muxing options */ int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *); -- cgit v1.2.3 From 5af894bd20fa16970378cae8ff55917294e0d9dd Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 21 Feb 2018 13:57:02 +0100 Subject: drm/sun4i: rgb: Fix potential division by zero In the case where mode_valid callback of our RGB connector was called before mode_set was being called, the range of dividers would not be set, resulting in a division by zero later on in the clk_round_rate logic. Set the range of dividers before calling clk_round_rate to fix this. Reviewed-by: Chen-Yu Tsai Tested-by: Giulio Benetti Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180221125703.4595-2-maxime.ripard@bootlin.com --- drivers/gpu/drm/sun4i/sun4i_rgb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index 832f8f9bc47f..b8da5a50a61d 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c @@ -92,6 +92,8 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector, DRM_DEBUG_DRIVER("Vertical parameters OK\n"); + tcon->dclk_min_div = 6; + tcon->dclk_max_div = 127; rounded_rate = clk_round_rate(tcon->dclk, rate); if (rounded_rate < rate) return MODE_CLOCK_LOW; -- cgit v1.2.3 From fd00c4ee76f0b509ce79ffbc1f5a682fbdd84efd Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 21 Feb 2018 13:57:03 +0100 Subject: drm/sun4i: crtc: Call drm_crtc_vblank_on / drm_crtc_vblank_off Make sure that the CRTC code will call the enable/disable_vblank hooks. Otherwise, since the refcounting will be off, we might end up in a situation where the vblank management functions are called while the CRTC is off. Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180221125703.4595-3-maxime.ripard@bootlin.com --- drivers/gpu/drm/sun4i/sun4i_crtc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c index 5decae0069d0..78cbc3145e44 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c @@ -93,6 +93,8 @@ static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, DRM_DEBUG_DRIVER("Disabling the CRTC\n"); + drm_crtc_vblank_off(crtc); + sun4i_tcon_set_status(scrtc->tcon, encoder, false); if (crtc->state->event && !crtc->state->active) { @@ -113,6 +115,8 @@ static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc, DRM_DEBUG_DRIVER("Enabling the CRTC\n"); sun4i_tcon_set_status(scrtc->tcon, encoder, true); + + drm_crtc_vblank_on(crtc); } static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc) -- cgit v1.2.3 From 8e5e83ad8250043c8d5cc8f2bf672e64c43f948a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 2 Mar 2018 15:25:42 +0200 Subject: drm: Don't create properties without names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Creating a property that doesn't have a name makes no sense to me. Don't allow it. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180302132544.12491-1-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_property.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index bae50e6b819d..fe8627fb7ae6 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -99,10 +99,8 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, property->num_values = num_values; INIT_LIST_HEAD(&property->enum_list); - if (name) { - strncpy(property->name, name, DRM_PROP_NAME_LEN); - property->name[DRM_PROP_NAME_LEN-1] = '\0'; - } + strncpy(property->name, name, DRM_PROP_NAME_LEN); + property->name[DRM_PROP_NAME_LEN-1] = '\0'; list_add_tail(&property->head, &dev->mode_config.property_list); -- cgit v1.2.3 From 5ebbb5b4d424e030b7d240ce71767c4145c7f26e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 2 Mar 2018 16:03:00 +0200 Subject: drm: Check property/enum name length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reject requests to add properties/enums with an overly long name. Previously we would have just silently truncated the string and exposed it userspace. v2: drm_property_create() returns a pointer Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180302140300.31110-1-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_property.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index fe8627fb7ae6..c37ac41125b5 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -78,6 +78,9 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, struct drm_property *property = NULL; int ret; + if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN)) + return NULL; + property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); if (!property) return NULL; @@ -372,6 +375,9 @@ int drm_property_add_enum(struct drm_property *property, int index, { struct drm_property_enum *prop_enum; + if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN)) + return -EINVAL; + if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) return -EINVAL; -- cgit v1.2.3 From cd526676de1ece03a8ea7cea726cf879a2dba2b8 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 2 Mar 2018 15:08:36 -0800 Subject: net: dsa: b53: Use strlcpy() for ethtool::get_strings Our statistics strings are allocated at initialization without being bound to a specific size, yet, we would copy ETH_GSTRING_LEN bytes using memcpy() which would create out of bounds accesses, this was flagged by KASAN. Replace this with strlcpy() to make sure we are bound the source buffer size and we also always NUL-terminate strings. Fixes: 967dd82ffc52 ("net: dsa: b53: Add support for Broadcom RoboSwitch") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index db830a1141d9..63e02a54d537 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -814,8 +814,8 @@ void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data) unsigned int i; for (i = 0; i < mib_size; i++) - memcpy(data + i * ETH_GSTRING_LEN, - mibs[i].name, ETH_GSTRING_LEN); + strlcpy(data + i * ETH_GSTRING_LEN, + mibs[i].name, ETH_GSTRING_LEN); } EXPORT_SYMBOL(b53_get_strings); -- cgit v1.2.3 From 98409b2bbca36b578be8e66758e6acb96e4c91da Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 2 Mar 2018 15:08:37 -0800 Subject: net: phy: marvell: Use strlcpy() for ethtool::get_strings Our statistics strings are allocated at initialization without being bound to a specific size, yet, we would copy ETH_GSTRING_LEN bytes using memcpy() which would create out of bounds accesses, this was flagged by KASAN. Replace this with strlcpy() to make sure we are bound the source buffer size and we also always NUL-terminate strings. Fixes: d2fa47d9dd5c ("phy: marvell: Add ethtool statistics counters") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 22d9bc9c33a4..0e0978d8a0eb 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1452,8 +1452,8 @@ static void marvell_get_strings(struct phy_device *phydev, u8 *data) int i; for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) { - memcpy(data + i * ETH_GSTRING_LEN, - marvell_hw_stats[i].string, ETH_GSTRING_LEN); + strlcpy(data + i * ETH_GSTRING_LEN, + marvell_hw_stats[i].string, ETH_GSTRING_LEN); } } -- cgit v1.2.3 From 55f53567afe5f0cd2fd9e006b174c08c31c466f8 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 2 Mar 2018 15:08:38 -0800 Subject: net: phy: micrel: Use strlcpy() for ethtool::get_strings Our statistics strings are allocated at initialization without being bound to a specific size, yet, we would copy ETH_GSTRING_LEN bytes using memcpy() which would create out of bounds accesses, this was flagged by KASAN. Replace this with strlcpy() to make sure we are bound the source buffer size and we also always NUL-terminate strings. Fixes: 2b2427d06426 ("phy: micrel: Add ethtool statistics counters") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/micrel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 0f45310300f6..49be85afbea9 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -664,8 +664,8 @@ static void kszphy_get_strings(struct phy_device *phydev, u8 *data) int i; for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++) { - memcpy(data + i * ETH_GSTRING_LEN, - kszphy_hw_stats[i].string, ETH_GSTRING_LEN); + strlcpy(data + i * ETH_GSTRING_LEN, + kszphy_hw_stats[i].string, ETH_GSTRING_LEN); } } -- cgit v1.2.3 From 8a17eefa235f73b60c0ca7d397d2e4f66f85f413 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 2 Mar 2018 15:08:39 -0800 Subject: net: phy: broadcom: Use strlcpy() for ethtool::get_strings Our statistics strings are allocated at initialization without being bound to a specific size, yet, we would copy ETH_GSTRING_LEN bytes using memcpy() which would create out of bounds accesses, this was flagged by KASAN. Replace this with strlcpy() to make sure we are bound the source buffer size and we also always NUL-terminate strings. Fixes: 820ee17b8d3b ("net: phy: broadcom: Add support code for reading PHY counters") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/bcm-phy-lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c index 171010eb4d9c..5ad130c3da43 100644 --- a/drivers/net/phy/bcm-phy-lib.c +++ b/drivers/net/phy/bcm-phy-lib.c @@ -341,8 +341,8 @@ void bcm_phy_get_strings(struct phy_device *phydev, u8 *data) unsigned int i; for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++) - memcpy(data + i * ETH_GSTRING_LEN, - bcm_phy_hw_stats[i].string, ETH_GSTRING_LEN); + strlcpy(data + i * ETH_GSTRING_LEN, + bcm_phy_hw_stats[i].string, ETH_GSTRING_LEN); } EXPORT_SYMBOL_GPL(bcm_phy_get_strings); -- cgit v1.2.3 From 22b8d8115d1b940d548a5fddcbce4cdd30083cfc Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 2 Mar 2018 16:34:22 -0800 Subject: ethernet: natsemi: correct spelling Correct spelling of National Semi-conductor (no hyphen) in drivers/net/ethernet/. Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller --- drivers/net/ethernet/8390/Kconfig | 2 +- drivers/net/ethernet/natsemi/Kconfig | 6 +++--- drivers/net/ethernet/natsemi/Makefile | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig index 29c3075bfb05..fdc673484add 100644 --- a/drivers/net/ethernet/8390/Kconfig +++ b/drivers/net/ethernet/8390/Kconfig @@ -3,7 +3,7 @@ # config NET_VENDOR_8390 - bool "National Semi-conductor 8390 devices" + bool "National Semiconductor 8390 devices" default y depends on NET_VENDOR_NATSEMI ---help--- diff --git a/drivers/net/ethernet/natsemi/Kconfig b/drivers/net/ethernet/natsemi/Kconfig index a10ef50e4f12..017fb2322589 100644 --- a/drivers/net/ethernet/natsemi/Kconfig +++ b/drivers/net/ethernet/natsemi/Kconfig @@ -1,16 +1,16 @@ # -# National Semi-conductor device configuration +# National Semiconductor device configuration # config NET_VENDOR_NATSEMI - bool "National Semi-conductor devices" + bool "National Semiconductor devices" default y ---help--- If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all - the questions about National Semi-conductor devices. If you say Y, + the questions about National Semiconductor devices. If you say Y, you will be asked for your specific card in the following questions. if NET_VENDOR_NATSEMI diff --git a/drivers/net/ethernet/natsemi/Makefile b/drivers/net/ethernet/natsemi/Makefile index cc664977596e..a759aa09ef59 100644 --- a/drivers/net/ethernet/natsemi/Makefile +++ b/drivers/net/ethernet/natsemi/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # -# Makefile for the National Semi-conductor Sonic devices. +# Makefile for the National Semiconductor Sonic devices. # obj-$(CONFIG_MACSONIC) += macsonic.o -- cgit v1.2.3 From 9a513c905bb95bef79d96feb08621c1ec8d8c4bb Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 6 Mar 2018 15:04:24 +0100 Subject: uas: fix comparison for error code A typo broke the comparison. Fixes: cbeef22fd611 ("usb: uas: unconditionally bring back host after reset") Signed-off-by: Oliver Neukum CC: stable@kernel.org Acked-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/uas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 3b1b9695177a..6034c39b67d1 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -1076,7 +1076,7 @@ static int uas_post_reset(struct usb_interface *intf) return 0; err = uas_configure_endpoints(devinfo); - if (err && err != ENODEV) + if (err && err != -ENODEV) shost_printk(KERN_ERR, shost, "%s: alloc streams error %d after reset", __func__, err); -- cgit v1.2.3 From cb88a0588717ba6c756cb5972d75766b273a6817 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 6 Mar 2018 09:38:49 +0100 Subject: usb: quirks: add control message delay for 1b1c:1b20 Corsair Strafe RGB keyboard does not respond to usb control messages sometimes and hence generates timeouts. Commit de3af5bf259d ("usb: quirks: add delay init quirk for Corsair Strafe RGB keyboard") tried to fix those timeouts by adding USB_QUIRK_DELAY_INIT. Unfortunately, even with this quirk timeouts of usb_control_msg() can still be seen, but with a lower frequency (approx. 1 out of 15): [ 29.103520] usb 1-8: string descriptor 0 read error: -110 [ 34.363097] usb 1-8: can't set config #1, error -110 Adding further delays to different locations where usb control messages are issued just moves the timeouts to other locations, e.g.: [ 35.400533] usbhid 1-8:1.0: can't add hid device: -110 [ 35.401014] usbhid: probe of 1-8:1.0 failed with error -110 The only way to reliably avoid those issues is having a pause after each usb control message. In approx. 200 boot cycles no more timeouts were seen. Addionaly, keep USB_QUIRK_DELAY_INIT as it turned out to be necessary to have the delay in hub_port_connect() after hub_port_init(). The overall boot time seems not to be influenced by these additional delays, even on fast machines and lightweight distributions. Fixes: de3af5bf259d ("usb: quirks: add delay init quirk for Corsair Strafe RGB keyboard") Cc: stable@vger.kernel.org Signed-off-by: Danilo Krummrich Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 4 ++++ drivers/usb/core/quirks.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index c64cf6c4a83d..0c11d40a12bc 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -151,6 +151,10 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout); + /* Linger a bit, prior to the next control message. */ + if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG) + msleep(200); + kfree(dr); return ret; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index f4a548471f0f..54b019e267c5 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -230,7 +230,8 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT }, /* Corsair Strafe RGB */ - { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT | + USB_QUIRK_DELAY_CTRL_MSG }, /* Corsair K70 LUX */ { USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT }, -- cgit v1.2.3 From df6b074dbe248d8c43a82131e8fd429e401841a5 Mon Sep 17 00:00:00 2001 From: Merlijn Wajer Date: Mon, 5 Mar 2018 11:35:10 -0600 Subject: usb: musb: call pm_runtime_{get,put}_sync before reading vbus registers Without pm_runtime_{get,put}_sync calls in place, reading vbus status via /sys causes the following error: Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa0ab060 pgd = b333e822 [fa0ab060] *pgd=48011452(bad) [] (musb_default_readb) from [] (musb_vbus_show+0x58/0xe4) [] (musb_vbus_show) from [] (dev_attr_show+0x20/0x44) [] (dev_attr_show) from [] (sysfs_kf_seq_show+0x80/0xdc) [] (sysfs_kf_seq_show) from [] (seq_read+0x250/0x448) [] (seq_read) from [] (__vfs_read+0x1c/0x118) [] (__vfs_read) from [] (vfs_read+0x90/0x144) [] (vfs_read) from [] (SyS_read+0x3c/0x74) [] (SyS_read) from [] (ret_fast_syscall+0x0/0x54) Solution was suggested by Tony Lindgren . Signed-off-by: Merlijn Wajer Acked-by: Tony Lindgren Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index eef4ad578b31..c344ef4e5355 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1756,6 +1756,7 @@ vbus_show(struct device *dev, struct device_attribute *attr, char *buf) int vbus; u8 devctl; + pm_runtime_get_sync(dev); spin_lock_irqsave(&musb->lock, flags); val = musb->a_wait_bcon; vbus = musb_platform_get_vbus_status(musb); @@ -1769,6 +1770,7 @@ vbus_show(struct device *dev, struct device_attribute *attr, char *buf) vbus = 0; } spin_unlock_irqrestore(&musb->lock, flags); + pm_runtime_put_sync(dev); return sprintf(buf, "Vbus %s, timeout %lu msec\n", vbus ? "on" : "off", val); -- cgit v1.2.3 From 6f566af3462897fc743e3af6ea8cc790a13148ba Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 6 Mar 2018 10:50:05 +0100 Subject: Revert "typec: tcpm: Only request matching pdos" Commit 57e6f0d7b804 ("typec: tcpm: Only request matching pdos") is causing a regression, before this commit e.g. the GPD win and GPD pocket devices were charging at 9V 3A with a PD charger, now they are instead slowly discharging at 5V 0.4A, as this commit causes the ports max_snk_mv/ma/mw settings to be completely ignored. Arguably the way to fix this would be to add a PDO_VAR() describing the voltage range to the snk_caps of boards which can handle any voltage in their range, but the "typec: tcpm: Only request matching pdos" commit looks at the type of PDO advertised by the source/charger and if that is fixed (as it typically is) only compairs against PDO_FIXED entries in the snk_caps so supporting a range of voltage would require adding a PDO_FIXED entry for *every possible* voltage to snk_caps. AFAICT there is no reason why a fixed source_cap cannot be matched against a variable snk_cap, so at a minimum the commit should be rewritten to support that. For now lets revert the "typec: tcpm: Only request matching pdos" commit, fixing the regression. Fixes: 57e6f0d7b804 ("typec: tcpm: Only request matching pdos") Cc: Badhri Jagan Sridharan Signed-off-by: Hans de Goede Acked-by: Heikki Krogerus Acked-by: Adam Thomson Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm.c | 163 ++++++++++++----------------------------------- 1 file changed, 42 insertions(+), 121 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm.c index f4d563ee7690..8b637a4b474b 100644 --- a/drivers/usb/typec/tcpm.c +++ b/drivers/usb/typec/tcpm.c @@ -252,9 +252,6 @@ struct tcpm_port { unsigned int nr_src_pdo; u32 snk_pdo[PDO_MAX_OBJECTS]; unsigned int nr_snk_pdo; - unsigned int nr_fixed; /* number of fixed sink PDOs */ - unsigned int nr_var; /* number of variable sink PDOs */ - unsigned int nr_batt; /* number of battery sink PDOs */ u32 snk_vdo[VDO_MAX_OBJECTS]; unsigned int nr_snk_vdo; @@ -1770,90 +1767,39 @@ static int tcpm_pd_check_request(struct tcpm_port *port) return 0; } -#define min_power(x, y) min(pdo_max_power(x), pdo_max_power(y)) -#define min_current(x, y) min(pdo_max_current(x), pdo_max_current(y)) - -static int tcpm_pd_select_pdo(struct tcpm_port *port, int *sink_pdo, - int *src_pdo) +static int tcpm_pd_select_pdo(struct tcpm_port *port) { - unsigned int i, j, max_mw = 0, max_mv = 0, mw = 0, mv = 0, ma = 0; + unsigned int i, max_mw = 0, max_mv = 0; int ret = -EINVAL; /* - * Select the source PDO providing the most power which has a - * matchig sink cap. + * Select the source PDO providing the most power while staying within + * the board's voltage limits. Prefer PDO providing exp */ for (i = 0; i < port->nr_source_caps; i++) { u32 pdo = port->source_caps[i]; enum pd_pdo_type type = pdo_type(pdo); + unsigned int mv, ma, mw; - if (type == PDO_TYPE_FIXED) { - for (j = 0; j < port->nr_fixed; j++) { - if (pdo_fixed_voltage(pdo) == - pdo_fixed_voltage(port->snk_pdo[j])) { - ma = min_current(pdo, port->snk_pdo[j]); - mv = pdo_fixed_voltage(pdo); - mw = ma * mv / 1000; - if (mw > max_mw || - (mw == max_mw && mv > max_mv)) { - ret = 0; - *src_pdo = i; - *sink_pdo = j; - max_mw = mw; - max_mv = mv; - } - /* There could only be one fixed pdo - * at a specific voltage level. - * So breaking here. - */ - break; - } - } - } else if (type == PDO_TYPE_BATT) { - for (j = port->nr_fixed; - j < port->nr_fixed + - port->nr_batt; - j++) { - if (pdo_min_voltage(pdo) >= - pdo_min_voltage(port->snk_pdo[j]) && - pdo_max_voltage(pdo) <= - pdo_max_voltage(port->snk_pdo[j])) { - mw = min_power(pdo, port->snk_pdo[j]); - mv = pdo_min_voltage(pdo); - if (mw > max_mw || - (mw == max_mw && mv > max_mv)) { - ret = 0; - *src_pdo = i; - *sink_pdo = j; - max_mw = mw; - max_mv = mv; - } - } - } - } else if (type == PDO_TYPE_VAR) { - for (j = port->nr_fixed + - port->nr_batt; - j < port->nr_fixed + - port->nr_batt + - port->nr_var; - j++) { - if (pdo_min_voltage(pdo) >= - pdo_min_voltage(port->snk_pdo[j]) && - pdo_max_voltage(pdo) <= - pdo_max_voltage(port->snk_pdo[j])) { - ma = min_current(pdo, port->snk_pdo[j]); - mv = pdo_min_voltage(pdo); - mw = ma * mv / 1000; - if (mw > max_mw || - (mw == max_mw && mv > max_mv)) { - ret = 0; - *src_pdo = i; - *sink_pdo = j; - max_mw = mw; - max_mv = mv; - } - } - } + if (type == PDO_TYPE_FIXED) + mv = pdo_fixed_voltage(pdo); + else + mv = pdo_min_voltage(pdo); + + if (type == PDO_TYPE_BATT) { + mw = pdo_max_power(pdo); + } else { + ma = min(pdo_max_current(pdo), + port->max_snk_ma); + mw = ma * mv / 1000; + } + + /* Perfer higher voltages if available */ + if ((mw > max_mw || (mw == max_mw && mv > max_mv)) && + mv <= port->max_snk_mv) { + ret = i; + max_mw = mw; + max_mv = mv; } } @@ -1865,14 +1811,13 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo) unsigned int mv, ma, mw, flags; unsigned int max_ma, max_mw; enum pd_pdo_type type; - int src_pdo_index, snk_pdo_index; - u32 pdo, matching_snk_pdo; + int index; + u32 pdo; - if (tcpm_pd_select_pdo(port, &snk_pdo_index, &src_pdo_index) < 0) + index = tcpm_pd_select_pdo(port); + if (index < 0) return -EINVAL; - - pdo = port->source_caps[src_pdo_index]; - matching_snk_pdo = port->snk_pdo[snk_pdo_index]; + pdo = port->source_caps[index]; type = pdo_type(pdo); if (type == PDO_TYPE_FIXED) @@ -1880,28 +1825,26 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo) else mv = pdo_min_voltage(pdo); - /* Select maximum available current within the sink pdo's limit */ + /* Select maximum available current within the board's power limit */ if (type == PDO_TYPE_BATT) { - mw = min_power(pdo, matching_snk_pdo); - ma = 1000 * mw / mv; + mw = pdo_max_power(pdo); + ma = 1000 * min(mw, port->max_snk_mw) / mv; } else { - ma = min_current(pdo, matching_snk_pdo); - mw = ma * mv / 1000; + ma = min(pdo_max_current(pdo), + 1000 * port->max_snk_mw / mv); } + ma = min(ma, port->max_snk_ma); flags = RDO_USB_COMM | RDO_NO_SUSPEND; /* Set mismatch bit if offered power is less than operating power */ + mw = ma * mv / 1000; max_ma = ma; max_mw = mw; if (mw < port->operating_snk_mw) { flags |= RDO_CAP_MISMATCH; - if (type == PDO_TYPE_BATT && - (pdo_max_power(matching_snk_pdo) > pdo_max_power(pdo))) - max_mw = pdo_max_power(matching_snk_pdo); - else if (pdo_max_current(matching_snk_pdo) > - pdo_max_current(pdo)) - max_ma = pdo_max_current(matching_snk_pdo); + max_mw = port->operating_snk_mw; + max_ma = max_mw * 1000 / mv; } tcpm_log(port, "cc=%d cc1=%d cc2=%d vbus=%d vconn=%s polarity=%d", @@ -1910,16 +1853,16 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo) port->polarity); if (type == PDO_TYPE_BATT) { - *rdo = RDO_BATT(src_pdo_index + 1, mw, max_mw, flags); + *rdo = RDO_BATT(index + 1, mw, max_mw, flags); tcpm_log(port, "Requesting PDO %d: %u mV, %u mW%s", - src_pdo_index, mv, mw, + index, mv, mw, flags & RDO_CAP_MISMATCH ? " [mismatch]" : ""); } else { - *rdo = RDO_FIXED(src_pdo_index + 1, ma, max_ma, flags); + *rdo = RDO_FIXED(index + 1, ma, max_ma, flags); tcpm_log(port, "Requesting PDO %d: %u mV, %u mA%s", - src_pdo_index, mv, ma, + index, mv, ma, flags & RDO_CAP_MISMATCH ? " [mismatch]" : ""); } @@ -3650,19 +3593,6 @@ int tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo, } EXPORT_SYMBOL_GPL(tcpm_update_sink_capabilities); -static int nr_type_pdos(const u32 *pdo, unsigned int nr_pdo, - enum pd_pdo_type type) -{ - int count = 0; - int i; - - for (i = 0; i < nr_pdo; i++) { - if (pdo_type(pdo[i]) == type) - count++; - } - return count; -} - struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) { struct tcpm_port *port; @@ -3708,15 +3638,6 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) tcpc->config->nr_src_pdo); port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcpc->config->snk_pdo, tcpc->config->nr_snk_pdo); - port->nr_fixed = nr_type_pdos(port->snk_pdo, - port->nr_snk_pdo, - PDO_TYPE_FIXED); - port->nr_var = nr_type_pdos(port->snk_pdo, - port->nr_snk_pdo, - PDO_TYPE_VAR); - port->nr_batt = nr_type_pdos(port->snk_pdo, - port->nr_snk_pdo, - PDO_TYPE_BATT); port->nr_snk_vdo = tcpm_copy_vdos(port->snk_vdo, tcpc->config->snk_vdo, tcpc->config->nr_snk_vdo); -- cgit v1.2.3 From 681066ec1d41e4b299146bada52cef846b323c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 27 Feb 2018 12:49:56 +0100 Subject: drm/prime: fix potential race in drm_gem_map_detach MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unpin the GEM object only after freeing the sg table. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Acked-by: Roger He Signed-off-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20180227115000.4105-1-christian.koenig@amd.com --- drivers/gpu/drm/drm_prime.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index e82a976f0fba..c38dacda6119 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -230,26 +230,26 @@ void drm_gem_map_detach(struct dma_buf *dma_buf, struct drm_prime_attachment *prime_attach = attach->priv; struct drm_gem_object *obj = dma_buf->priv; struct drm_device *dev = obj->dev; - struct sg_table *sgt; - if (dev->driver->gem_prime_unpin) - dev->driver->gem_prime_unpin(obj); + if (prime_attach) { + struct sg_table *sgt = prime_attach->sgt; - if (!prime_attach) - return; - - sgt = prime_attach->sgt; - if (sgt) { - if (prime_attach->dir != DMA_NONE) - dma_unmap_sg_attrs(attach->dev, sgt->sgl, sgt->nents, - prime_attach->dir, - DMA_ATTR_SKIP_CPU_SYNC); - sg_free_table(sgt); + if (sgt) { + if (prime_attach->dir != DMA_NONE) + dma_unmap_sg_attrs(attach->dev, sgt->sgl, + sgt->nents, + prime_attach->dir, + DMA_ATTR_SKIP_CPU_SYNC); + sg_free_table(sgt); + } + + kfree(sgt); + kfree(prime_attach); + attach->priv = NULL; } - kfree(sgt); - kfree(prime_attach); - attach->priv = NULL; + if (dev->driver->gem_prime_unpin) + dev->driver->gem_prime_unpin(obj); } EXPORT_SYMBOL(drm_gem_map_detach); -- cgit v1.2.3 From 186ca446aea19e49d2e1433dd170c6e1c211a52a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 27 Feb 2018 12:49:57 +0100 Subject: drm/prime: make the pages array optional for drm_prime_sg_to_page_addr_arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of the time we only need the dma addresses. Signed-off-by: Christian König Reviewed-by: Roger He Signed-off-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20180227115000.4105-2-christian.koenig@amd.com Link: https://patchwork.freedesktop.org/patch/msgid/20180227115000.4105-3-christian.koenig@amd.com Link: https://patchwork.freedesktop.org/patch/msgid/20180227115000.4105-4-christian.koenig@amd.com Link: https://patchwork.freedesktop.org/patch/msgid/20180227115000.4105-5-christian.koenig@amd.com Link: https://patchwork.freedesktop.org/patch/msgid/BN6PR12MB18262C0DE9B5F07B9A42EAE7F2C60@BN6PR12MB1826.namprd12.prod.outlook.com --- drivers/gpu/drm/drm_prime.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index c38dacda6119..7856a9b3f8a8 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -922,40 +922,40 @@ EXPORT_SYMBOL(drm_prime_pages_to_sg); /** * drm_prime_sg_to_page_addr_arrays - convert an sg table into a page array * @sgt: scatter-gather table to convert - * @pages: array of page pointers to store the page array in + * @pages: optional array of page pointers to store the page array in * @addrs: optional array to store the dma bus address of each page - * @max_pages: size of both the passed-in arrays + * @max_entries: size of both the passed-in arrays * * Exports an sg table into an array of pages and addresses. This is currently * required by the TTM driver in order to do correct fault handling. */ int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, - dma_addr_t *addrs, int max_pages) + dma_addr_t *addrs, int max_entries) { unsigned count; struct scatterlist *sg; struct page *page; - u32 len; - int pg_index; + u32 len, index; dma_addr_t addr; - pg_index = 0; + index = 0; for_each_sg(sgt->sgl, sg, sgt->nents, count) { len = sg->length; page = sg_page(sg); addr = sg_dma_address(sg); while (len > 0) { - if (WARN_ON(pg_index >= max_pages)) + if (WARN_ON(index >= max_entries)) return -1; - pages[pg_index] = page; + if (pages) + pages[index] = page; if (addrs) - addrs[pg_index] = addr; + addrs[index] = addr; page++; addr += PAGE_SIZE; len -= PAGE_SIZE; - pg_index++; + index++; } } return 0; -- cgit v1.2.3 From 655296c8bbeffcf020558c4455305d597a73bde1 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Sun, 4 Mar 2018 22:24:08 -0700 Subject: Drivers: hv: vmbus: Fix ring buffer signaling Fix bugs in signaling the Hyper-V host when freeing space in the host->guest ring buffer: 1. The interrupt_mask must not be used to determine whether to signal on the host->guest ring buffer 2. The ring buffer write_index must be read (via hv_get_bytes_to_write) *after* pending_send_sz is read in order to avoid a race condition 3. Comparisons with pending_send_sz must treat the "equals" case as not-enough-space 4. Don't signal if the pending_send_sz feature is not present. Older versions of Hyper-V that don't implement this feature will poll. Fixes: 03bad714a161 ("vmbus: more host signalling avoidance") Cc: Stable # 4.14 and above Signed-off-by: Michael Kelley Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/ring_buffer.c | 52 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 50e071444a5c..8699bb969e7e 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -417,13 +417,24 @@ __hv_pkt_iter_next(struct vmbus_channel *channel, } EXPORT_SYMBOL_GPL(__hv_pkt_iter_next); +/* How many bytes were read in this iterator cycle */ +static u32 hv_pkt_iter_bytes_read(const struct hv_ring_buffer_info *rbi, + u32 start_read_index) +{ + if (rbi->priv_read_index >= start_read_index) + return rbi->priv_read_index - start_read_index; + else + return rbi->ring_datasize - start_read_index + + rbi->priv_read_index; +} + /* * Update host ring buffer after iterating over packets. */ void hv_pkt_iter_close(struct vmbus_channel *channel) { struct hv_ring_buffer_info *rbi = &channel->inbound; - u32 orig_write_sz = hv_get_bytes_to_write(rbi); + u32 curr_write_sz, pending_sz, bytes_read, start_read_index; /* * Make sure all reads are done before we update the read index since @@ -431,8 +442,12 @@ void hv_pkt_iter_close(struct vmbus_channel *channel) * is updated. */ virt_rmb(); + start_read_index = rbi->ring_buffer->read_index; rbi->ring_buffer->read_index = rbi->priv_read_index; + if (!rbi->ring_buffer->feature_bits.feat_pending_send_sz) + return; + /* * Issue a full memory barrier before making the signaling decision. * Here is the reason for having this barrier: @@ -446,26 +461,29 @@ void hv_pkt_iter_close(struct vmbus_channel *channel) */ virt_mb(); - /* If host has disabled notifications then skip */ - if (rbi->ring_buffer->interrupt_mask) + pending_sz = READ_ONCE(rbi->ring_buffer->pending_send_sz); + if (!pending_sz) return; - if (rbi->ring_buffer->feature_bits.feat_pending_send_sz) { - u32 pending_sz = READ_ONCE(rbi->ring_buffer->pending_send_sz); + /* + * Ensure the read of write_index in hv_get_bytes_to_write() + * happens after the read of pending_send_sz. + */ + virt_rmb(); + curr_write_sz = hv_get_bytes_to_write(rbi); + bytes_read = hv_pkt_iter_bytes_read(rbi, start_read_index); - /* - * If there was space before we began iteration, - * then host was not blocked. Also handles case where - * pending_sz is zero then host has nothing pending - * and does not need to be signaled. - */ - if (orig_write_sz > pending_sz) - return; + /* + * If there was space before we began iteration, + * then host was not blocked. + */ - /* If pending write will not fit, don't give false hope. */ - if (hv_get_bytes_to_write(rbi) < pending_sz) - return; - } + if (curr_write_sz - bytes_read > pending_sz) + return; + + /* If pending write will not fit, don't give false hope. */ + if (curr_write_sz <= pending_sz) + return; vmbus_setevent(channel); } -- cgit v1.2.3 From 59a66424542c8e499e9d5c5c44935635b9a048fc Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Fri, 23 Feb 2018 16:39:59 +0800 Subject: drm/amd/pp: Implement update_dpm_settings on Fiji use SW method to update DPM settings by updating SRAM directly on Fiji. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c | 97 ++++++++++++++++++++++ 1 file changed, 97 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c index 047b2dfd89e2..fc556f0af021 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c @@ -2719,6 +2719,102 @@ static int fiji_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, array_size, SMC_RAM_END); } +static int fiji_update_dpm_settings(struct pp_hwmgr *hwmgr, + void *profile_setting) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct fiji_smumgr *smu_data = (struct fiji_smumgr *) + (hwmgr->smu_backend); + struct profile_mode_setting *setting; + struct SMU73_Discrete_GraphicsLevel *levels = + smu_data->smc_state_table.GraphicsLevel; + uint32_t array = smu_data->smu7_data.dpm_table_start + + offsetof(SMU73_Discrete_DpmTable, GraphicsLevel); + + uint32_t mclk_array = smu_data->smu7_data.dpm_table_start + + offsetof(SMU73_Discrete_DpmTable, MemoryLevel); + struct SMU73_Discrete_MemoryLevel *mclk_levels = + smu_data->smc_state_table.MemoryLevel; + uint32_t i; + uint32_t offset, up_hyst_offset, down_hyst_offset, clk_activity_offset, tmp; + + if (profile_setting == NULL) + return -EINVAL; + + setting = (struct profile_mode_setting *)profile_setting; + + if (setting->bupdate_sclk) { + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { + if (levels[i].ActivityLevel != + cpu_to_be16(setting->sclk_activity)) { + levels[i].ActivityLevel = cpu_to_be16(setting->sclk_activity); + + clk_activity_offset = array + (sizeof(SMU73_Discrete_GraphicsLevel) * i) + + offsetof(SMU73_Discrete_GraphicsLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (levels[i].UpHyst != setting->sclk_up_hyst || + levels[i].DownHyst != setting->sclk_down_hyst) { + levels[i].UpHyst = setting->sclk_up_hyst; + levels[i].DownHyst = setting->sclk_down_hyst; + up_hyst_offset = array + (sizeof(SMU73_Discrete_GraphicsLevel) * i) + + offsetof(SMU73_Discrete_GraphicsLevel, UpHyst); + down_hyst_offset = array + (sizeof(SMU73_Discrete_GraphicsLevel) * i) + + offsetof(SMU73_Discrete_GraphicsLevel, DownHyst); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, levels[i].UpHyst, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, levels[i].DownHyst, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel); + } + + if (setting->bupdate_mclk) { + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.MemoryDpmLevelCount; i++) { + if (mclk_levels[i].ActivityLevel != + cpu_to_be16(setting->mclk_activity)) { + mclk_levels[i].ActivityLevel = cpu_to_be16(setting->mclk_activity); + + clk_activity_offset = mclk_array + (sizeof(SMU73_Discrete_MemoryLevel) * i) + + offsetof(SMU73_Discrete_MemoryLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, mclk_levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (mclk_levels[i].UpHyst != setting->mclk_up_hyst || + mclk_levels[i].DownHyst != setting->mclk_down_hyst) { + mclk_levels[i].UpHyst = setting->mclk_up_hyst; + mclk_levels[i].DownHyst = setting->mclk_down_hyst; + up_hyst_offset = mclk_array + (sizeof(SMU73_Discrete_MemoryLevel) * i) + + offsetof(SMU73_Discrete_MemoryLevel, UpHyst); + down_hyst_offset = mclk_array + (sizeof(SMU73_Discrete_MemoryLevel) * i) + + offsetof(SMU73_Discrete_MemoryLevel, DownHyst); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, mclk_levels[i].UpHyst, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, mclk_levels[i].DownHyst, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel); + } + return 0; +} + const struct pp_smumgr_func fiji_smu_funcs = { .smu_init = &fiji_smu_init, .smu_fini = &smu7_smu_fini, @@ -2744,4 +2840,5 @@ const struct pp_smumgr_func fiji_smu_funcs = { .is_dpm_running = fiji_is_dpm_running, .populate_requested_graphic_levels = fiji_populate_requested_graphic_levels, .is_hw_avfs_present = fiji_is_hw_avfs_present, + .update_dpm_settings = fiji_update_dpm_settings, }; -- cgit v1.2.3 From fdd62a40d4f379c018895a6596ab6639b32bea50 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Fri, 23 Feb 2018 16:41:20 +0800 Subject: drm/amd/pp: Implement update_dpm_settings on Tonga use SW method to update DPM settings by updating SRAM directly on Tonga. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- .../gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c | 97 ++++++++++++++++++++++ 1 file changed, 97 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c index a268b98abb8e..86fb7709a1c4 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c @@ -3277,6 +3277,102 @@ static int tonga_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, array_size, SMC_RAM_END); } +static int tonga_update_dpm_settings(struct pp_hwmgr *hwmgr, + void *profile_setting) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct tonga_smumgr *smu_data = (struct tonga_smumgr *) + (hwmgr->smu_backend); + struct profile_mode_setting *setting; + struct SMU72_Discrete_GraphicsLevel *levels = + smu_data->smc_state_table.GraphicsLevel; + uint32_t array = smu_data->smu7_data.dpm_table_start + + offsetof(SMU72_Discrete_DpmTable, GraphicsLevel); + + uint32_t mclk_array = smu_data->smu7_data.dpm_table_start + + offsetof(SMU72_Discrete_DpmTable, MemoryLevel); + struct SMU72_Discrete_MemoryLevel *mclk_levels = + smu_data->smc_state_table.MemoryLevel; + uint32_t i; + uint32_t offset, up_hyst_offset, down_hyst_offset, clk_activity_offset, tmp; + + if (profile_setting == NULL) + return -EINVAL; + + setting = (struct profile_mode_setting *)profile_setting; + + if (setting->bupdate_sclk) { + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { + if (levels[i].ActivityLevel != + cpu_to_be16(setting->sclk_activity)) { + levels[i].ActivityLevel = cpu_to_be16(setting->sclk_activity); + + clk_activity_offset = array + (sizeof(SMU72_Discrete_GraphicsLevel) * i) + + offsetof(SMU72_Discrete_GraphicsLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (levels[i].UpHyst != setting->sclk_up_hyst || + levels[i].DownHyst != setting->sclk_down_hyst) { + levels[i].UpHyst = setting->sclk_up_hyst; + levels[i].DownHyst = setting->sclk_down_hyst; + up_hyst_offset = array + (sizeof(SMU72_Discrete_GraphicsLevel) * i) + + offsetof(SMU72_Discrete_GraphicsLevel, UpHyst); + down_hyst_offset = array + (sizeof(SMU72_Discrete_GraphicsLevel) * i) + + offsetof(SMU72_Discrete_GraphicsLevel, DownHyst); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, levels[i].UpHyst, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, levels[i].DownHyst, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel); + } + + if (setting->bupdate_mclk) { + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.MemoryDpmLevelCount; i++) { + if (mclk_levels[i].ActivityLevel != + cpu_to_be16(setting->mclk_activity)) { + mclk_levels[i].ActivityLevel = cpu_to_be16(setting->mclk_activity); + + clk_activity_offset = mclk_array + (sizeof(SMU72_Discrete_MemoryLevel) * i) + + offsetof(SMU72_Discrete_MemoryLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, mclk_levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (mclk_levels[i].UpHyst != setting->mclk_up_hyst || + mclk_levels[i].DownHyst != setting->mclk_down_hyst) { + mclk_levels[i].UpHyst = setting->mclk_up_hyst; + mclk_levels[i].DownHyst = setting->mclk_down_hyst; + up_hyst_offset = mclk_array + (sizeof(SMU72_Discrete_MemoryLevel) * i) + + offsetof(SMU72_Discrete_MemoryLevel, UpHyst); + down_hyst_offset = mclk_array + (sizeof(SMU72_Discrete_MemoryLevel) * i) + + offsetof(SMU72_Discrete_MemoryLevel, DownHyst); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, mclk_levels[i].UpHyst, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, mclk_levels[i].DownHyst, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel); + } + return 0; +} + const struct pp_smumgr_func tonga_smu_funcs = { .smu_init = &tonga_smu_init, .smu_fini = &smu7_smu_fini, @@ -3300,4 +3396,5 @@ const struct pp_smumgr_func tonga_smu_funcs = { .initialize_mc_reg_table = tonga_initialize_mc_reg_table, .is_dpm_running = tonga_is_dpm_running, .populate_requested_graphic_levels = tonga_populate_requested_graphic_levels, + .update_dpm_settings = tonga_update_dpm_settings, }; -- cgit v1.2.3 From 6dcd30aa11b84eb78d67fc9c081fd343abaaaef5 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Fri, 23 Feb 2018 16:52:41 +0800 Subject: drm/amd/pp: Implement update_dpm_settings on CI use SW method to update DPM settings by updating SRAM directly on CI. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c | 97 ++++++++++++++++++++++++ 1 file changed, 97 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c index 76f700fe7491..179d00cd5514 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c @@ -2819,6 +2819,102 @@ static int ci_start_smu(struct pp_hwmgr *hwmgr) return 0; } +static int ci_update_dpm_settings(struct pp_hwmgr *hwmgr, + void *profile_setting) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct ci_smumgr *smu_data = (struct ci_smumgr *) + (hwmgr->smu_backend); + struct profile_mode_setting *setting; + struct SMU7_Discrete_GraphicsLevel *levels = + smu_data->smc_state_table.GraphicsLevel; + uint32_t array = smu_data->dpm_table_start + + offsetof(SMU7_Discrete_DpmTable, GraphicsLevel); + + uint32_t mclk_array = smu_data->dpm_table_start + + offsetof(SMU7_Discrete_DpmTable, MemoryLevel); + struct SMU7_Discrete_MemoryLevel *mclk_levels = + smu_data->smc_state_table.MemoryLevel; + uint32_t i; + uint32_t offset, up_hyst_offset, down_hyst_offset, clk_activity_offset, tmp; + + if (profile_setting == NULL) + return -EINVAL; + + setting = (struct profile_mode_setting *)profile_setting; + + if (setting->bupdate_sclk) { + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { + if (levels[i].ActivityLevel != + cpu_to_be16(setting->sclk_activity)) { + levels[i].ActivityLevel = cpu_to_be16(setting->sclk_activity); + + clk_activity_offset = array + (sizeof(SMU7_Discrete_GraphicsLevel) * i) + + offsetof(SMU7_Discrete_GraphicsLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (levels[i].UpH != setting->sclk_up_hyst || + levels[i].DownH != setting->sclk_down_hyst) { + levels[i].UpH = setting->sclk_up_hyst; + levels[i].DownH = setting->sclk_down_hyst; + up_hyst_offset = array + (sizeof(SMU7_Discrete_GraphicsLevel) * i) + + offsetof(SMU7_Discrete_GraphicsLevel, UpH); + down_hyst_offset = array + (sizeof(SMU7_Discrete_GraphicsLevel) * i) + + offsetof(SMU7_Discrete_GraphicsLevel, DownH); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, levels[i].UpH, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, levels[i].DownH, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel); + } + + if (setting->bupdate_mclk) { + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.MemoryDpmLevelCount; i++) { + if (mclk_levels[i].ActivityLevel != + cpu_to_be16(setting->mclk_activity)) { + mclk_levels[i].ActivityLevel = cpu_to_be16(setting->mclk_activity); + + clk_activity_offset = mclk_array + (sizeof(SMU7_Discrete_MemoryLevel) * i) + + offsetof(SMU7_Discrete_MemoryLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, mclk_levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (mclk_levels[i].UpH != setting->mclk_up_hyst || + mclk_levels[i].DownH != setting->mclk_down_hyst) { + mclk_levels[i].UpH = setting->mclk_up_hyst; + mclk_levels[i].DownH = setting->mclk_down_hyst; + up_hyst_offset = mclk_array + (sizeof(SMU7_Discrete_MemoryLevel) * i) + + offsetof(SMU7_Discrete_MemoryLevel, UpH); + down_hyst_offset = mclk_array + (sizeof(SMU7_Discrete_MemoryLevel) * i) + + offsetof(SMU7_Discrete_MemoryLevel, DownH); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, mclk_levels[i].UpH, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, mclk_levels[i].DownH, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel); + } + return 0; +} + const struct pp_smumgr_func ci_smu_funcs = { .smu_init = ci_smu_init, .smu_fini = ci_smu_fini, @@ -2841,4 +2937,5 @@ const struct pp_smumgr_func ci_smu_funcs = { .initialize_mc_reg_table = ci_initialize_mc_reg_table, .is_dpm_running = ci_is_dpm_running, .populate_requested_graphic_levels = ci_populate_requested_graphic_levels, + .update_dpm_settings = ci_update_dpm_settings, }; -- cgit v1.2.3 From 5d24af846ee3264a0e3b2d6ee535b904e34b3fce Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Wed, 31 Jan 2018 14:48:14 +0800 Subject: drm/amd/pp: Implement get/set_power_profile_mode on smu7 It show what parameters can be configured to tune the behavior of natural dpm for perf/watt on smu7. user can select the mode per workload, but even the default per workload settings are not bulletproof. user can configure custom settings per different use case for better perf or better perf/watt. cat pp_power_profile_mode NUM MODE_NAME SCLK_UP_HYST SCLK_DOWN_HYST SCLK_ACTIVE_LEVEL MCLK_UP_HYST MCLK_DOWN_HYST MCLK_ACTIVE_LEVEL 0 3D_FULL_SCREEN: 0 100 30 0 100 10 1 POWER_SAVING: 10 0 30 - - - 2 VIDEO: - - - 10 16 31 3 VR: 0 11 50 0 100 10 4 COMPUTE: 0 5 30 - - - 5 CUSTOM: 0 0 0 0 0 0 * CURRENT: 0 100 30 0 100 10 Under manual dpm level, user can echo "0/1/2/3/4">pp_power_profile_mode to select 3D_FULL_SCREEN/POWER_SAVING/VIDEO/VR/COMPUTE mode. echo "5 * * * * * * * *">pp_power_profile_mode to set custom settings. "5 * * * * * * * *" mean "CUSTOM enable_sclk SCLK_UP_HYST SCLK_DOWN_HYST SCLK_ACTIVE_LEVEL enable_mclk MCLK_UP_HYST MCLK_DOWN_HYST MCLK_ACTIVE_LEVEL" if the parameter enable_sclk/enable_mclk is true, driver will update the following parameters to dpm table. if false, ignore the following parameters. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 143 +++++++++++++++++++++++ 1 file changed, 143 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index f6e1196a6e55..cde13ab647fa 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -80,6 +80,13 @@ #define PCIE_BUS_CLK 10000 #define TCLK (PCIE_BUS_CLK / 10) +static const struct profile_mode_setting smu7_profiling[5] = + {{1, 0, 100, 30, 1, 0, 100, 10}, + {1, 10, 0, 30, 0, 0, 0, 0}, + {0, 0, 0, 0, 1, 10, 16, 31}, + {1, 0, 11, 50, 1, 0, 100, 10}, + {1, 0, 5, 30, 0, 0, 0, 0}, + }; /** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */ enum DPM_EVENT_SRC { @@ -2459,6 +2466,9 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) smu7_patch_voltage_workaround(hwmgr); smu7_init_dpm_defaults(hwmgr); + hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D; + hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D; + /* Get leakage voltage based on leakage ID. */ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EVV)) { @@ -4895,6 +4905,137 @@ static int smu7_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, return 0; } +static int smu7_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + uint32_t i, size = 0; + uint32_t len; + + static const char *profile_name[6] = {"3D_FULL_SCREEN", + "POWER_SAVING", + "VIDEO", + "VR", + "COMPUTE", + "CUSTOM"}; + + static const char *title[8] = {"NUM", + "MODE_NAME", + "SCLK_UP_HYST", + "SCLK_DOWN_HYST", + "SCLK_ACTIVE_LEVEL", + "MCLK_UP_HYST", + "MCLK_DOWN_HYST", + "MCLK_ACTIVE_LEVEL"}; + + if (!buf) + return -EINVAL; + + size += sprintf(buf + size, "%s %16s %16s %16s %16s %16s %16s %16s\n", + title[0], title[1], title[2], title[3], + title[4], title[5], title[6], title[7]); + + len = sizeof(smu7_profiling) / sizeof(struct profile_mode_setting); + + for (i = 0; i < len; i++) { + if (smu7_profiling[i].bupdate_sclk) + size += sprintf(buf + size, "%3d %16s: %8d %16d %16d ", + i, profile_name[i], smu7_profiling[i].sclk_up_hyst, + smu7_profiling[i].sclk_down_hyst, + smu7_profiling[i].sclk_activity); + else + size += sprintf(buf + size, "%3d %16s: %8s %16s %16s ", + i, profile_name[i], "-", "-", "-"); + + if (smu7_profiling[i].bupdate_mclk) + size += sprintf(buf + size, "%16d %16d %16d\n", + smu7_profiling[i].mclk_up_hyst, + smu7_profiling[i].mclk_down_hyst, + smu7_profiling[i].mclk_activity); + else + size += sprintf(buf + size, "%16s %16s %16s\n", + "-", "-", "-"); + } + + size += sprintf(buf + size, "%3d %16s: %8d %16d %16d %16d %16d %16d\n", + i, profile_name[i], + data->custom_profile_setting.sclk_up_hyst, + data->custom_profile_setting.sclk_down_hyst, + data->custom_profile_setting.sclk_activity, + data->custom_profile_setting.mclk_up_hyst, + data->custom_profile_setting.mclk_down_hyst, + data->custom_profile_setting.mclk_activity); + + size += sprintf(buf + size, "%3s %16s: %8d %16d %16d %16d %16d %16d\n", + "*", "CURRENT", + data->current_profile_setting.sclk_up_hyst, + data->current_profile_setting.sclk_down_hyst, + data->current_profile_setting.sclk_activity, + data->current_profile_setting.mclk_up_hyst, + data->current_profile_setting.mclk_down_hyst, + data->current_profile_setting.mclk_activity); + + return size; +} + +static int smu7_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint32_t size) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct profile_mode_setting tmp; + enum PP_SMC_POWER_PROFILE mode; + + if (input == NULL) + return -EINVAL; + + mode = input[size]; + switch (mode) { + case PP_SMC_POWER_PROFILE_CUSTOM: + if (size < 8) + return -EINVAL; + + data->custom_profile_setting.bupdate_sclk = input[0]; + data->custom_profile_setting.sclk_up_hyst = input[1]; + data->custom_profile_setting.sclk_down_hyst = input[2]; + data->custom_profile_setting.sclk_activity = input[3]; + data->custom_profile_setting.bupdate_mclk = input[4]; + data->custom_profile_setting.mclk_up_hyst = input[5]; + data->custom_profile_setting.mclk_down_hyst = input[6]; + data->custom_profile_setting.mclk_activity = input[7]; + if (!smum_update_dpm_settings(hwmgr, &data->custom_profile_setting)) { + memcpy(&data->current_profile_setting, &data->custom_profile_setting, sizeof(struct profile_mode_setting)); + hwmgr->power_profile_mode = mode; + } + break; + case PP_SMC_POWER_PROFILE_FULLSCREEN3D: + case PP_SMC_POWER_PROFILE_POWERSAVING: + case PP_SMC_POWER_PROFILE_VIDEO: + case PP_SMC_POWER_PROFILE_VR: + case PP_SMC_POWER_PROFILE_COMPUTE: + if (mode == hwmgr->power_profile_mode) + return 0; + + memcpy(&tmp, &smu7_profiling[mode], sizeof(struct profile_mode_setting)); + if (!smum_update_dpm_settings(hwmgr, &tmp)) { + if (tmp.bupdate_sclk) { + data->current_profile_setting.bupdate_sclk = tmp.bupdate_sclk; + data->current_profile_setting.sclk_up_hyst = tmp.sclk_up_hyst; + data->current_profile_setting.sclk_down_hyst = tmp.sclk_down_hyst; + data->current_profile_setting.sclk_activity = tmp.sclk_activity; + } + if (tmp.bupdate_mclk) { + data->current_profile_setting.bupdate_mclk = tmp.bupdate_mclk; + data->current_profile_setting.mclk_up_hyst = tmp.mclk_up_hyst; + data->current_profile_setting.mclk_down_hyst = tmp.mclk_down_hyst; + data->current_profile_setting.mclk_activity = tmp.mclk_activity; + } + hwmgr->power_profile_mode = mode; + } + break; + default: + return -EINVAL; + } + + return 0; +} static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .backend_init = &smu7_hwmgr_backend_init, @@ -4951,6 +5092,8 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .get_thermal_temperature_range = smu7_get_thermal_temperature_range, .odn_edit_dpm_table = smu7_odn_edit_dpm_table, .set_power_limit = smu7_set_power_limit, + .get_power_profile_mode = smu7_get_power_profile_mode, + .set_power_profile_mode = smu7_set_power_profile_mode, }; uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock, -- cgit v1.2.3 From 180a8bebdd50fc8ce4677e579d49d9b73880caa7 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Fri, 23 Feb 2018 17:41:07 +0800 Subject: drm/amd/pp: Fix sclk in highest two levels when compute on smu7 Compute workload tends to be "bursty", Only tune the behavior of nature dpm don't work well for most of such workloads. From test results, Fix sclk in highest two levels can get better performance. so add min sclk setting into the default cumpute workload policy on smu7. user still can change sclk range through sysfs pp_dpm_sclk for better perf/watt. Reviewed-by: Evan Quan Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index cde13ab647fa..3f894bc85c25 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -4977,6 +4977,26 @@ static int smu7_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf) return size; } +static void smu7_patch_compute_profile_mode(struct pp_hwmgr *hwmgr, + enum PP_SMC_POWER_PROFILE requst) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + uint32_t tmp, level; + + if (requst == PP_SMC_POWER_PROFILE_COMPUTE) { + if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) { + level = 0; + tmp = data->dpm_level_enable_mask.sclk_dpm_enable_mask; + while (tmp >>= 1) + level++; + if (level > 0) + smu7_force_clock_level(hwmgr, PP_SCLK, 3 << (level-1)); + } + } else if (hwmgr->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE) { + smu7_force_clock_level(hwmgr, PP_SCLK, data->dpm_level_enable_mask.sclk_dpm_enable_mask); + } +} + static int smu7_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint32_t size) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); @@ -5027,6 +5047,7 @@ static int smu7_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint data->current_profile_setting.mclk_down_hyst = tmp.mclk_down_hyst; data->current_profile_setting.mclk_activity = tmp.mclk_activity; } + smu7_patch_compute_profile_mode(hwmgr, mode); hwmgr->power_profile_mode = mode; } break; -- cgit v1.2.3 From a5278e511dce23349e71d681dfa7e8c600d19603 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Sat, 24 Feb 2018 19:53:41 +0800 Subject: drm/amd/pp: Revert gfx/compute profile switch sysfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gfx/compute profiling mode switch is only for internally test. Not a complete solution and unexpectly upstream. so revert it. Reviewed-by: Evan Quan Acked-by: Christian König Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h | 8 - drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 180 --------------- drivers/gpu/drm/amd/amdgpu/ci_dpm.c | 256 --------------------- drivers/gpu/drm/amd/amdgpu/ci_dpm.h | 7 - drivers/gpu/drm/amd/include/kgd_pp_interface.h | 7 - drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 114 --------- .../gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c | 17 -- drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c | 2 - drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 77 ------- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 86 ------- .../gpu/drm/amd/powerplay/inc/hardwaremanager.h | 1 - drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 9 - drivers/gpu/drm/amd/powerplay/inc/smumgr.h | 3 - drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c | 27 --- drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c | 66 ------ .../drm/amd/powerplay/smumgr/polaris10_smumgr.c | 64 ------ drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c | 10 - .../gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c | 64 ------ 18 files changed, 998 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h index bd745a4fae0c..9c373f8f465c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h @@ -341,14 +341,6 @@ enum amdgpu_pcie_gen { ((adev)->powerplay.pp_funcs->reset_power_profile_state(\ (adev)->powerplay.pp_handle, request)) -#define amdgpu_dpm_get_power_profile_state(adev, query) \ - ((adev)->powerplay.pp_funcs->get_power_profile_state(\ - (adev)->powerplay.pp_handle, query)) - -#define amdgpu_dpm_set_power_profile_state(adev, request) \ - ((adev)->powerplay.pp_funcs->set_power_profile_state(\ - (adev)->powerplay.pp_handle, request)) - #define amdgpu_dpm_switch_power_profile(adev, type) \ ((adev)->powerplay.pp_funcs->switch_power_profile(\ (adev)->powerplay.pp_handle, type)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 9e73cbcfce44..632b18670098 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -734,161 +734,6 @@ fail: return -EINVAL; } -static ssize_t amdgpu_get_pp_power_profile(struct device *dev, - char *buf, struct amd_pp_profile *query) -{ - struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; - int ret = 0xff; - - if (adev->powerplay.pp_funcs->get_power_profile_state) - ret = amdgpu_dpm_get_power_profile_state( - adev, query); - - if (ret) - return ret; - - return snprintf(buf, PAGE_SIZE, - "%d %d %d %d %d\n", - query->min_sclk / 100, - query->min_mclk / 100, - query->activity_threshold, - query->up_hyst, - query->down_hyst); -} - -static ssize_t amdgpu_get_pp_gfx_power_profile(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct amd_pp_profile query = {0}; - - query.type = AMD_PP_GFX_PROFILE; - - return amdgpu_get_pp_power_profile(dev, buf, &query); -} - -static ssize_t amdgpu_get_pp_compute_power_profile(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct amd_pp_profile query = {0}; - - query.type = AMD_PP_COMPUTE_PROFILE; - - return amdgpu_get_pp_power_profile(dev, buf, &query); -} - -static ssize_t amdgpu_set_pp_power_profile(struct device *dev, - const char *buf, - size_t count, - struct amd_pp_profile *request) -{ - struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; - uint32_t loop = 0; - char *sub_str, buf_cpy[128], *tmp_str; - const char delimiter[3] = {' ', '\n', '\0'}; - long int value; - int ret = 0xff; - - if (strncmp("reset", buf, strlen("reset")) == 0) { - if (adev->powerplay.pp_funcs->reset_power_profile_state) - ret = amdgpu_dpm_reset_power_profile_state( - adev, request); - if (ret) { - count = -EINVAL; - goto fail; - } - return count; - } - - if (strncmp("set", buf, strlen("set")) == 0) { - if (adev->powerplay.pp_funcs->set_power_profile_state) - ret = amdgpu_dpm_set_power_profile_state( - adev, request); - - if (ret) { - count = -EINVAL; - goto fail; - } - return count; - } - - if (count + 1 >= 128) { - count = -EINVAL; - goto fail; - } - - memcpy(buf_cpy, buf, count + 1); - tmp_str = buf_cpy; - - while (tmp_str[0]) { - sub_str = strsep(&tmp_str, delimiter); - ret = kstrtol(sub_str, 0, &value); - if (ret) { - count = -EINVAL; - goto fail; - } - - switch (loop) { - case 0: - /* input unit MHz convert to dpm table unit 10KHz*/ - request->min_sclk = (uint32_t)value * 100; - break; - case 1: - /* input unit MHz convert to dpm table unit 10KHz*/ - request->min_mclk = (uint32_t)value * 100; - break; - case 2: - request->activity_threshold = (uint16_t)value; - break; - case 3: - request->up_hyst = (uint8_t)value; - break; - case 4: - request->down_hyst = (uint8_t)value; - break; - default: - break; - } - - loop++; - } - if (adev->powerplay.pp_funcs->set_power_profile_state) - ret = amdgpu_dpm_set_power_profile_state(adev, request); - - if (ret) - count = -EINVAL; - -fail: - return count; -} - -static ssize_t amdgpu_set_pp_gfx_power_profile(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct amd_pp_profile request = {0}; - - request.type = AMD_PP_GFX_PROFILE; - - return amdgpu_set_pp_power_profile(dev, buf, count, &request); -} - -static ssize_t amdgpu_set_pp_compute_power_profile(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct amd_pp_profile request = {0}; - - request.type = AMD_PP_COMPUTE_PROFILE; - - return amdgpu_set_pp_power_profile(dev, buf, count, &request); -} - static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, amdgpu_get_dpm_state, amdgpu_set_dpm_state); static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR, amdgpu_get_dpm_forced_performance_level, @@ -916,12 +761,6 @@ static DEVICE_ATTR(pp_sclk_od, S_IRUGO | S_IWUSR, static DEVICE_ATTR(pp_mclk_od, S_IRUGO | S_IWUSR, amdgpu_get_pp_mclk_od, amdgpu_set_pp_mclk_od); -static DEVICE_ATTR(pp_gfx_power_profile, S_IRUGO | S_IWUSR, - amdgpu_get_pp_gfx_power_profile, - amdgpu_set_pp_gfx_power_profile); -static DEVICE_ATTR(pp_compute_power_profile, S_IRUGO | S_IWUSR, - amdgpu_get_pp_compute_power_profile, - amdgpu_set_pp_compute_power_profile); static DEVICE_ATTR(pp_power_profile_mode, S_IRUGO | S_IWUSR, amdgpu_get_pp_power_profile_mode, amdgpu_set_pp_power_profile_mode); @@ -1766,21 +1605,6 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) DRM_ERROR("failed to create device file pp_mclk_od\n"); return ret; } - ret = device_create_file(adev->dev, - &dev_attr_pp_gfx_power_profile); - if (ret) { - DRM_ERROR("failed to create device file " - "pp_gfx_power_profile\n"); - return ret; - } - ret = device_create_file(adev->dev, - &dev_attr_pp_compute_power_profile); - if (ret) { - DRM_ERROR("failed to create device file " - "pp_compute_power_profile\n"); - return ret; - } - ret = device_create_file(adev->dev, &dev_attr_pp_power_profile_mode); if (ret) { @@ -1826,10 +1650,6 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie); device_remove_file(adev->dev, &dev_attr_pp_sclk_od); device_remove_file(adev->dev, &dev_attr_pp_mclk_od); - device_remove_file(adev->dev, - &dev_attr_pp_gfx_power_profile); - device_remove_file(adev->dev, - &dev_attr_pp_compute_power_profile); device_remove_file(adev->dev, &dev_attr_pp_power_profile_mode); device_remove_file(adev->dev, diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index f82f40fb3bea..ddb814f7e952 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -3695,40 +3695,6 @@ static int ci_find_boot_level(struct ci_single_dpm_table *table, return ret; } -static void ci_save_default_power_profile(struct amdgpu_device *adev) -{ - struct ci_power_info *pi = ci_get_pi(adev); - struct SMU7_Discrete_GraphicsLevel *levels = - pi->smc_state_table.GraphicsLevel; - uint32_t min_level = 0; - - pi->default_gfx_power_profile.activity_threshold = - be16_to_cpu(levels[0].ActivityLevel); - pi->default_gfx_power_profile.up_hyst = levels[0].UpH; - pi->default_gfx_power_profile.down_hyst = levels[0].DownH; - pi->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE; - - pi->default_compute_power_profile = pi->default_gfx_power_profile; - pi->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE; - - /* Optimize compute power profile: Use only highest - * 2 power levels (if more than 2 are available), Hysteresis: - * 0ms up, 5ms down - */ - if (pi->smc_state_table.GraphicsDpmLevelCount > 2) - min_level = pi->smc_state_table.GraphicsDpmLevelCount - 2; - else if (pi->smc_state_table.GraphicsDpmLevelCount == 2) - min_level = 1; - pi->default_compute_power_profile.min_sclk = - be32_to_cpu(levels[min_level].SclkFrequency); - - pi->default_compute_power_profile.up_hyst = 0; - pi->default_compute_power_profile.down_hyst = 5; - - pi->gfx_power_profile = pi->default_gfx_power_profile; - pi->compute_power_profile = pi->default_compute_power_profile; -} - static int ci_init_smc_table(struct amdgpu_device *adev) { struct ci_power_info *pi = ci_get_pi(adev); @@ -3874,8 +3840,6 @@ static int ci_init_smc_table(struct amdgpu_device *adev) if (ret) return ret; - ci_save_default_power_profile(adev); - return 0; } @@ -6753,222 +6717,6 @@ static int ci_dpm_set_mclk_od(void *handle, uint32_t value) return 0; } -static int ci_dpm_get_power_profile_state(void *handle, - struct amd_pp_profile *query) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - struct ci_power_info *pi = ci_get_pi(adev); - - if (!pi || !query) - return -EINVAL; - - if (query->type == AMD_PP_GFX_PROFILE) - memcpy(query, &pi->gfx_power_profile, - sizeof(struct amd_pp_profile)); - else if (query->type == AMD_PP_COMPUTE_PROFILE) - memcpy(query, &pi->compute_power_profile, - sizeof(struct amd_pp_profile)); - else - return -EINVAL; - - return 0; -} - -static int ci_populate_requested_graphic_levels(struct amdgpu_device *adev, - struct amd_pp_profile *request) -{ - struct ci_power_info *pi = ci_get_pi(adev); - struct ci_dpm_table *dpm_table = &(pi->dpm_table); - struct SMU7_Discrete_GraphicsLevel *levels = - pi->smc_state_table.GraphicsLevel; - uint32_t array = pi->dpm_table_start + - offsetof(SMU7_Discrete_DpmTable, GraphicsLevel); - uint32_t array_size = sizeof(struct SMU7_Discrete_GraphicsLevel) * - SMU7_MAX_LEVELS_GRAPHICS; - uint32_t i; - - for (i = 0; i < dpm_table->sclk_table.count; i++) { - levels[i].ActivityLevel = - cpu_to_be16(request->activity_threshold); - levels[i].EnabledForActivity = 1; - levels[i].UpH = request->up_hyst; - levels[i].DownH = request->down_hyst; - } - - return amdgpu_ci_copy_bytes_to_smc(adev, array, (uint8_t *)levels, - array_size, pi->sram_end); -} - -static void ci_find_min_clock_masks(struct amdgpu_device *adev, - uint32_t *sclk_mask, uint32_t *mclk_mask, - uint32_t min_sclk, uint32_t min_mclk) -{ - struct ci_power_info *pi = ci_get_pi(adev); - struct ci_dpm_table *dpm_table = &(pi->dpm_table); - uint32_t i; - - for (i = 0; i < dpm_table->sclk_table.count; i++) { - if (dpm_table->sclk_table.dpm_levels[i].enabled && - dpm_table->sclk_table.dpm_levels[i].value >= min_sclk) - *sclk_mask |= 1 << i; - } - - for (i = 0; i < dpm_table->mclk_table.count; i++) { - if (dpm_table->mclk_table.dpm_levels[i].enabled && - dpm_table->mclk_table.dpm_levels[i].value >= min_mclk) - *mclk_mask |= 1 << i; - } -} - -static int ci_set_power_profile_state(struct amdgpu_device *adev, - struct amd_pp_profile *request) -{ - struct ci_power_info *pi = ci_get_pi(adev); - int tmp_result, result = 0; - uint32_t sclk_mask = 0, mclk_mask = 0; - - tmp_result = ci_freeze_sclk_mclk_dpm(adev); - if (tmp_result) { - DRM_ERROR("Failed to freeze SCLK MCLK DPM!"); - result = tmp_result; - } - - tmp_result = ci_populate_requested_graphic_levels(adev, - request); - if (tmp_result) { - DRM_ERROR("Failed to populate requested graphic levels!"); - result = tmp_result; - } - - tmp_result = ci_unfreeze_sclk_mclk_dpm(adev); - if (tmp_result) { - DRM_ERROR("Failed to unfreeze SCLK MCLK DPM!"); - result = tmp_result; - } - - ci_find_min_clock_masks(adev, &sclk_mask, &mclk_mask, - request->min_sclk, request->min_mclk); - - if (sclk_mask) { - if (!pi->sclk_dpm_key_disabled) - amdgpu_ci_send_msg_to_smc_with_parameter( - adev, - PPSMC_MSG_SCLKDPM_SetEnabledMask, - pi->dpm_level_enable_mask. - sclk_dpm_enable_mask & - sclk_mask); - } - - if (mclk_mask) { - if (!pi->mclk_dpm_key_disabled) - amdgpu_ci_send_msg_to_smc_with_parameter( - adev, - PPSMC_MSG_MCLKDPM_SetEnabledMask, - pi->dpm_level_enable_mask. - mclk_dpm_enable_mask & - mclk_mask); - } - - - return result; -} - -static int ci_dpm_set_power_profile_state(void *handle, - struct amd_pp_profile *request) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - struct ci_power_info *pi = ci_get_pi(adev); - int ret = -1; - - if (!pi || !request) - return -EINVAL; - - if (adev->pm.dpm.forced_level != - AMD_DPM_FORCED_LEVEL_AUTO) - return -EINVAL; - - if (request->min_sclk || - request->min_mclk || - request->activity_threshold || - request->up_hyst || - request->down_hyst) { - if (request->type == AMD_PP_GFX_PROFILE) - memcpy(&pi->gfx_power_profile, request, - sizeof(struct amd_pp_profile)); - else if (request->type == AMD_PP_COMPUTE_PROFILE) - memcpy(&pi->compute_power_profile, request, - sizeof(struct amd_pp_profile)); - else - return -EINVAL; - - if (request->type == pi->current_power_profile) - ret = ci_set_power_profile_state( - adev, - request); - } else { - /* set power profile if it exists */ - switch (request->type) { - case AMD_PP_GFX_PROFILE: - ret = ci_set_power_profile_state( - adev, - &pi->gfx_power_profile); - break; - case AMD_PP_COMPUTE_PROFILE: - ret = ci_set_power_profile_state( - adev, - &pi->compute_power_profile); - break; - default: - return -EINVAL; - } - } - - if (!ret) - pi->current_power_profile = request->type; - - return 0; -} - -static int ci_dpm_reset_power_profile_state(void *handle, - struct amd_pp_profile *request) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - struct ci_power_info *pi = ci_get_pi(adev); - - if (!pi || !request) - return -EINVAL; - - if (request->type == AMD_PP_GFX_PROFILE) { - pi->gfx_power_profile = pi->default_gfx_power_profile; - return ci_dpm_set_power_profile_state(adev, - &pi->gfx_power_profile); - } else if (request->type == AMD_PP_COMPUTE_PROFILE) { - pi->compute_power_profile = - pi->default_compute_power_profile; - return ci_dpm_set_power_profile_state(adev, - &pi->compute_power_profile); - } else - return -EINVAL; -} - -static int ci_dpm_switch_power_profile(void *handle, - enum amd_pp_profile_type type) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - struct ci_power_info *pi = ci_get_pi(adev); - struct amd_pp_profile request = {0}; - - if (!pi) - return -EINVAL; - - if (pi->current_power_profile != type) { - request.type = type; - return ci_dpm_set_power_profile_state(adev, &request); - } - - return 0; -} - static int ci_dpm_read_sensor(void *handle, int idx, void *value, int *size) { @@ -7053,10 +6801,6 @@ const struct amd_pm_funcs ci_dpm_funcs = { .set_mclk_od = ci_dpm_set_mclk_od, .check_state_equal = ci_check_state_equal, .get_vce_clock_state = amdgpu_get_vce_clock_state, - .get_power_profile_state = ci_dpm_get_power_profile_state, - .set_power_profile_state = ci_dpm_set_power_profile_state, - .reset_power_profile_state = ci_dpm_reset_power_profile_state, - .switch_power_profile = ci_dpm_switch_power_profile, .read_sensor = ci_dpm_read_sensor, }; diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.h b/drivers/gpu/drm/amd/amdgpu/ci_dpm.h index 84cbc9c45f4d..91be2996ae7c 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.h @@ -295,13 +295,6 @@ struct ci_power_info { bool fan_is_controlled_by_smc; u32 t_min; u32 fan_ctrl_default_mode; - - /* power profile */ - struct amd_pp_profile gfx_power_profile; - struct amd_pp_profile compute_power_profile; - struct amd_pp_profile default_gfx_power_profile; - struct amd_pp_profile default_compute_power_profile; - enum amd_pp_profile_type current_power_profile; }; #define CISLANDS_VOLTAGE_CONTROL_NONE 0x0 diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 666a9e343270..e482daf394d3 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -252,13 +252,6 @@ struct amd_pm_funcs { int (*get_pp_table)(void *handle, char **table); int (*set_pp_table)(void *handle, const char *buf, size_t size); void (*debugfs_print_current_performance_level)(void *handle, struct seq_file *m); - - int (*reset_power_profile_state)(void *handle, - struct amd_pp_profile *request); - int (*get_power_profile_state)(void *handle, - struct amd_pp_profile *query); - int (*set_power_profile_state)(void *handle, - struct amd_pp_profile *request); int (*switch_power_profile)(void *handle, enum amd_pp_profile_type type); /* export to amdgpu */ diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 20ac0fc12483..a8705b5ad264 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -1018,58 +1018,6 @@ pp_dpm_get_vce_clock_state(void *handle, unsigned idx) return NULL; } -static int pp_dpm_reset_power_profile_state(void *handle, - struct amd_pp_profile *request) -{ - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; - - if (!request || pp_check(pp_handle)) - return -EINVAL; - - hwmgr = pp_handle->hwmgr; - - if (hwmgr->hwmgr_func->set_power_profile_state == NULL) { - pr_info("%s was not implemented.\n", __func__); - return 0; - } - - if (request->type == AMD_PP_GFX_PROFILE) { - hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile; - return hwmgr->hwmgr_func->set_power_profile_state(hwmgr, - &hwmgr->gfx_power_profile); - } else if (request->type == AMD_PP_COMPUTE_PROFILE) { - hwmgr->compute_power_profile = - hwmgr->default_compute_power_profile; - return hwmgr->hwmgr_func->set_power_profile_state(hwmgr, - &hwmgr->compute_power_profile); - } else - return -EINVAL; -} - -static int pp_dpm_get_power_profile_state(void *handle, - struct amd_pp_profile *query) -{ - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; - - if (!query || pp_check(pp_handle)) - return -EINVAL; - - hwmgr = pp_handle->hwmgr; - - if (query->type == AMD_PP_GFX_PROFILE) - memcpy(query, &hwmgr->gfx_power_profile, - sizeof(struct amd_pp_profile)); - else if (query->type == AMD_PP_COMPUTE_PROFILE) - memcpy(query, &hwmgr->compute_power_profile, - sizeof(struct amd_pp_profile)); - else - return -EINVAL; - - return 0; -} - static int pp_get_power_profile_mode(void *handle, char *buf) { struct pp_hwmgr *hwmgr; @@ -1128,65 +1076,6 @@ static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint3 return hwmgr->hwmgr_func->odn_edit_dpm_table(hwmgr, type, input, size); } -static int pp_dpm_set_power_profile_state(void *handle, - struct amd_pp_profile *request) -{ - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; - int ret = -1; - - if (!request || pp_check(pp_handle)) - return -EINVAL; - - hwmgr = pp_handle->hwmgr; - - if (hwmgr->hwmgr_func->set_power_profile_state == NULL) { - pr_info("%s was not implemented.\n", __func__); - return 0; - } - - if (request->min_sclk || - request->min_mclk || - request->activity_threshold || - request->up_hyst || - request->down_hyst) { - if (request->type == AMD_PP_GFX_PROFILE) - memcpy(&hwmgr->gfx_power_profile, request, - sizeof(struct amd_pp_profile)); - else if (request->type == AMD_PP_COMPUTE_PROFILE) - memcpy(&hwmgr->compute_power_profile, request, - sizeof(struct amd_pp_profile)); - else - return -EINVAL; - - if (request->type == hwmgr->current_power_profile) - ret = hwmgr->hwmgr_func->set_power_profile_state( - hwmgr, - request); - } else { - /* set power profile if it exists */ - switch (request->type) { - case AMD_PP_GFX_PROFILE: - ret = hwmgr->hwmgr_func->set_power_profile_state( - hwmgr, - &hwmgr->gfx_power_profile); - break; - case AMD_PP_COMPUTE_PROFILE: - ret = hwmgr->hwmgr_func->set_power_profile_state( - hwmgr, - &hwmgr->compute_power_profile); - break; - default: - return -EINVAL; - } - } - - if (!ret) - hwmgr->current_power_profile = request->type; - - return 0; -} - static int pp_dpm_switch_power_profile(void *handle, enum amd_pp_profile_type type) { @@ -1584,9 +1473,6 @@ const struct amd_pm_funcs pp_dpm_funcs = { .set_mclk_od = pp_dpm_set_mclk_od, .read_sensor = pp_dpm_read_sensor, .get_vce_clock_state = pp_dpm_get_vce_clock_state, - .reset_power_profile_state = pp_dpm_reset_power_profile_state, - .get_power_profile_state = pp_dpm_get_power_profile_state, - .set_power_profile_state = pp_dpm_set_power_profile_state, .switch_power_profile = pp_dpm_switch_power_profile, .set_clockgating_by_smu = pp_set_clockgating_by_smu, .notify_smu_memory_info = pp_dpm_notify_smu_memory_info, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c index 33480deb64b9..f06f8f42e776 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c @@ -128,23 +128,6 @@ int phm_force_dpm_levels(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level return ret; } -int phm_reset_power_profile_state(struct pp_hwmgr *hwmgr) -{ - int ret = 0; - - if (hwmgr->hwmgr_func->set_power_profile_state) { - if (hwmgr->current_power_profile == AMD_PP_GFX_PROFILE) - ret = hwmgr->hwmgr_func->set_power_profile_state( - hwmgr, - &hwmgr->gfx_power_profile); - else if (hwmgr->current_power_profile == AMD_PP_COMPUTE_PROFILE) - ret = hwmgr->hwmgr_func->set_power_profile_state( - hwmgr, - &hwmgr->compute_power_profile); - } - return ret; -} - int phm_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, struct pp_power_state *adjusted_ps, const struct pp_power_state *current_ps) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c index 95ab772e0c3e..ed3bd1502c0d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c @@ -247,8 +247,6 @@ int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip, if (!phm_force_dpm_levels(hwmgr, hwmgr->request_dpm_level)) hwmgr->dpm_level = hwmgr->request_dpm_level; - phm_reset_power_profile_state(hwmgr); - return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 3f894bc85c25..58e2e0a10b3d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -4584,82 +4584,6 @@ static int smu7_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type return 0; } -static void smu7_find_min_clock_masks(struct pp_hwmgr *hwmgr, - uint32_t *sclk_mask, uint32_t *mclk_mask, - uint32_t min_sclk, uint32_t min_mclk) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - struct smu7_dpm_table *dpm_table = &(data->dpm_table); - uint32_t i; - - for (i = 0; i < dpm_table->sclk_table.count; i++) { - if (dpm_table->sclk_table.dpm_levels[i].enabled && - dpm_table->sclk_table.dpm_levels[i].value >= min_sclk) - *sclk_mask |= 1 << i; - } - - for (i = 0; i < dpm_table->mclk_table.count; i++) { - if (dpm_table->mclk_table.dpm_levels[i].enabled && - dpm_table->mclk_table.dpm_levels[i].value >= min_mclk) - *mclk_mask |= 1 << i; - } -} - -static int smu7_set_power_profile_state(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - int tmp_result, result = 0; - uint32_t sclk_mask = 0, mclk_mask = 0; - - if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_AUTO) - return -EINVAL; - - if (smum_is_dpm_running(hwmgr)) { - if (!data->sclk_dpm_key_disabled) - smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel); - - if (!data->mclk_dpm_key_disabled) - smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel); - } - - tmp_result = smum_populate_requested_graphic_levels(hwmgr, request); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to populate requested graphic levels!", - result = tmp_result); - - if (smum_is_dpm_running(hwmgr)) { - if (!data->sclk_dpm_key_disabled) - smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel); - - if (!data->mclk_dpm_key_disabled) - smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel); - } - - smu7_find_min_clock_masks(hwmgr, &sclk_mask, &mclk_mask, - request->min_sclk, request->min_mclk); - - if (sclk_mask) { - if (!data->sclk_dpm_key_disabled) - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SCLKDPM_SetEnabledMask, - data->dpm_level_enable_mask. - sclk_dpm_enable_mask & - sclk_mask); - } - - if (mclk_mask) { - if (!data->mclk_dpm_key_disabled) - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_MCLKDPM_SetEnabledMask, - data->dpm_level_enable_mask. - mclk_dpm_enable_mask & - mclk_mask); - } - - return result; -} - static int smu7_notify_cac_buffer_info(struct pp_hwmgr *hwmgr, uint32_t virtual_addr_low, uint32_t virtual_addr_hi, @@ -5104,7 +5028,6 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .get_clock_by_type = smu7_get_clock_by_type, .read_sensor = smu7_read_sensor, .dynamic_state_management_disable = smu7_disable_dpm_tasks, - .set_power_profile_state = smu7_set_power_profile_state, .avfs_control = smu7_avfs_control, .disable_smc_firmware_ctf = smu7_thermal_disable_alert, .start_thermal_controller = smu7_start_thermal_controller, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 1596fd84627a..d90a0f1dbb55 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -2408,34 +2408,6 @@ static int vega10_populate_and_upload_avfs_fuse_override(struct pp_hwmgr *hwmgr) return result; } -static int vega10_save_default_power_profile(struct pp_hwmgr *hwmgr) -{ - struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); - struct vega10_single_dpm_table *dpm_table = &(data->dpm_table.gfx_table); - uint32_t min_level; - - hwmgr->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE; - hwmgr->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE; - - /* Optimize compute power profile: Use only highest - * 2 power levels (if more than 2 are available) - */ - if (dpm_table->count > 2) - min_level = dpm_table->count - 2; - else if (dpm_table->count == 2) - min_level = 1; - else - min_level = 0; - - hwmgr->default_compute_power_profile.min_sclk = - dpm_table->dpm_levels[min_level].value; - - hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->compute_power_profile = hwmgr->default_compute_power_profile; - - return 0; -} - /** * Initializes the SMC table and uploads it * @@ -2579,7 +2551,6 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(!result, "Attempt to enable AVFS feature Failed!", return result); vega10_acg_enable(hwmgr); - vega10_save_default_power_profile(hwmgr); return 0; } @@ -4754,62 +4725,6 @@ static int vega10_power_off_asic(struct pp_hwmgr *hwmgr) return result; } -static void vega10_find_min_clock_index(struct pp_hwmgr *hwmgr, - uint32_t *sclk_idx, uint32_t *mclk_idx, - uint32_t min_sclk, uint32_t min_mclk) -{ - struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); - struct vega10_dpm_table *dpm_table = &(data->dpm_table); - uint32_t i; - - for (i = 0; i < dpm_table->gfx_table.count; i++) { - if (dpm_table->gfx_table.dpm_levels[i].enabled && - dpm_table->gfx_table.dpm_levels[i].value >= min_sclk) { - *sclk_idx = i; - break; - } - } - - for (i = 0; i < dpm_table->mem_table.count; i++) { - if (dpm_table->mem_table.dpm_levels[i].enabled && - dpm_table->mem_table.dpm_levels[i].value >= min_mclk) { - *mclk_idx = i; - break; - } - } -} - -static int vega10_set_power_profile_state(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request) -{ - struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); - uint32_t sclk_idx = ~0, mclk_idx = ~0; - - if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_AUTO) - return -EINVAL; - - vega10_find_min_clock_index(hwmgr, &sclk_idx, &mclk_idx, - request->min_sclk, request->min_mclk); - - if (sclk_idx != ~0) { - if (!data->registry_data.sclk_dpm_key_disabled) - smum_send_msg_to_smc_with_parameter( - hwmgr, - PPSMC_MSG_SetSoftMinGfxclkByIndex, - sclk_idx); - } - - if (mclk_idx != ~0) { - if (!data->registry_data.mclk_dpm_key_disabled) - smum_send_msg_to_smc_with_parameter( - hwmgr, - PPSMC_MSG_SetSoftMinUclkByIndex, - mclk_idx); - } - - return 0; -} - static int vega10_get_sclk_od(struct pp_hwmgr *hwmgr) { struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); @@ -5103,7 +5018,6 @@ static const struct pp_hwmgr_func vega10_hwmgr_funcs = { vega10_check_smc_update_required_for_display_configuration, .power_off_asic = vega10_power_off_asic, .disable_smc_firmware_ctf = vega10_thermal_disable_alert, - .set_power_profile_state = vega10_set_power_profile_state, .get_sclk_od = vega10_get_sclk_od, .set_sclk_od = vega10_set_sclk_od, .get_mclk_od = vega10_get_mclk_od, diff --git a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h index 6f528e662a6f..b366a5bd2d81 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h @@ -448,6 +448,5 @@ extern int phm_display_clock_voltage_request(struct pp_hwmgr *hwmgr, extern int phm_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks); extern int phm_disable_smc_firmware_ctf(struct pp_hwmgr *hwmgr); -extern int phm_reset_power_profile_state(struct pp_hwmgr *hwmgr); #endif /* _HARDWARE_MANAGER_H_ */ diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 2dc2e2c20a3a..65224dbb550d 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -236,8 +236,6 @@ struct pp_smumgr_func { uint32_t (*get_offsetof)(uint32_t type, uint32_t member); uint32_t (*get_mac_definition)(uint32_t value); bool (*is_dpm_running)(struct pp_hwmgr *hwmgr); - int (*populate_requested_graphic_levels)(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request); bool (*is_hw_avfs_present)(struct pp_hwmgr *hwmgr); int (*update_dpm_settings)(struct pp_hwmgr *hwmgr, void *profile_setting); }; @@ -329,8 +327,6 @@ struct pp_hwmgr_func { int (*get_mclk_od)(struct pp_hwmgr *hwmgr); int (*set_mclk_od)(struct pp_hwmgr *hwmgr, uint32_t value); int (*read_sensor)(struct pp_hwmgr *hwmgr, int idx, void *value, int *size); - int (*set_power_profile_state)(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request); int (*avfs_control)(struct pp_hwmgr *hwmgr, bool enable); int (*disable_smc_firmware_ctf)(struct pp_hwmgr *hwmgr); int (*set_active_display_count)(struct pp_hwmgr *hwmgr, uint32_t count); @@ -753,11 +749,6 @@ struct pp_hwmgr { uint32_t feature_mask; /* UMD Pstate */ - struct amd_pp_profile gfx_power_profile; - struct amd_pp_profile compute_power_profile; - struct amd_pp_profile default_gfx_power_profile; - struct amd_pp_profile default_compute_power_profile; - enum amd_pp_profile_type current_power_profile; bool en_umd_pstate; uint32_t power_profile_mode; uint32_t default_power_profile_mode; diff --git a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h index e05a57e2eedc..e1f6e830c84d 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h @@ -129,9 +129,6 @@ extern uint32_t smum_get_mac_definition(struct pp_hwmgr *hwmgr, uint32_t value); extern bool smum_is_dpm_running(struct pp_hwmgr *hwmgr); -extern int smum_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request); - extern bool smum_is_hw_avfs_present(struct pp_hwmgr *hwmgr); extern int smum_update_dpm_settings(struct pp_hwmgr *hwmgr, void *profile_setting); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c index 179d00cd5514..5d6dfdfbbbb6 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c @@ -2766,32 +2766,6 @@ static bool ci_is_dpm_running(struct pp_hwmgr *hwmgr) return ci_is_smc_ram_running(hwmgr); } -static int ci_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request) -{ - struct ci_smumgr *smu_data = (struct ci_smumgr *) - (hwmgr->smu_backend); - struct SMU7_Discrete_GraphicsLevel *levels = - smu_data->smc_state_table.GraphicsLevel; - uint32_t array = smu_data->dpm_table_start + - offsetof(SMU7_Discrete_DpmTable, GraphicsLevel); - uint32_t array_size = sizeof(struct SMU7_Discrete_GraphicsLevel) * - SMU7_MAX_LEVELS_GRAPHICS; - uint32_t i; - - for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { - levels[i].ActivityLevel = - cpu_to_be16(request->activity_threshold); - levels[i].EnabledForActivity = 1; - levels[i].UpH = request->up_hyst; - levels[i].DownH = request->down_hyst; - } - - return ci_copy_bytes_to_smc(hwmgr, array, (uint8_t *)levels, - array_size, SMC_RAM_END); -} - - static int ci_smu_init(struct pp_hwmgr *hwmgr) { struct ci_smumgr *ci_priv = NULL; @@ -2936,6 +2910,5 @@ const struct pp_smumgr_func ci_smu_funcs = { .get_mac_definition = ci_get_mac_definition, .initialize_mc_reg_table = ci_initialize_mc_reg_table, .is_dpm_running = ci_is_dpm_running, - .populate_requested_graphic_levels = ci_populate_requested_graphic_levels, .update_dpm_settings = ci_update_dpm_settings, }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c index fc556f0af021..0b2b5d155e5e 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c @@ -1960,44 +1960,6 @@ static int fiji_init_arb_table_index(struct pp_hwmgr *hwmgr) smu_data->smu7_data.arb_table_start, tmp, SMC_RAM_END); } -static int fiji_save_default_power_profile(struct pp_hwmgr *hwmgr) -{ - struct fiji_smumgr *data = (struct fiji_smumgr *)(hwmgr->smu_backend); - struct SMU73_Discrete_GraphicsLevel *levels = - data->smc_state_table.GraphicsLevel; - unsigned min_level = 1; - - hwmgr->default_gfx_power_profile.activity_threshold = - be16_to_cpu(levels[0].ActivityLevel); - hwmgr->default_gfx_power_profile.up_hyst = levels[0].UpHyst; - hwmgr->default_gfx_power_profile.down_hyst = levels[0].DownHyst; - hwmgr->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE; - - hwmgr->default_compute_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE; - - /* Workaround compute SDMA instability: disable lowest SCLK - * DPM level. Optimize compute power profile: Use only highest - * 2 power levels (if more than 2 are available), Hysteresis: - * 0ms up, 5ms down - */ - if (data->smc_state_table.GraphicsDpmLevelCount > 2) - min_level = data->smc_state_table.GraphicsDpmLevelCount - 2; - else if (data->smc_state_table.GraphicsDpmLevelCount == 2) - min_level = 1; - else - min_level = 0; - hwmgr->default_compute_power_profile.min_sclk = - be32_to_cpu(levels[min_level].SclkFrequency); - hwmgr->default_compute_power_profile.up_hyst = 0; - hwmgr->default_compute_power_profile.down_hyst = 5; - - hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->compute_power_profile = hwmgr->default_compute_power_profile; - - return 0; -} - static int fiji_setup_dpm_led_config(struct pp_hwmgr *hwmgr) { pp_atomctrl_voltage_table param_led_dpm; @@ -2238,8 +2200,6 @@ static int fiji_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(0 == result, "Failed to setup dpm led config", return result); - fiji_save_default_power_profile(hwmgr); - return 0; } @@ -2694,31 +2654,6 @@ static bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr) ? true : false; } -static int fiji_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request) -{ - struct fiji_smumgr *smu_data = (struct fiji_smumgr *) - (hwmgr->smu_backend); - struct SMU73_Discrete_GraphicsLevel *levels = - smu_data->smc_state_table.GraphicsLevel; - uint32_t array = smu_data->smu7_data.dpm_table_start + - offsetof(SMU73_Discrete_DpmTable, GraphicsLevel); - uint32_t array_size = sizeof(struct SMU73_Discrete_GraphicsLevel) * - SMU73_MAX_LEVELS_GRAPHICS; - uint32_t i; - - for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { - levels[i].ActivityLevel = - cpu_to_be16(request->activity_threshold); - levels[i].EnabledForActivity = 1; - levels[i].UpHyst = request->up_hyst; - levels[i].DownHyst = request->down_hyst; - } - - return smu7_copy_bytes_to_smc(hwmgr, array, (uint8_t *)levels, - array_size, SMC_RAM_END); -} - static int fiji_update_dpm_settings(struct pp_hwmgr *hwmgr, void *profile_setting) { @@ -2838,7 +2773,6 @@ const struct pp_smumgr_func fiji_smu_funcs = { .get_mac_definition = fiji_get_mac_definition, .initialize_mc_reg_table = fiji_initialize_mc_reg_table, .is_dpm_running = fiji_is_dpm_running, - .populate_requested_graphic_levels = fiji_populate_requested_graphic_levels, .is_hw_avfs_present = fiji_is_hw_avfs_present, .update_dpm_settings = fiji_update_dpm_settings, }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c index 757824875935..632d1ca2f69c 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c @@ -1840,42 +1840,6 @@ static void polaris10_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) } -static void polaris10_save_default_power_profile(struct pp_hwmgr *hwmgr) -{ - struct polaris10_smumgr *data = (struct polaris10_smumgr *)(hwmgr->smu_backend); - struct SMU74_Discrete_GraphicsLevel *levels = - data->smc_state_table.GraphicsLevel; - unsigned min_level = 1; - - hwmgr->default_gfx_power_profile.activity_threshold = - be16_to_cpu(levels[0].ActivityLevel); - hwmgr->default_gfx_power_profile.up_hyst = levels[0].UpHyst; - hwmgr->default_gfx_power_profile.down_hyst = levels[0].DownHyst; - hwmgr->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE; - - hwmgr->default_compute_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE; - - /* Workaround compute SDMA instability: disable lowest SCLK - * DPM level. Optimize compute power profile: Use only highest - * 2 power levels (if more than 2 are available), Hysteresis: - * 0ms up, 5ms down - */ - if (data->smc_state_table.GraphicsDpmLevelCount > 2) - min_level = data->smc_state_table.GraphicsDpmLevelCount - 2; - else if (data->smc_state_table.GraphicsDpmLevelCount == 2) - min_level = 1; - else - min_level = 0; - hwmgr->default_compute_power_profile.min_sclk = - be32_to_cpu(levels[min_level].SclkSetting.SclkFrequency); - hwmgr->default_compute_power_profile.up_hyst = 0; - hwmgr->default_compute_power_profile.down_hyst = 5; - - hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->compute_power_profile = hwmgr->default_compute_power_profile; -} - static int polaris10_init_smc_table(struct pp_hwmgr *hwmgr) { int result; @@ -2090,8 +2054,6 @@ static int polaris10_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(0 == result, "Failed to populate PM fuses to SMC memory!", return result); - polaris10_save_default_power_profile(hwmgr); - return 0; } @@ -2550,31 +2512,6 @@ static bool polaris10_is_dpm_running(struct pp_hwmgr *hwmgr) ? true : false; } -static int polaris10_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request) -{ - struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *) - (hwmgr->smu_backend); - struct SMU74_Discrete_GraphicsLevel *levels = - smu_data->smc_state_table.GraphicsLevel; - uint32_t array = smu_data->smu7_data.dpm_table_start + - offsetof(SMU74_Discrete_DpmTable, GraphicsLevel); - uint32_t array_size = sizeof(struct SMU74_Discrete_GraphicsLevel) * - SMU74_MAX_LEVELS_GRAPHICS; - uint32_t i; - - for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { - levels[i].ActivityLevel = - cpu_to_be16(request->activity_threshold); - levels[i].EnabledForActivity = 1; - levels[i].UpHyst = request->up_hyst; - levels[i].DownHyst = request->down_hyst; - } - - return smu7_copy_bytes_to_smc(hwmgr, array, (uint8_t *)levels, - array_size, SMC_RAM_END); -} - static int polaris10_update_dpm_settings(struct pp_hwmgr *hwmgr, void *profile_setting) { @@ -2693,7 +2630,6 @@ const struct pp_smumgr_func polaris10_smu_funcs = { .populate_all_memory_levels = polaris10_populate_all_memory_levels, .get_mac_definition = polaris10_get_mac_definition, .is_dpm_running = polaris10_is_dpm_running, - .populate_requested_graphic_levels = polaris10_populate_requested_graphic_levels, .is_hw_avfs_present = polaris10_is_hw_avfs_present, .update_dpm_settings = polaris10_update_dpm_settings, }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c index 1ce4959cba6e..43b1010ae7ee 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c @@ -236,16 +236,6 @@ bool smum_is_dpm_running(struct pp_hwmgr *hwmgr) return true; } -int smum_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request) -{ - if (hwmgr->smumgr_funcs->populate_requested_graphic_levels) - return hwmgr->smumgr_funcs->populate_requested_graphic_levels( - hwmgr, request); - - return 0; -} - bool smum_is_hw_avfs_present(struct pp_hwmgr *hwmgr) { if (hwmgr->smumgr_funcs->is_hw_avfs_present) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c index 86fb7709a1c4..39d6f4ef96ce 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c @@ -2256,42 +2256,6 @@ static void tonga_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) smu_data->power_tune_defaults = &tonga_power_tune_data_set_array[0]; } -static void tonga_save_default_power_profile(struct pp_hwmgr *hwmgr) -{ - struct tonga_smumgr *data = (struct tonga_smumgr *)(hwmgr->smu_backend); - struct SMU72_Discrete_GraphicsLevel *levels = - data->smc_state_table.GraphicsLevel; - unsigned min_level = 1; - - hwmgr->default_gfx_power_profile.activity_threshold = - be16_to_cpu(levels[0].ActivityLevel); - hwmgr->default_gfx_power_profile.up_hyst = levels[0].UpHyst; - hwmgr->default_gfx_power_profile.down_hyst = levels[0].DownHyst; - hwmgr->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE; - - hwmgr->default_compute_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE; - - /* Workaround compute SDMA instability: disable lowest SCLK - * DPM level. Optimize compute power profile: Use only highest - * 2 power levels (if more than 2 are available), Hysteresis: - * 0ms up, 5ms down - */ - if (data->smc_state_table.GraphicsDpmLevelCount > 2) - min_level = data->smc_state_table.GraphicsDpmLevelCount - 2; - else if (data->smc_state_table.GraphicsDpmLevelCount == 2) - min_level = 1; - else - min_level = 0; - hwmgr->default_compute_power_profile.min_sclk = - be32_to_cpu(levels[min_level].SclkFrequency); - hwmgr->default_compute_power_profile.up_hyst = 0; - hwmgr->default_compute_power_profile.down_hyst = 5; - - hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->compute_power_profile = hwmgr->default_compute_power_profile; -} - static int tonga_init_smc_table(struct pp_hwmgr *hwmgr) { int result; @@ -2533,8 +2497,6 @@ static int tonga_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE((!result), "Failed to populate initialize MC Reg table !", return result); - tonga_save_default_power_profile(hwmgr); - return 0; } @@ -3252,31 +3214,6 @@ static bool tonga_is_dpm_running(struct pp_hwmgr *hwmgr) ? true : false; } -static int tonga_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request) -{ - struct tonga_smumgr *smu_data = (struct tonga_smumgr *) - (hwmgr->smu_backend); - struct SMU72_Discrete_GraphicsLevel *levels = - smu_data->smc_state_table.GraphicsLevel; - uint32_t array = smu_data->smu7_data.dpm_table_start + - offsetof(SMU72_Discrete_DpmTable, GraphicsLevel); - uint32_t array_size = sizeof(struct SMU72_Discrete_GraphicsLevel) * - SMU72_MAX_LEVELS_GRAPHICS; - uint32_t i; - - for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { - levels[i].ActivityLevel = - cpu_to_be16(request->activity_threshold); - levels[i].EnabledForActivity = 1; - levels[i].UpHyst = request->up_hyst; - levels[i].DownHyst = request->down_hyst; - } - - return smu7_copy_bytes_to_smc(hwmgr, array, (uint8_t *)levels, - array_size, SMC_RAM_END); -} - static int tonga_update_dpm_settings(struct pp_hwmgr *hwmgr, void *profile_setting) { @@ -3395,6 +3332,5 @@ const struct pp_smumgr_func tonga_smu_funcs = { .get_mac_definition = tonga_get_mac_definition, .initialize_mc_reg_table = tonga_initialize_mc_reg_table, .is_dpm_running = tonga_is_dpm_running, - .populate_requested_graphic_levels = tonga_populate_requested_graphic_levels, .update_dpm_settings = tonga_update_dpm_settings, }; -- cgit v1.2.3 From 590347e4000356f55eb10b03ced2686bd74dab40 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Feb 2018 16:56:16 +0100 Subject: dm bufio: avoid false-positive Wmaybe-uninitialized warning gcc-6.3 and earlier show a new warning after a seemingly unrelated change to the arm64 PAGE_KERNEL definition: In file included from drivers/md/dm-bufio.c:14:0: drivers/md/dm-bufio.c: In function 'alloc_buffer': include/linux/sched/mm.h:182:56: warning: 'noio_flag' may be used uninitialized in this function [-Wmaybe-uninitialized] current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags; ^ The same warning happened earlier on linux-3.18 for MIPS and I did a workaround for that, but now it's come back. gcc-7 and newer are apparently smart enough to figure this out, and other architectures don't show it, so the best I could come up with is to rework the caller slightly in a way that makes it obvious enough to all arm64 compilers what is happening here. Fixes: 41acec624087 ("arm64: kpti: Make use of nG dependent on arm64_kernel_unmapped_at_el0()") Link: https://patchwork.kernel.org/patch/9692829/ Cc: stable@vger.kernel.org Signed-off-by: Arnd Bergmann [snitzer: moved declarations inside conditional, altered vmalloc return] Signed-off-by: Mike Snitzer --- drivers/md/dm-bufio.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 414c9af54ded..aa2032fa80d4 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -386,9 +386,6 @@ static void __cache_size_refresh(void) static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, enum data_mode *data_mode) { - unsigned noio_flag; - void *ptr; - if (c->block_size <= DM_BUFIO_BLOCK_SIZE_SLAB_LIMIT) { *data_mode = DATA_MODE_SLAB; return kmem_cache_alloc(DM_BUFIO_CACHE(c), gfp_mask); @@ -412,16 +409,15 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, * all allocations done by this process (including pagetables) are done * as if GFP_NOIO was specified. */ + if (gfp_mask & __GFP_NORETRY) { + unsigned noio_flag = memalloc_noio_save(); + void *ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL); - if (gfp_mask & __GFP_NORETRY) - noio_flag = memalloc_noio_save(); - - ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL); - - if (gfp_mask & __GFP_NORETRY) memalloc_noio_restore(noio_flag); + return ptr; + } - return ptr; + return __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL); } /* -- cgit v1.2.3 From 519049afead4f7c3e6446028c41e99fde958cc04 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 22 Feb 2018 13:31:20 -0500 Subject: dm: use blkdev_get rather than bdgrab when issuing pass-through ioctl Otherwise an underlying device's teardown (e.g. SCSI) may race with the DM ioctl or persistent reservation and result in dereferencing driver memory that gets freed when the underlying device's final blkdev_put() occurs. bdgrab() only increases the refcount for the block_device's inode to ensure the block_device struct itself will not be freed, but does not guarantee the block_device will remain associated with the gendisk or its storage. Cc: stable@vger.kernel.org # 4.8+ Reported-by: David Jeffery Suggested-by: David Jeffery Reviewed-by: Ben Marzinski Signed-off-by: Mike Snitzer --- drivers/md/dm.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 68136806d365..45328d8b2859 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -458,9 +458,11 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) return dm_get_geometry(md, geo); } -static int dm_grab_bdev_for_ioctl(struct mapped_device *md, - struct block_device **bdev, - fmode_t *mode) +static char *_dm_claim_ptr = "I belong to device-mapper"; + +static int dm_get_bdev_for_ioctl(struct mapped_device *md, + struct block_device **bdev, + fmode_t *mode) { struct dm_target *tgt; struct dm_table *map; @@ -490,6 +492,10 @@ retry: goto out; bdgrab(*bdev); + r = blkdev_get(*bdev, *mode, _dm_claim_ptr); + if (r < 0) + goto out; + dm_put_live_table(md, srcu_idx); return r; @@ -508,7 +514,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, struct mapped_device *md = bdev->bd_disk->private_data; int r; - r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); + r = dm_get_bdev_for_ioctl(md, &bdev, &mode); if (r < 0) return r; @@ -528,7 +534,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, r = __blkdev_driver_ioctl(bdev, mode, cmd, arg); out: - bdput(bdev); + blkdev_put(bdev, mode); return r; } @@ -708,14 +714,13 @@ static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU) static int open_table_device(struct table_device *td, dev_t dev, struct mapped_device *md) { - static char *_claim_ptr = "I belong to device-mapper"; struct block_device *bdev; int r; BUG_ON(td->dm_dev.bdev); - bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _claim_ptr); + bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _dm_claim_ptr); if (IS_ERR(bdev)) return PTR_ERR(bdev); @@ -3011,7 +3016,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type, fmode_t mode; int r; - r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); + r = dm_get_bdev_for_ioctl(md, &bdev, &mode); if (r < 0) return r; @@ -3021,7 +3026,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type, else r = -EOPNOTSUPP; - bdput(bdev); + blkdev_put(bdev, mode); return r; } @@ -3032,7 +3037,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type) fmode_t mode; int r; - r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); + r = dm_get_bdev_for_ioctl(md, &bdev, &mode); if (r < 0) return r; @@ -3042,7 +3047,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type) else r = -EOPNOTSUPP; - bdput(bdev); + blkdev_put(bdev, mode); return r; } @@ -3054,7 +3059,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key, fmode_t mode; int r; - r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); + r = dm_get_bdev_for_ioctl(md, &bdev, &mode); if (r < 0) return r; @@ -3064,7 +3069,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key, else r = -EOPNOTSUPP; - bdput(bdev); + blkdev_put(bdev, mode); return r; } @@ -3075,7 +3080,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key) fmode_t mode; int r; - r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); + r = dm_get_bdev_for_ioctl(md, &bdev, &mode); if (r < 0) return r; @@ -3085,7 +3090,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key) else r = -EOPNOTSUPP; - bdput(bdev); + blkdev_put(bdev, mode); return r; } -- cgit v1.2.3 From da1e148803e0b98961599b0295418bb7a8fc79f3 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Tue, 27 Feb 2018 21:58:59 +0100 Subject: dm raid: fix incorrect sync_ratio when degraded MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream commit 4102d9de6d375 ("dm raid: fix rs_get_progress() synchronization state/ratio") in combination with commit 7c29744ecce ("dm raid: simplify rs_get_progress()") introduced a regression by incorrectly reporting a sync_ratio of 0 for degraded raid sets. This caused lvm2 to fail to repair raid legs automatically. Fix by identifying the degraded state by checking the MD_RECOVERY_INTR flag and returning mddev->recovery_cp in case it is set. MD sets recovery = [ MD_RECOVERY_RECOVER MD_RECOVERY_INTR MD_RECOVERY_NEEDED ] when a RAID member fails. It then shuts down any sync thread that is running and leaves us with all MD_RECOVERY_* flags cleared. The bug occurs if a status is requested in the short time it takes to shut down any sync thread and clear the flags, because we were keying in on the MD_RECOVERY_NEEDED - understanding it to be the initial phase of a “recover” sync thread. However, this is an incorrect interpretation if MD_RECOVERY_INTR is also set. This also explains why the bug only happened when automatic repair was enabled and not a normal ‘manual’ method. It is impossible to react quick enough to hit the problematic window without it being automated. Fix passes automatic repair tests. Fixes: 7c29744ecce ("dm raid: simplify rs_get_progress()") Signed-off-by: Jonathan Brassow Signed-off-by: Heinz Mauelshagen Signed-off-by: Mike Snitzer --- drivers/md/dm-raid.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 7ef469e902c6..c1d1034ff7b7 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -3408,9 +3408,10 @@ static sector_t rs_get_progress(struct raid_set *rs, unsigned long recovery, set_bit(RT_FLAG_RS_IN_SYNC, &rs->runtime_flags); } else { - if (test_bit(MD_RECOVERY_NEEDED, &recovery) || - test_bit(MD_RECOVERY_RESHAPE, &recovery) || - test_bit(MD_RECOVERY_RUNNING, &recovery)) + if (!test_bit(MD_RECOVERY_INTR, &recovery) && + (test_bit(MD_RECOVERY_NEEDED, &recovery) || + test_bit(MD_RECOVERY_RESHAPE, &recovery) || + test_bit(MD_RECOVERY_RUNNING, &recovery))) r = mddev->curr_resync_completed; else r = mddev->recovery_cp; -- cgit v1.2.3 From 99243b922c9ddb4976b8db2eeffb0aed6e06c6f9 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 26 Feb 2018 15:22:32 -0500 Subject: dm table: fix "nvme" test The strncmp function should compare 4 bytes. Fixes: 22c11858e8002 ("dm: introduce DM_TYPE_NVME_BIO_BASED") Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer --- drivers/md/dm-table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 5fe7ec356c33..30b3294a8778 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1755,7 +1755,7 @@ static int device_no_partial_completion(struct dm_target *ti, struct dm_dev *dev char b[BDEVNAME_SIZE]; /* For now, NVMe devices are the only devices of this class */ - return (strncmp(bdevname(dev->bdev, b), "nvme", 3) == 0); + return (strncmp(bdevname(dev->bdev, b), "nvme", 4) == 0); } static bool dm_table_does_not_support_partial_completion(struct dm_table *t) -- cgit v1.2.3 From 8d47e65948ddea4398892946d9e50778a316b397 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Mon, 5 Mar 2018 14:10:11 -0500 Subject: dm mpath: remove unnecessary NVMe branching in favor of scsi_dh checks This eliminates the "queue_mode" configuration's "nvme" mode. There wasn't anything NVMe-specific about that mode. It was named "nvme" because it was a short name for the mode. But the entire point of the mode was to optimize the multipath target for underlying devices that are _not_ SCSI-based. Devices that aren't SCSI have no need for the various SCSI device handler (scsi_dh) specific code in DM multipath. But rather than narrowly define this scsi_dh vs not branching in terms of "nvme": invert the logic so that we're just checking whether a multipath device is layered on SCSI devices with scsi_dh attached. This allows any future storage technology to avoid scsi_dh specific code in the multipath target too. Fixes: 848b8aefd4 ("dm mpath: optimize NVMe bio-based support") Suggested-by: Mikulas Patocka Signed-off-by: Mike Snitzer --- drivers/md/dm-mpath.c | 66 ++++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 7d3e572072f5..3fde9e9faddd 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -211,25 +212,13 @@ static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m) else m->queue_mode = DM_TYPE_REQUEST_BASED; - } else if (m->queue_mode == DM_TYPE_BIO_BASED || - m->queue_mode == DM_TYPE_NVME_BIO_BASED) { + } else if (m->queue_mode == DM_TYPE_BIO_BASED) { INIT_WORK(&m->process_queued_bios, process_queued_bios); - - if (m->queue_mode == DM_TYPE_BIO_BASED) { - /* - * bio-based doesn't support any direct scsi_dh management; - * it just discovers if a scsi_dh is attached. - */ - set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); - } - } - - if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) { - set_bit(MPATHF_QUEUE_IO, &m->flags); - atomic_set(&m->pg_init_in_progress, 0); - atomic_set(&m->pg_init_count, 0); - m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT; - init_waitqueue_head(&m->pg_init_wait); + /* + * bio-based doesn't support any direct scsi_dh management; + * it just discovers if a scsi_dh is attached. + */ + set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); } dm_table_set_type(ti->table, m->queue_mode); @@ -337,14 +326,12 @@ static void __switch_pg(struct multipath *m, struct priority_group *pg) { m->current_pg = pg; - if (m->queue_mode == DM_TYPE_NVME_BIO_BASED) - return; - /* Must we initialise the PG first, and queue I/O till it's ready? */ if (m->hw_handler_name) { set_bit(MPATHF_PG_INIT_REQUIRED, &m->flags); set_bit(MPATHF_QUEUE_IO, &m->flags); } else { + /* FIXME: not needed if no scsi_dh is attached */ clear_bit(MPATHF_PG_INIT_REQUIRED, &m->flags); clear_bit(MPATHF_QUEUE_IO, &m->flags); } @@ -385,8 +372,7 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes) unsigned bypassed = 1; if (!atomic_read(&m->nr_valid_paths)) { - if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) - clear_bit(MPATHF_QUEUE_IO, &m->flags); + clear_bit(MPATHF_QUEUE_IO, &m->flags); goto failed; } @@ -599,7 +585,7 @@ static struct pgpath *__map_bio(struct multipath *m, struct bio *bio) return pgpath; } -static struct pgpath *__map_bio_nvme(struct multipath *m, struct bio *bio) +static struct pgpath *__map_bio_fast(struct multipath *m, struct bio *bio) { struct pgpath *pgpath; unsigned long flags; @@ -634,8 +620,8 @@ static int __multipath_map_bio(struct multipath *m, struct bio *bio, { struct pgpath *pgpath; - if (m->queue_mode == DM_TYPE_NVME_BIO_BASED) - pgpath = __map_bio_nvme(m, bio); + if (!m->hw_handler_name) + pgpath = __map_bio_fast(m, bio); else pgpath = __map_bio(m, bio); @@ -675,8 +661,7 @@ static void process_queued_io_list(struct multipath *m) { if (m->queue_mode == DM_TYPE_MQ_REQUEST_BASED) dm_mq_kick_requeue_list(dm_table_get_md(m->ti->table)); - else if (m->queue_mode == DM_TYPE_BIO_BASED || - m->queue_mode == DM_TYPE_NVME_BIO_BASED) + else if (m->queue_mode == DM_TYPE_BIO_BASED) queue_work(kmultipathd, &m->process_queued_bios); } @@ -838,6 +823,16 @@ retain: */ kfree(m->hw_handler_name); m->hw_handler_name = attached_handler_name; + + /* + * Init fields that are only used when a scsi_dh is attached + */ + if (!test_and_set_bit(MPATHF_QUEUE_IO, &m->flags)) { + atomic_set(&m->pg_init_in_progress, 0); + atomic_set(&m->pg_init_count, 0); + m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT; + init_waitqueue_head(&m->pg_init_wait); + } } } @@ -873,6 +868,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps int r; struct pgpath *p; struct multipath *m = ti->private; + struct scsi_device *sdev; /* we need at least a path arg */ if (as->argc < 1) { @@ -891,7 +887,9 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps goto bad; } - if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) { + sdev = scsi_device_from_queue(bdev_get_queue(p->path.dev->bdev)); + if (sdev) { + put_device(&sdev->sdev_gendev); INIT_DELAYED_WORK(&p->activate_path, activate_path_work); r = setup_scsi_dh(p->path.dev->bdev, m, &ti->error); if (r) { @@ -1001,8 +999,7 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m) if (!hw_argc) return 0; - if (m->queue_mode == DM_TYPE_BIO_BASED || - m->queue_mode == DM_TYPE_NVME_BIO_BASED) { + if (m->queue_mode == DM_TYPE_BIO_BASED) { dm_consume_args(as, hw_argc); DMERR("bio-based multipath doesn't allow hardware handler args"); return 0; @@ -1091,8 +1088,6 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) if (!strcasecmp(queue_mode_name, "bio")) m->queue_mode = DM_TYPE_BIO_BASED; - else if (!strcasecmp(queue_mode_name, "nvme")) - m->queue_mode = DM_TYPE_NVME_BIO_BASED; else if (!strcasecmp(queue_mode_name, "rq")) m->queue_mode = DM_TYPE_REQUEST_BASED; else if (!strcasecmp(queue_mode_name, "mq")) @@ -1193,7 +1188,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv) ti->num_discard_bios = 1; ti->num_write_same_bios = 1; ti->num_write_zeroes_bios = 1; - if (m->queue_mode == DM_TYPE_BIO_BASED || m->queue_mode == DM_TYPE_NVME_BIO_BASED) + if (m->queue_mode == DM_TYPE_BIO_BASED) ti->per_io_data_size = multipath_per_bio_data_size(); else ti->per_io_data_size = sizeof(struct dm_mpath_io); @@ -1730,9 +1725,6 @@ static void multipath_status(struct dm_target *ti, status_type_t type, case DM_TYPE_BIO_BASED: DMEMIT("queue_mode bio "); break; - case DM_TYPE_NVME_BIO_BASED: - DMEMIT("queue_mode nvme "); - break; case DM_TYPE_MQ_REQUEST_BASED: DMEMIT("queue_mode mq "); break; -- cgit v1.2.3 From c934edadcc7a64e399942ae34b912939057a77a7 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Mon, 5 Mar 2018 15:26:06 -0500 Subject: dm table: allow upgrade from bio-based to specialized bio-based variant In practice this is really only meaningful in the context of the DM multipath target (which uses dm_table_set_type() to set the type of device DM should create via its "queue_mode" option). So this change allows a DM multipath device with "queue_mode bio" to be upgraded from DM_TYPE_BIO_BASED to DM_TYPE_NVME_BIO_BASED -- iff the underlying device(s) are NVMe. DM_TYPE_NVME_BIO_BASED is just a DM core implementation detail that allows for NVMe-specific optimizations (e.g. use direct_make_request instead of generic_make_request). If in the future there is no benefit or need to distinguish NVMe vs not: then it will be removed. Signed-off-by: Mike Snitzer --- drivers/md/dm-table.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 30b3294a8778..7eb3e2a3c07d 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -942,17 +942,12 @@ static int dm_table_determine_type(struct dm_table *t) if (t->type != DM_TYPE_NONE) { /* target already set the table's type */ - if (t->type == DM_TYPE_BIO_BASED) - return 0; - else if (t->type == DM_TYPE_NVME_BIO_BASED) { - if (!dm_table_does_not_support_partial_completion(t)) { - DMERR("nvme bio-based is only possible with devices" - " that don't support partial completion"); - return -EINVAL; - } - /* Fallthru, also verify all devices are blk-mq */ + if (t->type == DM_TYPE_BIO_BASED) { + /* possibly upgrade to a variant of bio-based */ + goto verify_bio_based; } BUG_ON(t->type == DM_TYPE_DAX_BIO_BASED); + BUG_ON(t->type == DM_TYPE_NVME_BIO_BASED); goto verify_rq_based; } @@ -985,6 +980,7 @@ static int dm_table_determine_type(struct dm_table *t) } if (bio_based) { +verify_bio_based: /* We must use this table as bio-based */ t->type = DM_TYPE_BIO_BASED; if (dm_table_supports_dax(t) || -- cgit v1.2.3 From 11052696fdbf673d422e92e6149eaad78ae0c252 Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Mon, 5 Mar 2018 10:50:08 +0200 Subject: RDMA/qedr: Fix ipv6 destination address resolution The wrong parameter was passed to dst_neigh_lookup Signed-off-by: Michal Kalderon Signed-off-by: Ariel Elior Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/qedr/qedr_iw_cm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/qedr_iw_cm.c b/drivers/infiniband/hw/qedr/qedr_iw_cm.c index 478b7317b80a..1fc97157def8 100644 --- a/drivers/infiniband/hw/qedr/qedr_iw_cm.c +++ b/drivers/infiniband/hw/qedr/qedr_iw_cm.c @@ -458,8 +458,7 @@ qedr_addr6_resolve(struct qedr_dev *dev, } return -EINVAL; } - neigh = dst_neigh_lookup(dst, &dst_in); - + neigh = dst_neigh_lookup(dst, &fl6.daddr); if (neigh) { rcu_read_lock(); if (neigh->nud_state & NUD_VALID) { -- cgit v1.2.3 From ea0ed47803df93d0904b838d6b5afceec3ad0ba4 Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Mon, 5 Mar 2018 10:50:09 +0200 Subject: RDMA/qedr: Fix iWARP connect with port mapper Fix iWARP connect and listen to use the mapped port for ipv4 and ipv6. Without this fixed, running on a server that has iwpmd enabled will not use the correct port Signed-off-by: Michal Kalderon Signed-off-by: Ariel Elior Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/qedr/qedr_iw_cm.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/qedr_iw_cm.c b/drivers/infiniband/hw/qedr/qedr_iw_cm.c index 1fc97157def8..26dc374787f7 100644 --- a/drivers/infiniband/hw/qedr/qedr_iw_cm.c +++ b/drivers/infiniband/hw/qedr/qedr_iw_cm.c @@ -493,10 +493,14 @@ int qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) qp = idr_find(&dev->qpidr, conn_param->qpn); - laddr = (struct sockaddr_in *)&cm_id->local_addr; - raddr = (struct sockaddr_in *)&cm_id->remote_addr; - laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr; - raddr6 = (struct sockaddr_in6 *)&cm_id->remote_addr; + laddr = (struct sockaddr_in *)&cm_id->m_local_addr; + raddr = (struct sockaddr_in *)&cm_id->m_remote_addr; + laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr; + raddr6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr; + + DP_DEBUG(dev, QEDR_MSG_IWARP, "MAPPED %d %d\n", + ntohs(((struct sockaddr_in *)&cm_id->remote_addr)->sin_port), + ntohs(raddr->sin_port)); DP_DEBUG(dev, QEDR_MSG_IWARP, "Connect source address: %pISpc, remote address: %pISpc\n", @@ -598,8 +602,8 @@ int qedr_iw_create_listen(struct iw_cm_id *cm_id, int backlog) int rc; int i; - laddr = (struct sockaddr_in *)&cm_id->local_addr; - laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr; + laddr = (struct sockaddr_in *)&cm_id->m_local_addr; + laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr; DP_DEBUG(dev, QEDR_MSG_IWARP, "Create Listener address: %pISpc\n", &cm_id->local_addr); -- cgit v1.2.3 From e3fd112cbf21d049faf64ba1471d72b93c22109a Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Mon, 5 Mar 2018 10:50:10 +0200 Subject: RDMA/qedr: Fix kernel panic when running fio over NFSoRDMA Race in qedr_poll_cq, lastest_cqe wasn't protected by lock, leading to a case where two context's accessing poll_cq at the same time lead to one of them having a pointer to an old latest_cqe and reading an invalid cqe element Signed-off-by: Amit Radzi Signed-off-by: Michal Kalderon Signed-off-by: Ariel Elior Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/qedr/verbs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 53f00dbf313f..102b9e0efe9a 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -3724,7 +3724,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) { struct qedr_dev *dev = get_qedr_dev(ibcq->device); struct qedr_cq *cq = get_qedr_cq(ibcq); - union rdma_cqe *cqe = cq->latest_cqe; + union rdma_cqe *cqe; u32 old_cons, new_cons; unsigned long flags; int update = 0; @@ -3741,6 +3741,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) return qedr_gsi_poll_cq(ibcq, num_entries, wc); spin_lock_irqsave(&cq->cq_lock, flags); + cqe = cq->latest_cqe; old_cons = qed_chain_get_cons_idx_u32(&cq->pbl); while (num_entries && is_valid_cqe(cq, cqe)) { struct qedr_qp *qp; -- cgit v1.2.3 From 551e1c67b4207455375a2e7a285dea1c7e8fc361 Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Mon, 5 Mar 2018 10:50:11 +0200 Subject: RDMA/qedr: Fix iWARP write and send with immediate iWARP does not support RDMA WRITE or SEND with immediate data. Driver should check this before submitting to FW and return an immediate error Signed-off-by: Michal Kalderon Signed-off-by: Ariel Elior Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/qedr/verbs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 102b9e0efe9a..875b17272d65 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -3034,6 +3034,11 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, switch (wr->opcode) { case IB_WR_SEND_WITH_IMM: + if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { + rc = -EINVAL; + *bad_wr = wr; + break; + } wqe->req_type = RDMA_SQ_REQ_TYPE_SEND_WITH_IMM; swqe = (struct rdma_sq_send_wqe_1st *)wqe; swqe->wqe_size = 2; @@ -3075,6 +3080,11 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, break; case IB_WR_RDMA_WRITE_WITH_IMM: + if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { + rc = -EINVAL; + *bad_wr = wr; + break; + } wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_WR_WITH_IMM; rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe; -- cgit v1.2.3 From 864449eea7c600596e305ffdc4a6a846414b222c Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 26 Feb 2018 15:26:01 +0100 Subject: scsi: mpt3sas: Do not mark fw_event workqueue as WQ_MEM_RECLAIM The firmware event workqueue should not be marked as WQ_MEM_RECLAIM as it's doesn't need to make forward progress under memory pressure. In the current state it will result in a deadlock if the device had been forcefully removed. Cc: Sreekanth Reddy Cc: Suganath Prabu Subramani Acked-by: Sreekanth Reddy Signed-off-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index c2ea13c7e37e..a1cb0236c550 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -10558,7 +10558,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), "fw_event_%s%d", ioc->driver_name, ioc->id); ioc->firmware_event_thread = alloc_ordered_workqueue( - ioc->firmware_event_name, WQ_MEM_RECLAIM); + ioc->firmware_event_name, 0); if (!ioc->firmware_event_thread) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); -- cgit v1.2.3 From 4b433924b2755a94f99258c178684a0e05c344de Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Fri, 2 Mar 2018 07:19:28 +0900 Subject: scsi: sd_zbc: Fix potential memory leak Rework sd_zbc_check_zone_size() to avoid a memory leak due to an early return if sd_zbc_report_zones() fails. Reported-by: David.butterfield Signed-off-by: Damien Le Moal Cc: stable@vger.kernel.org Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/sd_zbc.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 27793b9f54c0..9049a189c8e5 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -486,7 +486,7 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf) */ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp) { - u64 zone_blocks; + u64 zone_blocks = 0; sector_t block = 0; unsigned char *buf; unsigned char *rec; @@ -504,10 +504,8 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp) /* Do a report zone to get the same field */ ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0); - if (ret) { - zone_blocks = 0; - goto out; - } + if (ret) + goto out_free; same = buf[4] & 0x0f; if (same > 0) { @@ -547,7 +545,7 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp) ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, block); if (ret) - return ret; + goto out_free; } } while (block < sdkp->capacity); @@ -555,35 +553,32 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp) zone_blocks = sdkp->zone_blocks; out: - kfree(buf); - if (!zone_blocks) { if (sdkp->first_scan) sd_printk(KERN_NOTICE, sdkp, "Devices with non constant zone " "size are not supported\n"); - return -ENODEV; - } - - if (!is_power_of_2(zone_blocks)) { + ret = -ENODEV; + } else if (!is_power_of_2(zone_blocks)) { if (sdkp->first_scan) sd_printk(KERN_NOTICE, sdkp, "Devices with non power of 2 zone " "size are not supported\n"); - return -ENODEV; - } - - if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) { + ret = -ENODEV; + } else if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) { if (sdkp->first_scan) sd_printk(KERN_NOTICE, sdkp, "Zone size too large\n"); - return -ENODEV; + ret = -ENODEV; + } else { + sdkp->zone_blocks = zone_blocks; + sdkp->zone_shift = ilog2(zone_blocks); } - sdkp->zone_blocks = zone_blocks; - sdkp->zone_shift = ilog2(zone_blocks); +out_free: + kfree(buf); - return 0; + return ret; } static int sd_zbc_setup(struct scsi_disk *sdkp) -- cgit v1.2.3 From 6a2cf8d3663e13e19af636c2a8d92e766261dc45 Mon Sep 17 00:00:00 2001 From: Bill Kuzeja Date: Mon, 5 Mar 2018 00:02:55 -0500 Subject: scsi: qla2xxx: Fix crashes in qla2x00_probe_one on probe failure Because of the shifting around of code in qla2x00_probe_one recently, failures during adapter initialization can lead to problems, i.e. NULL pointer crashes and doubly freed data structures which cause eventual panics. This V2 version makes the relevant memory free routines idempotent, so repeat calls won't cause any harm. I also removed the problematic probe_init_failed exit point as it is not needed. Fixes: d64d6c5671db ("scsi: qla2xxx: Fix NULL pointer crash due to probe failure") Signed-off-by: Bill Kuzeja Acked-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 59 +++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 285911e81728..5c5dcca4d1da 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -454,7 +454,7 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, ha->req_q_map[0] = req; set_bit(0, ha->rsp_qid_map); set_bit(0, ha->req_qid_map); - return 1; + return 0; fail_qpair_map: kfree(ha->base_qpair); @@ -471,6 +471,9 @@ fail_req_map: static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req) { + if (!ha->req_q_map) + return; + if (IS_QLAFX00(ha)) { if (req && req->ring_fx00) dma_free_coherent(&ha->pdev->dev, @@ -481,14 +484,17 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req) (req->length + 1) * sizeof(request_t), req->ring, req->dma); - if (req) + if (req) { kfree(req->outstanding_cmds); - - kfree(req); + kfree(req); + } } static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp) { + if (!ha->rsp_q_map) + return; + if (IS_QLAFX00(ha)) { if (rsp && rsp->ring) dma_free_coherent(&ha->pdev->dev, @@ -499,7 +505,8 @@ static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp) (rsp->length + 1) * sizeof(response_t), rsp->ring, rsp->dma); } - kfree(rsp); + if (rsp) + kfree(rsp); } static void qla2x00_free_queues(struct qla_hw_data *ha) @@ -1723,6 +1730,8 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) struct qla_tgt_cmd *cmd; uint8_t trace = 0; + if (!ha->req_q_map) + return; spin_lock_irqsave(qp->qp_lock_ptr, flags); req = qp->req; for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) { @@ -3095,14 +3104,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) /* Set up the irqs */ ret = qla2x00_request_irqs(ha, rsp); if (ret) - goto probe_hw_failed; + goto probe_failed; /* Alloc arrays of request and response ring ptrs */ - if (!qla2x00_alloc_queues(ha, req, rsp)) { + if (qla2x00_alloc_queues(ha, req, rsp)) { ql_log(ql_log_fatal, base_vha, 0x003d, "Failed to allocate memory for queue pointers..." "aborting.\n"); - goto probe_init_failed; + goto probe_failed; } if (ha->mqenable && shost_use_blk_mq(host)) { @@ -3387,15 +3396,6 @@ skip_dpc: return 0; -probe_init_failed: - qla2x00_free_req_que(ha, req); - ha->req_q_map[0] = NULL; - clear_bit(0, ha->req_qid_map); - qla2x00_free_rsp_que(ha, rsp); - ha->rsp_q_map[0] = NULL; - clear_bit(0, ha->rsp_qid_map); - ha->max_req_queues = ha->max_rsp_queues = 0; - probe_failed: if (base_vha->timer_active) qla2x00_stop_timer(base_vha); @@ -4508,11 +4508,17 @@ qla2x00_mem_free(struct qla_hw_data *ha) if (ha->init_cb) dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, ha->init_cb_dma); - vfree(ha->optrom_buffer); - kfree(ha->nvram); - kfree(ha->npiv_info); - kfree(ha->swl); - kfree(ha->loop_id_map); + + if (ha->optrom_buffer) + vfree(ha->optrom_buffer); + if (ha->nvram) + kfree(ha->nvram); + if (ha->npiv_info) + kfree(ha->npiv_info); + if (ha->swl) + kfree(ha->swl); + if (ha->loop_id_map) + kfree(ha->loop_id_map); ha->srb_mempool = NULL; ha->ctx_mempool = NULL; @@ -4528,6 +4534,15 @@ qla2x00_mem_free(struct qla_hw_data *ha) ha->ex_init_cb_dma = 0; ha->async_pd = NULL; ha->async_pd_dma = 0; + ha->loop_id_map = NULL; + ha->npiv_info = NULL; + ha->optrom_buffer = NULL; + ha->swl = NULL; + ha->nvram = NULL; + ha->mctp_dump = NULL; + ha->dcbx_tlv = NULL; + ha->xgmac_data = NULL; + ha->sfp_data = NULL; ha->s_dma_pool = NULL; ha->dl_dma_pool = NULL; -- cgit v1.2.3 From 20bd1d026aacc5399464f8328f305985c493cde3 Mon Sep 17 00:00:00 2001 From: Jeremy Cline Date: Tue, 6 Mar 2018 21:47:32 +0000 Subject: scsi: sd: Keep disk read-only when re-reading partition If the read-only flag is true on a SCSI disk, re-reading the partition table sets the flag back to false. To observe this bug, you can run: 1. blockdev --setro /dev/sda 2. blockdev --rereadpt /dev/sda 3. blockdev --getro /dev/sda This commit reads the disk's old state and combines it with the device disk-reported state rather than unconditionally marking it as RW. Reported-by: Li Ning Signed-off-by: Jeremy Cline Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index ab75ebd518a7..3b45f7fc5620 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2624,6 +2624,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) int res; struct scsi_device *sdp = sdkp->device; struct scsi_mode_data data; + int disk_ro = get_disk_ro(sdkp->disk); int old_wp = sdkp->write_prot; set_disk_ro(sdkp->disk, 0); @@ -2664,7 +2665,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) "Test WP failed, assume Write Enabled\n"); } else { sdkp->write_prot = ((data.device_specific & 0x80) != 0); - set_disk_ro(sdkp->disk, sdkp->write_prot); + set_disk_ro(sdkp->disk, sdkp->write_prot || disk_ro); if (sdkp->first_scan || old_wp != sdkp->write_prot) { sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n", sdkp->write_prot ? "on" : "off"); -- cgit v1.2.3 From 0077416a3d529baccbe07ab3242e8db541cfadf6 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Mon, 5 Mar 2018 20:09:45 +0200 Subject: IB/mlx4: Fix corruption of RoCEv2 IPv4 GIDs When using IPv4 addresses in RoCEv2, the GID format for the mapped IPv4 address should be: ::ffff:<4-byte IPv4 address>. In the cited commit, IPv4 mapped IPV6 addresses had the 3 upper dwords zeroed out by memset, which resulted in deleting the ffff field. However, since procedure ipv6_addr_v4mapped() already verifies that the gid has format ::ffff:, no change is needed for the gid, and the memset can simply be removed. Fixes: 7e57b85c444c ("IB/mlx4: Add support for setting RoCEv2 gids in hardware") Reviewed-by: Moni Shoua Signed-off-by: Jack Morgenstein Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx4/main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 8d2ee9322f2e..90790818d655 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -219,8 +219,6 @@ static int mlx4_ib_update_gids_v1_v2(struct gid_entry *gids, gid_tbl[i].version = 2; if (!ipv6_addr_v4mapped((struct in6_addr *)&gids[i].gid)) gid_tbl[i].type = 1; - else - memset(&gid_tbl[i].gid, 0, 12); } } -- cgit v1.2.3 From a18177925c252da7801149abe217c05b80884798 Mon Sep 17 00:00:00 2001 From: Jack M Date: Mon, 5 Mar 2018 20:09:46 +0200 Subject: IB/mlx4: Include GID type when deleting GIDs from HW table under RoCE The commit cited below added a gid_type field (RoCEv1 or RoCEv2) to GID properties. When adding GIDs, this gid_type field was copied over to the hardware gid table. However, when deleting GIDs, the gid_type field was not copied over to the hardware gid table. As a result, when running RoCEv2, all RoCEv2 gids in the hardware gid table were set to type RoCEv1 when any gid was deleted. This problem would persist until the next gid was added (which would again restore the gid_type field for all the gids in the hardware gid table). Fix this by copying over the gid_type field to the hardware gid table when deleting gids, so that the gid_type of all remaining gids is preserved when a gid is deleted. Fixes: b699a859d17b ("IB/mlx4: Add gid_type to GID properties") Reviewed-by: Moni Shoua Signed-off-by: Jack Morgenstein Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx4/main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 90790818d655..5a0e4fc4785a 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -364,8 +364,13 @@ static int mlx4_ib_del_gid(struct ib_device *device, if (!gids) { ret = -ENOMEM; } else { - for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) - memcpy(&gids[i].gid, &port_gid_table->gids[i].gid, sizeof(union ib_gid)); + for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) { + memcpy(&gids[i].gid, + &port_gid_table->gids[i].gid, + sizeof(union ib_gid)); + gids[i].gid_type = + port_gid_table->gids[i].gid_type; + } } } spin_unlock_bh(&iboe->lock); -- cgit v1.2.3 From 210b1f78076f88cad25b333fffafbac6ae870fcc Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Mon, 5 Mar 2018 20:09:47 +0200 Subject: IB/mlx5: When not in dual port RoCE mode, use provided port as native The series that introduced dual port RoCE mode assumed that we don't have a dual port HCA that use the mlx5 driver, this is not the case for Connect-IB HCAs. This reasoning led to assigning 1 as the native port index which causes issue when the second port is used. For example query_pkey() when called on the second port will return values of the first port. Make sure that we assign the right port index as the native port index. Fixes: 32f69e4be269 ("{net, IB}/mlx5: Manage port association for multiport RoCE") Reviewed-by: Daniel Jurgens Signed-off-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index bab38c6647d7..033b6af90de9 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -245,12 +245,16 @@ struct mlx5_core_dev *mlx5_ib_get_native_port_mdev(struct mlx5_ib_dev *ibdev, struct mlx5_ib_multiport_info *mpi; struct mlx5_ib_port *port; + if (!mlx5_core_mp_enabled(ibdev->mdev) || + ll != IB_LINK_LAYER_ETHERNET) { + if (native_port_num) + *native_port_num = ib_port_num; + return ibdev->mdev; + } + if (native_port_num) *native_port_num = 1; - if (!mlx5_core_mp_enabled(ibdev->mdev) || ll != IB_LINK_LAYER_ETHERNET) - return ibdev->mdev; - port = &ibdev->port[ib_port_num - 1]; if (!port) return NULL; -- cgit v1.2.3 From 5d414b178e950ce9685c253994cc730893d5d887 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 6 Mar 2018 13:00:31 +0300 Subject: IB/mlx5: Fix an error code in __mlx5_ib_modify_qp() "err" is either zero or possibly uninitialized here. It should be -EINVAL. Fixes: 427c1e7bcd7e ("{IB, net}/mlx5: Move the modify QP operation table to mlx5_ib") Signed-off-by: Dan Carpenter Acked-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/qp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index e8d7eaf0670c..36197fbac63a 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -3100,8 +3100,10 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, goto out; if (mlx5_cur >= MLX5_QP_NUM_STATE || mlx5_new >= MLX5_QP_NUM_STATE || - !optab[mlx5_cur][mlx5_new]) + !optab[mlx5_cur][mlx5_new]) { + err = -EINVAL; goto out; + } op = optab[mlx5_cur][mlx5_new]; optpar = ib_mask_to_mlx5_opt(attr_mask); -- cgit v1.2.3 From d3b9e8ad425cfd5b9116732e057f1b48e4d3bcb8 Mon Sep 17 00:00:00 2001 From: Max Gurtovoy Date: Mon, 5 Mar 2018 20:09:48 +0200 Subject: RDMA/core: Reduce poll batch for direct cq polling Fix warning limit for kernel stack consumption: drivers/infiniband/core/cq.c: In function 'ib_process_cq_direct': drivers/infiniband/core/cq.c:78:1: error: the frame size of 1032 bytes is larger than 1024 bytes [-Werror=frame-larger-than=] Using smaller ib_wc array on the stack brings us comfortably below that limit again. Fixes: 246d8b184c10 ("IB/cq: Don't force IB_POLL_DIRECT poll context for ib_process_cq_direct") Reported-by: Arnd Bergmann Reviewed-by: Sergey Gorenko Signed-off-by: Max Gurtovoy Signed-off-by: Leon Romanovsky Reviewed-by: Bart Van Assche Acked-by: Arnd Bergmann Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cq.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/cq.c b/drivers/infiniband/core/cq.c index bc79ca8215d7..af5ad6a56ae4 100644 --- a/drivers/infiniband/core/cq.c +++ b/drivers/infiniband/core/cq.c @@ -17,6 +17,7 @@ /* # of WCs to poll for with a single call to ib_poll_cq */ #define IB_POLL_BATCH 16 +#define IB_POLL_BATCH_DIRECT 8 /* # of WCs to iterate over before yielding */ #define IB_POLL_BUDGET_IRQ 256 @@ -25,18 +26,18 @@ #define IB_POLL_FLAGS \ (IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS) -static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) +static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *wcs, + int batch) { int i, n, completed = 0; - struct ib_wc *wcs = poll_wc ? : cq->wc; /* * budget might be (-1) if the caller does not * want to bound this call, thus we need unsigned * minimum here. */ - while ((n = ib_poll_cq(cq, min_t(u32, IB_POLL_BATCH, - budget - completed), wcs)) > 0) { + while ((n = ib_poll_cq(cq, min_t(u32, batch, + budget - completed), wcs)) > 0) { for (i = 0; i < n; i++) { struct ib_wc *wc = &wcs[i]; @@ -48,8 +49,7 @@ static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) completed += n; - if (n != IB_POLL_BATCH || - (budget != -1 && completed >= budget)) + if (n != batch || (budget != -1 && completed >= budget)) break; } @@ -72,9 +72,9 @@ static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) */ int ib_process_cq_direct(struct ib_cq *cq, int budget) { - struct ib_wc wcs[IB_POLL_BATCH]; + struct ib_wc wcs[IB_POLL_BATCH_DIRECT]; - return __ib_process_cq(cq, budget, wcs); + return __ib_process_cq(cq, budget, wcs, IB_POLL_BATCH_DIRECT); } EXPORT_SYMBOL(ib_process_cq_direct); @@ -88,7 +88,7 @@ static int ib_poll_handler(struct irq_poll *iop, int budget) struct ib_cq *cq = container_of(iop, struct ib_cq, iop); int completed; - completed = __ib_process_cq(cq, budget, NULL); + completed = __ib_process_cq(cq, budget, cq->wc, IB_POLL_BATCH); if (completed < budget) { irq_poll_complete(&cq->iop); if (ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) @@ -108,7 +108,8 @@ static void ib_cq_poll_work(struct work_struct *work) struct ib_cq *cq = container_of(work, struct ib_cq, work); int completed; - completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, NULL); + completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, cq->wc, + IB_POLL_BATCH); if (completed >= IB_POLL_BUDGET_WORKQUEUE || ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) queue_work(ib_comp_wq, &cq->work); -- cgit v1.2.3 From 942c9b6ca8de5b7ad675e9b2e0e964449c10c18a Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 5 Mar 2018 21:49:28 -0800 Subject: RDMA/bnxt_re: Avoid Hard lockup during error CQE processing Hitting the following hardlockup due to a race condition in error CQE processing. [26146.879798] bnxt_en 0000:04:00.0: QPLIB: FP: CQ Processed Req [26146.886346] bnxt_en 0000:04:00.0: QPLIB: wr_id[1251] = 0x0 with status 0xa [26156.350935] NMI watchdog: Watchdog detected hard LOCKUP on cpu 4 [26156.357470] Modules linked in: nfsd auth_rpcgss nfs_acl lockd grace [26156.447957] CPU: 4 PID: 3413 Comm: kworker/4:1H Kdump: loaded [26156.457994] Hardware name: Dell Inc. PowerEdge R430/0CN7X8, [26156.466390] Workqueue: ib-comp-wq ib_cq_poll_work [ib_core] [26156.472639] Call Trace: [26156.475379] [] dump_stack+0x19/0x1b [26156.481833] [] watchdog_overflow_callback+0x135/0x140 [26156.489341] [] __perf_event_overflow+0x57/0x100 [26156.496256] [] perf_event_overflow+0x14/0x20 [26156.502887] [] intel_pmu_handle_irq+0x220/0x510 [26156.509813] [] perf_event_nmi_handler+0x31/0x50 [26156.516738] [] nmi_handle.isra.0+0x8c/0x150 [26156.523273] [] do_nmi+0x218/0x460 [26156.528834] [] end_repeat_nmi+0x1e/0x7e [26156.534980] [] ? native_queued_spin_lock_slowpath+0x1d0/0x200 [26156.543268] [] ? native_queued_spin_lock_slowpath+0x1d0/0x200 [26156.551556] [] ? native_queued_spin_lock_slowpath+0x1d0/0x200 [26156.559842] [] queued_spin_lock_slowpath+0xb/0xf [26156.567555] [] _raw_spin_lock+0x20/0x30 [26156.573696] [] bnxt_qplib_lock_buddy_cq+0x31/0x40 [bnxt_re] [26156.581789] [] bnxt_qplib_poll_cq+0x43a/0xf10 [bnxt_re] [26156.589493] [] bnxt_re_poll_cq+0x9b/0x760 [bnxt_re] The issue happens if RQ poll_cq or SQ poll_cq or Async error event tries to put the error QP in flush list. Since SQ and RQ of each error qp are added to two different flush list, we need to protect it using locks of corresponding CQs. Difference in order of acquiring the lock in SQ poll_cq and RQ poll_cq can cause a hard lockup. Revisits the locking strategy and removes the usage of qplib_cq.hwq.lock. Instead of this lock, introduces qplib_cq.flush_lock to handle addition/deletion of QPs in flush list. Also, always invoke the flush_lock in order (SQ CQ lock first and then RQ CQ lock) to avoid any potential deadlock. Other than the poll_cq context, the movement of QP to/from flush list can be done in modify_qp context or from an async error event from HW. Synchronize these operations using the bnxt_re verbs layer CQ locks. To achieve this, adds a call back to the HW abstraction layer(qplib) to bnxt_re ib_verbs layer in case of async error event. Also, removes the buddy cq functions as it is no longer required. Signed-off-by: Sriharsha Basavapatna Signed-off-by: Somnath Kotur Signed-off-by: Devesh Sharma Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 11 ++- drivers/infiniband/hw/bnxt_re/ib_verbs.h | 3 + drivers/infiniband/hw/bnxt_re/main.c | 7 ++ drivers/infiniband/hw/bnxt_re/qplib_fp.c | 109 +++++++---------------------- drivers/infiniband/hw/bnxt_re/qplib_fp.h | 12 ++++ drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 3 +- 6 files changed, 55 insertions(+), 90 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 755f1ccd82bb..0dd75f449872 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -785,7 +785,7 @@ int bnxt_re_query_ah(struct ib_ah *ib_ah, struct rdma_ah_attr *ah_attr) return 0; } -static unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp) +unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp) __acquires(&qp->scq->cq_lock) __acquires(&qp->rcq->cq_lock) { unsigned long flags; @@ -799,8 +799,8 @@ static unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp) return flags; } -static void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, - unsigned long flags) +void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, + unsigned long flags) __releases(&qp->scq->cq_lock) __releases(&qp->rcq->cq_lock) { if (qp->rcq != qp->scq) @@ -1606,6 +1606,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, int status; union ib_gid sgid; struct ib_gid_attr sgid_attr; + unsigned int flags; u8 nw_type; qp->qplib_qp.modify_flags = 0; @@ -1634,14 +1635,18 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, dev_dbg(rdev_to_dev(rdev), "Move QP = %p to flush list\n", qp); + flags = bnxt_re_lock_cqs(qp); bnxt_qplib_add_flush_qp(&qp->qplib_qp); + bnxt_re_unlock_cqs(qp, flags); } if (!qp->sumem && qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_RESET) { dev_dbg(rdev_to_dev(rdev), "Move QP = %p out of flush list\n", qp); + flags = bnxt_re_lock_cqs(qp); bnxt_qplib_clean_qp(&qp->qplib_qp); + bnxt_re_unlock_cqs(qp, flags); } } if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) { diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h index b88a48d43a9d..e62b7c2c7da6 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h @@ -222,4 +222,7 @@ struct ib_ucontext *bnxt_re_alloc_ucontext(struct ib_device *ibdev, struct ib_udata *udata); int bnxt_re_dealloc_ucontext(struct ib_ucontext *context); int bnxt_re_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); + +unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp); +void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, unsigned long flags); #endif /* __BNXT_RE_IB_VERBS_H__ */ diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 604c805ceaa7..f6e361750466 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -730,6 +730,13 @@ static int bnxt_re_handle_qp_async_event(struct creq_qp_event *qp_event, struct bnxt_re_qp *qp) { struct ib_event event; + unsigned int flags; + + if (qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR) { + flags = bnxt_re_lock_cqs(qp); + bnxt_qplib_add_flush_qp(&qp->qplib_qp); + bnxt_re_unlock_cqs(qp, flags); + } memset(&event, 0, sizeof(event)); if (qp->qplib_qp.srq) { diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index 3ea5b9624f6b..06b42c880fd4 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -88,75 +88,35 @@ static void __bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp) } } -void bnxt_qplib_acquire_cq_locks(struct bnxt_qplib_qp *qp, - unsigned long *flags) - __acquires(&qp->scq->hwq.lock) __acquires(&qp->rcq->hwq.lock) +static void bnxt_qplib_acquire_cq_flush_locks(struct bnxt_qplib_qp *qp, + unsigned long *flags) + __acquires(&qp->scq->flush_lock) __acquires(&qp->rcq->flush_lock) { - spin_lock_irqsave(&qp->scq->hwq.lock, *flags); + spin_lock_irqsave(&qp->scq->flush_lock, *flags); if (qp->scq == qp->rcq) - __acquire(&qp->rcq->hwq.lock); + __acquire(&qp->rcq->flush_lock); else - spin_lock(&qp->rcq->hwq.lock); + spin_lock(&qp->rcq->flush_lock); } -void bnxt_qplib_release_cq_locks(struct bnxt_qplib_qp *qp, - unsigned long *flags) - __releases(&qp->scq->hwq.lock) __releases(&qp->rcq->hwq.lock) +static void bnxt_qplib_release_cq_flush_locks(struct bnxt_qplib_qp *qp, + unsigned long *flags) + __releases(&qp->scq->flush_lock) __releases(&qp->rcq->flush_lock) { if (qp->scq == qp->rcq) - __release(&qp->rcq->hwq.lock); + __release(&qp->rcq->flush_lock); else - spin_unlock(&qp->rcq->hwq.lock); - spin_unlock_irqrestore(&qp->scq->hwq.lock, *flags); -} - -static struct bnxt_qplib_cq *bnxt_qplib_find_buddy_cq(struct bnxt_qplib_qp *qp, - struct bnxt_qplib_cq *cq) -{ - struct bnxt_qplib_cq *buddy_cq = NULL; - - if (qp->scq == qp->rcq) - buddy_cq = NULL; - else if (qp->scq == cq) - buddy_cq = qp->rcq; - else - buddy_cq = qp->scq; - return buddy_cq; -} - -static void bnxt_qplib_lock_buddy_cq(struct bnxt_qplib_qp *qp, - struct bnxt_qplib_cq *cq) - __acquires(&buddy_cq->hwq.lock) -{ - struct bnxt_qplib_cq *buddy_cq = NULL; - - buddy_cq = bnxt_qplib_find_buddy_cq(qp, cq); - if (!buddy_cq) - __acquire(&cq->hwq.lock); - else - spin_lock(&buddy_cq->hwq.lock); -} - -static void bnxt_qplib_unlock_buddy_cq(struct bnxt_qplib_qp *qp, - struct bnxt_qplib_cq *cq) - __releases(&buddy_cq->hwq.lock) -{ - struct bnxt_qplib_cq *buddy_cq = NULL; - - buddy_cq = bnxt_qplib_find_buddy_cq(qp, cq); - if (!buddy_cq) - __release(&cq->hwq.lock); - else - spin_unlock(&buddy_cq->hwq.lock); + spin_unlock(&qp->rcq->flush_lock); + spin_unlock_irqrestore(&qp->scq->flush_lock, *flags); } void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp) { unsigned long flags; - bnxt_qplib_acquire_cq_locks(qp, &flags); + bnxt_qplib_acquire_cq_flush_locks(qp, &flags); __bnxt_qplib_add_flush_qp(qp); - bnxt_qplib_release_cq_locks(qp, &flags); + bnxt_qplib_release_cq_flush_locks(qp, &flags); } static void __bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp) @@ -177,7 +137,7 @@ void bnxt_qplib_clean_qp(struct bnxt_qplib_qp *qp) { unsigned long flags; - bnxt_qplib_acquire_cq_locks(qp, &flags); + bnxt_qplib_acquire_cq_flush_locks(qp, &flags); __clean_cq(qp->scq, (u64)(unsigned long)qp); qp->sq.hwq.prod = 0; qp->sq.hwq.cons = 0; @@ -186,7 +146,7 @@ void bnxt_qplib_clean_qp(struct bnxt_qplib_qp *qp) qp->rq.hwq.cons = 0; __bnxt_qplib_del_flush_qp(qp); - bnxt_qplib_release_cq_locks(qp, &flags); + bnxt_qplib_release_cq_flush_locks(qp, &flags); } static void bnxt_qpn_cqn_sched_task(struct work_struct *work) @@ -2107,9 +2067,6 @@ void bnxt_qplib_mark_qp_error(void *qp_handle) /* Must block new posting of SQ and RQ */ qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; bnxt_qplib_cancel_phantom_processing(qp); - - /* Add qp to flush list of the CQ */ - __bnxt_qplib_add_flush_qp(qp); } /* Note: SQE is valid from sw_sq_cons up to cqe_sq_cons (exclusive) @@ -2285,9 +2242,9 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq, sw_sq_cons, cqe->wr_id, cqe->status); cqe++; (*budget)--; - bnxt_qplib_lock_buddy_cq(qp, cq); bnxt_qplib_mark_qp_error(qp); - bnxt_qplib_unlock_buddy_cq(qp, cq); + /* Add qp to flush list of the CQ */ + bnxt_qplib_add_flush_qp(qp); } else { if (swq->flags & SQ_SEND_FLAGS_SIGNAL_COMP) { /* Before we complete, do WA 9060 */ @@ -2403,9 +2360,7 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq, if (hwcqe->status != CQ_RES_RC_STATUS_OK) { qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; /* Add qp to flush list of the CQ */ - bnxt_qplib_lock_buddy_cq(qp, cq); - __bnxt_qplib_add_flush_qp(qp); - bnxt_qplib_unlock_buddy_cq(qp, cq); + bnxt_qplib_add_flush_qp(qp); } } @@ -2489,9 +2444,7 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, if (hwcqe->status != CQ_RES_RC_STATUS_OK) { qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; /* Add qp to flush list of the CQ */ - bnxt_qplib_lock_buddy_cq(qp, cq); - __bnxt_qplib_add_flush_qp(qp); - bnxt_qplib_unlock_buddy_cq(qp, cq); + bnxt_qplib_add_flush_qp(qp); } } done: @@ -2501,11 +2454,9 @@ done: bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq) { struct cq_base *hw_cqe, **hw_cqe_ptr; - unsigned long flags; u32 sw_cons, raw_cons; bool rc = true; - spin_lock_irqsave(&cq->hwq.lock, flags); raw_cons = cq->hwq.cons; sw_cons = HWQ_CMP(raw_cons, &cq->hwq); hw_cqe_ptr = (struct cq_base **)cq->hwq.pbl_ptr; @@ -2513,7 +2464,6 @@ bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq) /* Check for Valid bit. If the CQE is valid, return false */ rc = !CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements); - spin_unlock_irqrestore(&cq->hwq.lock, flags); return rc; } @@ -2602,9 +2552,7 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq, if (hwcqe->status != CQ_RES_RC_STATUS_OK) { qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; /* Add qp to flush list of the CQ */ - bnxt_qplib_lock_buddy_cq(qp, cq); - __bnxt_qplib_add_flush_qp(qp); - bnxt_qplib_unlock_buddy_cq(qp, cq); + bnxt_qplib_add_flush_qp(qp); } } @@ -2719,9 +2667,7 @@ do_rq: */ /* Add qp to flush list of the CQ */ - bnxt_qplib_lock_buddy_cq(qp, cq); - __bnxt_qplib_add_flush_qp(qp); - bnxt_qplib_unlock_buddy_cq(qp, cq); + bnxt_qplib_add_flush_qp(qp); done: return rc; } @@ -2750,7 +2696,7 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq, u32 budget = num_cqes; unsigned long flags; - spin_lock_irqsave(&cq->hwq.lock, flags); + spin_lock_irqsave(&cq->flush_lock, flags); list_for_each_entry(qp, &cq->sqf_head, sq_flush) { dev_dbg(&cq->hwq.pdev->dev, "QPLIB: FP: Flushing SQ QP= %p", @@ -2764,7 +2710,7 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq, qp); __flush_rq(&qp->rq, qp, &cqe, &budget); } - spin_unlock_irqrestore(&cq->hwq.lock, flags); + spin_unlock_irqrestore(&cq->flush_lock, flags); return num_cqes - budget; } @@ -2773,11 +2719,9 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, int num_cqes, struct bnxt_qplib_qp **lib_qp) { struct cq_base *hw_cqe, **hw_cqe_ptr; - unsigned long flags; u32 sw_cons, raw_cons; int budget, rc = 0; - spin_lock_irqsave(&cq->hwq.lock, flags); raw_cons = cq->hwq.cons; budget = num_cqes; @@ -2853,20 +2797,15 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, bnxt_qplib_arm_cq(cq, DBR_DBR_TYPE_CQ); } exit: - spin_unlock_irqrestore(&cq->hwq.lock, flags); return num_cqes - budget; } void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type) { - unsigned long flags; - - spin_lock_irqsave(&cq->hwq.lock, flags); if (arm_type) bnxt_qplib_arm_cq(cq, arm_type); /* Using cq->arm_state variable to track whether to issue cq handler */ atomic_set(&cq->arm_state, 1); - spin_unlock_irqrestore(&cq->hwq.lock, flags); } void bnxt_qplib_flush_cqn_wq(struct bnxt_qplib_qp *qp) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h index ca0a2ffa3509..ade9f13c0fd1 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h @@ -389,6 +389,18 @@ struct bnxt_qplib_cq { struct list_head sqf_head, rqf_head; atomic_t arm_state; spinlock_t compl_lock; /* synch CQ handlers */ +/* Locking Notes: + * QP can move to error state from modify_qp, async error event or error + * CQE as part of poll_cq. When QP is moved to error state, it gets added + * to two flush lists, one each for SQ and RQ. + * Each flush list is protected by qplib_cq->flush_lock. Both scq and rcq + * flush_locks should be acquired when QP is moved to error. The control path + * operations(modify_qp and async error events) are synchronized with poll_cq + * using upper level CQ locks (bnxt_re_cq->cq_lock) of both SCQ and RCQ. + * The qplib_cq->flush_lock is required to synchronize two instances of poll_cq + * of the same QP while manipulating the flush list. + */ + spinlock_t flush_lock; /* QP flush management */ }; #define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE sizeof(struct xrrq_irrq) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 14d153d4013c..80027a494730 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -305,9 +305,8 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw, err_event->res_err_state_reason); if (!qp) break; - bnxt_qplib_acquire_cq_locks(qp, &flags); bnxt_qplib_mark_qp_error(qp); - bnxt_qplib_release_cq_locks(qp, &flags); + rcfw->aeq_handler(rcfw, qp_event, qp); break; default: /* Command Response */ -- cgit v1.2.3 From 8a30ecc6e0ecbb9ae95daf499b2680b885ed0349 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 7 Mar 2018 14:13:58 +0100 Subject: Revert "nvme: create 'slaves' and 'holders' entries for hidden controllers" This reverts commit e9a48034d7d1318ece7d4a235838a86c94db9d68. The slaves and holders link for the hidden gendisks confuse lsblk so that it errors out on, or doesn't report the nvme multipath devices. Given that we don't need holder relationships for something that can't even be directly accessed we should just stop creating those links. Signed-off-by: Christoph Hellwig Reported-by: Potnuri Bharat Teja Cc: stable@vger.kernel.org Signed-off-by: Keith Busch --- drivers/nvme/host/core.c | 2 -- drivers/nvme/host/multipath.c | 30 ------------------------------ drivers/nvme/host/nvme.h | 8 -------- 3 files changed, 40 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 817e5e2766da..7aeca5db7916 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -3033,7 +3033,6 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) ns->disk->disk_name); nvme_mpath_add_disk(ns->head); - nvme_mpath_add_disk_links(ns); return; out_unlink_ns: mutex_lock(&ctrl->subsys->lock); @@ -3053,7 +3052,6 @@ static void nvme_ns_remove(struct nvme_ns *ns) return; if (ns->disk && ns->disk->flags & GENHD_FL_UP) { - nvme_mpath_remove_disk_links(ns); sysfs_remove_group(&disk_to_dev(ns->disk)->kobj, &nvme_ns_id_attr_group); if (ns->ndev) diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index b7e5c6db4d92..060f69e03427 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -210,25 +210,6 @@ void nvme_mpath_add_disk(struct nvme_ns_head *head) mutex_unlock(&head->subsys->lock); } -void nvme_mpath_add_disk_links(struct nvme_ns *ns) -{ - struct kobject *slave_disk_kobj, *holder_disk_kobj; - - if (!ns->head->disk) - return; - - slave_disk_kobj = &disk_to_dev(ns->disk)->kobj; - if (sysfs_create_link(ns->head->disk->slave_dir, slave_disk_kobj, - kobject_name(slave_disk_kobj))) - return; - - holder_disk_kobj = &disk_to_dev(ns->head->disk)->kobj; - if (sysfs_create_link(ns->disk->part0.holder_dir, holder_disk_kobj, - kobject_name(holder_disk_kobj))) - sysfs_remove_link(ns->head->disk->slave_dir, - kobject_name(slave_disk_kobj)); -} - void nvme_mpath_remove_disk(struct nvme_ns_head *head) { if (!head->disk) @@ -243,14 +224,3 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head) blk_cleanup_queue(head->disk->queue); put_disk(head->disk); } - -void nvme_mpath_remove_disk_links(struct nvme_ns *ns) -{ - if (!ns->head->disk) - return; - - sysfs_remove_link(ns->disk->part0.holder_dir, - kobject_name(&disk_to_dev(ns->head->disk)->kobj)); - sysfs_remove_link(ns->head->disk->slave_dir, - kobject_name(&disk_to_dev(ns->disk)->kobj)); -} diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 0521e4707d1c..d733b14ede9d 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -410,9 +410,7 @@ bool nvme_req_needs_failover(struct request *req, blk_status_t error); void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl); int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,struct nvme_ns_head *head); void nvme_mpath_add_disk(struct nvme_ns_head *head); -void nvme_mpath_add_disk_links(struct nvme_ns *ns); void nvme_mpath_remove_disk(struct nvme_ns_head *head); -void nvme_mpath_remove_disk_links(struct nvme_ns *ns); static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns) { @@ -454,12 +452,6 @@ static inline void nvme_mpath_add_disk(struct nvme_ns_head *head) static inline void nvme_mpath_remove_disk(struct nvme_ns_head *head) { } -static inline void nvme_mpath_add_disk_links(struct nvme_ns *ns) -{ -} -static inline void nvme_mpath_remove_disk_links(struct nvme_ns *ns) -{ -} static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns) { } -- cgit v1.2.3 From 250c6c49e3b68756b14983c076183568636e2bde Mon Sep 17 00:00:00 2001 From: Peter Malone Date: Wed, 7 Mar 2018 14:00:34 +0100 Subject: fbdev: Fixing arbitrary kernel leak in case FBIOGETCMAP_SPARC in sbusfb_ioctl_helper(). Fixing arbitrary kernel leak in case FBIOGETCMAP_SPARC in sbusfb_ioctl_helper(). 'index' is defined as an int in sbusfb_ioctl_helper(). We retrieve this from the user: if (get_user(index, &c->index) || __get_user(count, &c->count) || __get_user(ured, &c->red) || __get_user(ugreen, &c->green) || __get_user(ublue, &c->blue)) return -EFAULT; and then we use 'index' in the following way: red = cmap->red[index + i] >> 8; green = cmap->green[index + i] >> 8; blue = cmap->blue[index + i] >> 8; This is a classic information leak vulnerability. 'index' should be an unsigned int, given its usage above. This patch is straight-forward; it changes 'index' to unsigned int in two switch-cases: FBIOGETCMAP_SPARC && FBIOPUTCMAP_SPARC. This patch fixes CVE-2018-6412. Signed-off-by: Peter Malone Acked-by: Mathieu Malaterre Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/video/fbdev/sbuslib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbdev/sbuslib.c b/drivers/video/fbdev/sbuslib.c index af6fc97f4ba4..a436d44f1b7f 100644 --- a/drivers/video/fbdev/sbuslib.c +++ b/drivers/video/fbdev/sbuslib.c @@ -122,7 +122,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, unsigned char __user *ured; unsigned char __user *ugreen; unsigned char __user *ublue; - int index, count, i; + unsigned int index, count, i; if (get_user(index, &c->index) || __get_user(count, &c->count) || @@ -161,7 +161,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, unsigned char __user *ugreen; unsigned char __user *ublue; struct fb_cmap *cmap = &info->cmap; - int index, count, i; + unsigned int index, count, i; u8 red, green, blue; if (get_user(index, &c->index) || -- cgit v1.2.3 From 933897342d0714ae1c10729cbaeecea0c6178db5 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Wed, 28 Feb 2018 21:15:19 +0100 Subject: brcmfmac: add possibility to obtain firmware error The feature module needs to evaluate the actual firmware error return upon a control command. This adds a flag to struct brcmf_if that the caller can set. This flag is checked to determine the error code that needs to be returned. Fixes: b69c1df47281 ("brcmfmac: separate firmware errors from i/o errors") Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h | 2 ++ drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c | 10 ++++++++++ drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c | 3 +++ 3 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index df8a1ecb9924..232dcbb83311 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -181,6 +181,7 @@ enum brcmf_netif_stop_reason { * @netif_stop_lock: spinlock for update netif_stop from multiple sources. * @pend_8021x_cnt: tracks outstanding number of 802.1x frames. * @pend_8021x_wait: used for signalling change in count. + * @fwil_fwerr: flag indicating fwil layer should return firmware error codes. */ struct brcmf_if { struct brcmf_pub *drvr; @@ -198,6 +199,7 @@ struct brcmf_if { wait_queue_head_t pend_8021x_wait; struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES]; u8 ipv6addr_idx; + bool fwil_fwerr; }; int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 47de35a33853..bede7b7fd996 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -104,6 +104,9 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, u32 data; int err; + /* we need to know firmware error */ + ifp->fwil_fwerr = true; + err = brcmf_fil_iovar_int_get(ifp, name, &data); if (err == 0) { brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]); @@ -112,6 +115,8 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, brcmf_dbg(TRACE, "%s feature check failed: %d\n", brcmf_feat_names[id], err); } + + ifp->fwil_fwerr = false; } static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp, @@ -120,6 +125,9 @@ static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp, { int err; + /* we need to know firmware error */ + ifp->fwil_fwerr = true; + err = brcmf_fil_iovar_data_set(ifp, name, data, len); if (err != -BRCMF_FW_UNSUPPORTED) { brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]); @@ -128,6 +136,8 @@ static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp, brcmf_dbg(TRACE, "%s feature check failed: %d\n", brcmf_feat_names[id], err); } + + ifp->fwil_fwerr = false; } #define MAX_CAPS_BUFFER_SIZE 512 diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c index f2cfdd3b2bf1..fc5751116d99 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c @@ -131,6 +131,9 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) brcmf_fil_get_errstr((u32)(-fwerr)), fwerr); err = -EBADE; } + if (ifp->fwil_fwerr) + return fwerr; + return err; } -- cgit v1.2.3 From 455f3e76cfc0d893585a5f358b9ddbe9c1e1e53b Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Wed, 28 Feb 2018 21:15:20 +0100 Subject: brcmfmac: fix P2P_DEVICE ethernet address generation The firmware has a requirement that the P2P_DEVICE address should be different from the address of the primary interface. When not specified by user-space, the driver generates the MAC address for the P2P_DEVICE interface using the MAC address of the primary interface and setting the locally administered bit. However, the MAC address of the primary interface may already have that bit set causing the creation of the P2P_DEVICE interface to fail with -EBUSY. Fix this by using a random address instead to determine the P2P_DEVICE address. Cc: stable@vger.kernel.org # 3.10.y Reported-by: Hans de Goede Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 24 ++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index 2ee54133efa1..82064e909784 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -462,25 +462,23 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac) * @dev_addr: optional device address. * * P2P needs mac addresses for P2P device and interface. If no device - * address it specified, these are derived from the primary net device, ie. - * the permanent ethernet address of the device. + * address it specified, these are derived from a random ethernet + * address. */ static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr) { - struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; - bool local_admin = false; + bool random_addr = false; - if (!dev_addr || is_zero_ether_addr(dev_addr)) { - dev_addr = pri_ifp->mac_addr; - local_admin = true; - } + if (!dev_addr || is_zero_ether_addr(dev_addr)) + random_addr = true; - /* Generate the P2P Device Address. This consists of the device's - * primary MAC address with the locally administered bit set. + /* Generate the P2P Device Address obtaining a random ethernet + * address with the locally administered bit set. */ - memcpy(p2p->dev_addr, dev_addr, ETH_ALEN); - if (local_admin) - p2p->dev_addr[0] |= 0x02; + if (random_addr) + eth_random_addr(p2p->dev_addr); + else + memcpy(p2p->dev_addr, dev_addr, ETH_ALEN); /* Generate the P2P Interface Address. If the discovery and connection * BSSCFGs need to simultaneously co-exist, then this address must be -- cgit v1.2.3 From ea2a14da0f191e93c0924acb4ab8a9009e33de81 Mon Sep 17 00:00:00 2001 From: zain wang Date: Mon, 5 Mar 2018 09:57:39 +0100 Subject: drm/bridge: analogix_dp: Don't power bridge in analogix_dp_bind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bridge does not need to be powered in analogix_dp_bind(), so remove the calls to pm_runtime_get()/phy_power_on()/analogix_dp_init_dp() as well as their power-off counterparts. Cc: Stéphane Marchesin Signed-off-by: zain wang Signed-off-by: Caesar Wang [the patch originally just removed the power_on portion, seanpaul removed the power off code as well as improved the commit message] Signed-off-by: Sean Paul Signed-off-by: Thierry Escande Signed-off-by: Marek Szyprowski Tested-by: Heiko Stuebner Reviewed-by: Heiko Stuebner Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20180305085741.18896-2-m.szyprowski@samsung.com --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 3f7a796b27e4..8475749baae5 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1378,11 +1378,6 @@ analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, pm_runtime_enable(dev); - pm_runtime_get_sync(dev); - phy_power_on(dp->phy); - - analogix_dp_init_dp(dp); - ret = devm_request_threaded_irq(&pdev->dev, dp->irq, analogix_dp_hardirq, analogix_dp_irq_thread, @@ -1410,15 +1405,10 @@ analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, goto err_disable_pm_runtime; } - phy_power_off(dp->phy); - pm_runtime_put(dev); - return dp; err_disable_pm_runtime: - phy_power_off(dp->phy); - pm_runtime_put(dev); pm_runtime_disable(dev); return ERR_PTR(ret); -- cgit v1.2.3 From f25c83581583eca9b1c1e6fd2914c7f8a1be22de Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 5 Mar 2018 09:57:40 +0100 Subject: drm/bridge: analogix_dp: Postpone enabling runtime power management Enabling runtime power management early in analogix_dp_bind() causes following kernel NULL pointer dereference: Unable to handle kernel NULL pointer dereference at virtual address 000007d8 pgd = 28ffa2e4 [000007d8] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM Modules linked in: CPU: 6 PID: 69 Comm: kworker/6:1 Not tainted 4.16.0-rc1-00062-ge25751974ba8 #3622 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) Workqueue: events deferred_probe_work_func PC is at analogix_dp_resume+0x8/0xc0 LR is at pm_generic_runtime_resume+0x2c/0x38 pc : [] lr : [] psr: a0000113 sp : ee13fbd8 ip : 0000001a fp : 00000001 r10: ee0eb080 r9 : c0552bd8 r8 : c0fb1d98 r7 : eebb1010 r6 : eeae9808 r5 : 00000000 r4 : d4850415 r3 : ee0ed010 r2 : b2d05e00 r1 : 00000000 r0 : 00000000 Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none Control: 10c5387d Table: 2000406a DAC: 00000051 Process kworker/6:1 (pid: 69, stack limit = 0x913205b4) Stack: (0xee13fbd8 to 0xee140000) ... [] (analogix_dp_resume) from [] (pm_generic_runtime_resume+0x2c/0x38) [] (pm_generic_runtime_resume) from [] (__genpd_runtime_resume+0x2c/0x8c) [] (__genpd_runtime_resume) from [] (genpd_runtime_resume+0x14c/0x258) [] (genpd_runtime_resume) from [] (__rpm_callback+0x134/0x214) [] (__rpm_callback) from [] (rpm_callback+0x20/0x80) [] (rpm_callback) from [] (rpm_resume+0x3a0/0x734) [] (rpm_resume) from [] (__pm_runtime_resume+0x64/0x9c) [] (__pm_runtime_resume) from [] (__device_attach+0x8c/0x134) [] (__device_attach) from [] (bus_probe_device+0x88/0x90) [] (bus_probe_device) from [] (device_add+0x3a8/0x580) [] (device_add) from [] (i2c_register_adapter+0xd4/0x3ec) [] (i2c_register_adapter) from [] (analogix_dp_bind+0x2a0/0x410) [] (analogix_dp_bind) from [] (exynos_dp_bind+0x9c/0x12c) [] (exynos_dp_bind) from [] (component_bind_all+0xfc/0x258) [] (component_bind_all) from [] (exynos_drm_bind+0x15c/0x28c) [] (exynos_drm_bind) from [] (try_to_bring_up_master+0x1b8/0x29c) [] (try_to_bring_up_master) from [] (component_add+0xa0/0x170) [] (component_add) from [] (exynos_dp_probe+0x64/0xb8) [] (exynos_dp_probe) from [] (platform_drv_probe+0x50/0xb0) [] (platform_drv_probe) from [] (driver_probe_device+0x2b8/0x4a0) [] (driver_probe_device) from [] (bus_for_each_drv+0x44/0x8c) [] (bus_for_each_drv) from [] (__device_attach+0xa0/0x134) [] (__device_attach) from [] (bus_probe_device+0x88/0x90) [] (bus_probe_device) from [] (deferred_probe_work_func+0x3c/0x168) [] (deferred_probe_work_func) from [] (process_one_work+0x1d0/0x7bc) [] (process_one_work) from [] (worker_thread+0x34/0x4dc) [] (worker_thread) from [] (kthread+0x128/0x164) [] (kthread) from [] (ret_from_fork+0x14/0x20) Exception stack(0xee13ffb0 to 0xee13fff8) ffa0: 00000000 00000000 00000000 00000000 ffc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ffe0: 00000000 00000000 00000000 00000000 00000013 00000000 Code: e2800e37 eafee601 e92d4070 e1a05000 (e59067d8) ---[ end trace bf6046013df7cab2 ]--- This oops happens, because analogix_dp_bind() calls drm_dp_aux_register() which registers i2c adapter. I2C core tries to runtime get i2c host device during registration. This ends in analogix_dp_resume(), but dp context is NULL there. dp context is set in exynos_dp_bind() after executing analogix_dp_bind(). Fix this issue by postponing enabling runtime power management after drm_dp_aux_register(). Signed-off-by: Marek Szyprowski Tested-by: Heiko Stuebner Reviewed-by: Heiko Stuebner Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20180305085741.18896-3-m.szyprowski@samsung.com --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 8475749baae5..b391d149db91 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1376,8 +1376,6 @@ analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, return ERR_PTR(-ENODEV); } - pm_runtime_enable(dev); - ret = devm_request_threaded_irq(&pdev->dev, dp->irq, analogix_dp_hardirq, analogix_dp_irq_thread, @@ -1397,7 +1395,9 @@ analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, ret = drm_dp_aux_register(&dp->aux); if (ret) - goto err_disable_pm_runtime; + return ERR_PTR(ret); + + pm_runtime_enable(dev); ret = analogix_dp_create_bridge(drm_dev, dp); if (ret) { -- cgit v1.2.3 From 2e9b3e74b4a184f657995cf28963f72531c7a420 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 5 Mar 2018 09:57:41 +0100 Subject: drm/bridge: analogix_dp: Don't create useless connectors If there is another bridge after analogix_dp, then the connector object should not be created. This fixes following timeouts on Exynos5420-based Chromebook2 Peach-PIT board during boot: exynos-dp 145b0000.dp-controller: AUX CH cmd reply timeout! exynos-dp 145b0000.dp-controller: AUX CH enable timeout! exynos-dp 145b0000.dp-controller: AUX CH enable timeout! exynos-dp 145b0000.dp-controller: AUX CH enable timeout! exynos-dp 145b0000.dp-controller: AUX CH enable timeout! Signed-off-by: Marek Szyprowski Tested-by: Heiko Stuebner Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20180305085741.18896-4-m.szyprowski@samsung.com --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 29 ++++++++++++---------- drivers/gpu/drm/exynos/exynos_dp.c | 1 + 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index b391d149db91..a693ab3078f0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1012,27 +1012,30 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge) { struct analogix_dp_device *dp = bridge->driver_private; struct drm_encoder *encoder = dp->encoder; - struct drm_connector *connector = &dp->connector; - int ret; + struct drm_connector *connector = NULL; + int ret = 0; if (!bridge->encoder) { DRM_ERROR("Parent encoder object not found"); return -ENODEV; } - connector->polled = DRM_CONNECTOR_POLL_HPD; + if (!dp->plat_data->skip_connector) { + connector = &dp->connector; + connector->polled = DRM_CONNECTOR_POLL_HPD; - ret = drm_connector_init(dp->drm_dev, connector, - &analogix_dp_connector_funcs, - DRM_MODE_CONNECTOR_eDP); - if (ret) { - DRM_ERROR("Failed to initialize connector with drm\n"); - return ret; - } + ret = drm_connector_init(dp->drm_dev, connector, + &analogix_dp_connector_funcs, + DRM_MODE_CONNECTOR_eDP); + if (ret) { + DRM_ERROR("Failed to initialize connector with drm\n"); + return ret; + } - drm_connector_helper_add(connector, - &analogix_dp_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_helper_add(connector, + &analogix_dp_connector_helper_funcs); + drm_mode_connector_attach_encoder(connector, encoder); + } /* * NOTE: the connector registration is implemented in analogix diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index 33319a858f3a..964831dab102 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -244,6 +244,7 @@ static int exynos_dp_probe(struct platform_device *pdev) /* The remote port can be either a panel or a bridge */ dp->plat_data.panel = panel; + dp->plat_data.skip_connector = !!bridge; dp->ptn_bridge = bridge; out: -- cgit v1.2.3 From 803fafbe0cd522fa6b9e41ca3b96cfb2e2a2222d Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Sun, 4 Mar 2018 21:48:17 +0300 Subject: fsl/fman: avoid sleeping in atomic context while adding an address __dev_mc_add grabs an adress spinlock so use atomic context in kmalloc. / # ifconfig eth0 inet 192.168.0.111 [ 89.331622] BUG: sleeping function called from invalid context at mm/slab.h:420 [ 89.339002] in_atomic(): 1, irqs_disabled(): 0, pid: 1035, name: ifconfig [ 89.345799] 2 locks held by ifconfig/1035: [ 89.349908] #0: (rtnl_mutex){+.+.}, at: [<(ptrval)>] devinet_ioctl+0xc0/0x8a0 [ 89.357258] #1: (_xmit_ETHER){+...}, at: [<(ptrval)>] __dev_mc_add+0x28/0x80 [ 89.364520] CPU: 1 PID: 1035 Comm: ifconfig Not tainted 4.16.0-rc3-dirty #8 [ 89.371464] Call Trace: [ 89.373908] [e959db60] [c066f948] dump_stack+0xa4/0xfc (unreliable) [ 89.380177] [e959db80] [c00671d8] ___might_sleep+0x248/0x280 [ 89.385833] [e959dba0] [c01aec34] kmem_cache_alloc_trace+0x174/0x320 [ 89.392179] [e959dbd0] [c04ab920] dtsec_add_hash_mac_address+0x130/0x240 [ 89.398874] [e959dc00] [c04a9d74] set_multi+0x174/0x1b0 [ 89.404093] [e959dc30] [c04afb68] dpaa_set_rx_mode+0x68/0xe0 [ 89.409745] [e959dc40] [c057baf8] __dev_mc_add+0x58/0x80 [ 89.415052] [e959dc60] [c060fd64] igmp_group_added+0x164/0x190 [ 89.420878] [e959dca0] [c060ffa8] ip_mc_inc_group+0x218/0x460 [ 89.426617] [e959dce0] [c06120fc] ip_mc_up+0x3c/0x190 [ 89.431662] [e959dd10] [c0607270] inetdev_event+0x250/0x620 [ 89.437227] [e959dd50] [c005f190] notifier_call_chain+0x80/0xf0 [ 89.443138] [e959dd80] [c0573a74] __dev_notify_flags+0x54/0xf0 [ 89.448964] [e959dda0] [c05743f8] dev_change_flags+0x48/0x60 [ 89.454615] [e959ddc0] [c0606744] devinet_ioctl+0x544/0x8a0 [ 89.460180] [e959de10] [c060987c] inet_ioctl+0x9c/0x1f0 [ 89.465400] [e959de80] [c05479a8] sock_ioctl+0x168/0x460 [ 89.470708] [e959ded0] [c01cf3ec] do_vfs_ioctl+0xac/0x8c0 [ 89.476099] [e959df20] [c01cfc40] SyS_ioctl+0x40/0xc0 [ 89.481147] [e959df40] [c0011318] ret_from_syscall+0x0/0x3c [ 89.486715] --- interrupt: c01 at 0x1006943c [ 89.486715] LR = 0x100c45ec Signed-off-by: Denis Kirjanov Acked-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fman/fman_dtsec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c index ea43b4974149..7af31ddd093f 100644 --- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c +++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c @@ -1100,7 +1100,7 @@ int dtsec_add_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr) set_bucket(dtsec->regs, bucket, true); /* Create element to be added to the driver hash table */ - hash_entry = kmalloc(sizeof(*hash_entry), GFP_KERNEL); + hash_entry = kmalloc(sizeof(*hash_entry), GFP_ATOMIC); if (!hash_entry) return -ENOMEM; hash_entry->addr = addr; -- cgit v1.2.3 From 81c0e3dd82927064a2f56a31a0974a0d110fcdb0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 10 Jan 2018 02:40:27 +0200 Subject: drm: rcar-du: Fix legacy DT to create LVDS encoder nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The internal LVDS encoders now have their own DT bindings. Before switching the driver infrastructure to those new bindings, implement backward-compatibility through live DT patching. Patching is disabled and will be enabled along with support for the new DT bindings in the DU driver. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Frank Rowand --- drivers/gpu/drm/rcar-du/Kconfig | 2 + drivers/gpu/drm/rcar-du/Makefile | 7 +- drivers/gpu/drm/rcar-du/rcar_du_of.c | 322 +++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_du_of.h | 20 ++ .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts | 76 +++++ .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts | 50 ++++ .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts | 50 ++++ .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts | 50 ++++ .../gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts | 50 ++++ 9 files changed, 626 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.c create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of.h create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts (limited to 'drivers') diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 5d0b4b7119af..3f83352a7313 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -22,6 +22,8 @@ config DRM_RCAR_LVDS bool "R-Car DU LVDS Encoder Support" depends on DRM_RCAR_DU select DRM_PANEL + select OF_FLATTREE + select OF_OVERLAY help Enable support for the R-Car Display Unit embedded LVDS encoders. diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 0cf5c11030e8..86b337b4be5d 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -8,7 +8,12 @@ rcar-du-drm-y := rcar_du_crtc.o \ rcar_du_plane.o rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_lvdsenc.o - +rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_of.o \ + rcar_du_of_lvds_r8a7790.dtb.o \ + rcar_du_of_lvds_r8a7791.dtb.o \ + rcar_du_of_lvds_r8a7793.dtb.o \ + rcar_du_of_lvds_r8a7795.dtb.o \ + rcar_du_of_lvds_r8a7796.dtb.o rcar-du-drm-$(CONFIG_DRM_RCAR_VSP) += rcar_du_vsp.o obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.c b/drivers/gpu/drm/rcar-du/rcar_du_of.c new file mode 100644 index 000000000000..68a0b82cb17e --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rcar_du_of.c - Legacy DT bindings compatibility + * + * Copyright (C) 2018 Laurent Pinchart + * + * Based on work from Jyri Sarha + * Copyright (C) 2015 Texas Instruments + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rcar_du_crtc.h" +#include "rcar_du_drv.h" + +/* ----------------------------------------------------------------------------- + * Generic Overlay Handling + */ + +struct rcar_du_of_overlay { + const char *compatible; + void *begin; + void *end; +}; + +#define RCAR_DU_OF_DTB(type, soc) \ + extern char __dtb_rcar_du_of_##type##_##soc##_begin[]; \ + extern char __dtb_rcar_du_of_##type##_##soc##_end[] + +#define RCAR_DU_OF_OVERLAY(type, soc) \ + { \ + .compatible = "renesas,du-" #soc, \ + .begin = __dtb_rcar_du_of_##type##_##soc##_begin, \ + .end = __dtb_rcar_du_of_##type##_##soc##_end, \ + } + +static int __init rcar_du_of_apply_overlay(const struct rcar_du_of_overlay *dtbs, + const char *compatible) +{ + const struct rcar_du_of_overlay *dtb = NULL; + unsigned int i; + int ovcs_id; + + for (i = 0; dtbs[i].compatible; ++i) { + if (!strcmp(dtbs[i].compatible, compatible)) { + dtb = &dtbs[i]; + break; + } + } + + if (!dtb) + return -ENODEV; + + ovcs_id = 0; + return of_overlay_fdt_apply(dtb->begin, dtb->end - dtb->begin, + &ovcs_id); +} + +static int __init rcar_du_of_add_property(struct of_changeset *ocs, + struct device_node *np, + const char *name, const void *value, + int length) +{ + struct property *prop; + int ret = -ENOMEM; + + prop = kzalloc(sizeof(*prop), GFP_KERNEL); + if (!prop) + return -ENOMEM; + + prop->name = kstrdup(name, GFP_KERNEL); + if (!prop->name) + goto out_err; + + prop->value = kmemdup(value, length, GFP_KERNEL); + if (!prop->value) + goto out_err; + + of_property_set_flag(prop, OF_DYNAMIC); + + prop->length = length; + + ret = of_changeset_add_property(ocs, np, prop); + if (!ret) + return 0; + +out_err: + kfree(prop->value); + kfree(prop->name); + kfree(prop); + return ret; +} + +/* ----------------------------------------------------------------------------- + * LVDS Overlays + */ + +RCAR_DU_OF_DTB(lvds, r8a7790); +RCAR_DU_OF_DTB(lvds, r8a7791); +RCAR_DU_OF_DTB(lvds, r8a7793); +RCAR_DU_OF_DTB(lvds, r8a7795); +RCAR_DU_OF_DTB(lvds, r8a7796); + +static const struct rcar_du_of_overlay rcar_du_lvds_overlays[] __initconst = { + RCAR_DU_OF_OVERLAY(lvds, r8a7790), + RCAR_DU_OF_OVERLAY(lvds, r8a7791), + RCAR_DU_OF_OVERLAY(lvds, r8a7793), + RCAR_DU_OF_OVERLAY(lvds, r8a7795), + RCAR_DU_OF_OVERLAY(lvds, r8a7796), + { /* Sentinel */ }, +}; + +static struct of_changeset rcar_du_lvds_changeset; + +static void __init rcar_du_of_lvds_patch_one(struct device_node *lvds, + const struct of_phandle_args *clk, + struct device_node *local, + struct device_node *remote) +{ + unsigned int psize; + unsigned int i; + __be32 value[4]; + int ret; + + /* + * Set the LVDS clocks property. This can't be performed by the overlay + * as the structure of the clock specifier has changed over time, and we + * don't know at compile time which binding version the system we will + * run on uses. + */ + if (clk->args_count >= ARRAY_SIZE(value) - 1) + return; + + of_changeset_init(&rcar_du_lvds_changeset); + + value[0] = cpu_to_be32(clk->np->phandle); + for (i = 0; i < clk->args_count; ++i) + value[i + 1] = cpu_to_be32(clk->args[i]); + + psize = (clk->args_count + 1) * 4; + ret = rcar_du_of_add_property(&rcar_du_lvds_changeset, lvds, + "clocks", value, psize); + if (ret < 0) + goto done; + + /* + * Insert the node in the OF graph: patch the LVDS ports remote-endpoint + * properties to point to the endpoints of the sibling nodes in the + * graph. This can't be performed by the overlay: on the input side the + * overlay would contain a phandle for the DU LVDS output port that + * would clash with the system DT, and on the output side the connection + * is board-specific. + */ + value[0] = cpu_to_be32(local->phandle); + value[1] = cpu_to_be32(remote->phandle); + + for (i = 0; i < 2; ++i) { + struct device_node *endpoint; + + endpoint = of_graph_get_endpoint_by_regs(lvds, i, 0); + if (!endpoint) { + ret = -EINVAL; + goto done; + } + + ret = rcar_du_of_add_property(&rcar_du_lvds_changeset, + endpoint, "remote-endpoint", + &value[i], sizeof(value[i])); + of_node_put(endpoint); + if (ret < 0) + goto done; + } + + ret = of_changeset_apply(&rcar_du_lvds_changeset); + +done: + if (ret < 0) + of_changeset_destroy(&rcar_du_lvds_changeset); +} + +struct lvds_of_data { + struct resource res; + struct of_phandle_args clkspec; + struct device_node *local; + struct device_node *remote; +}; + +static void __init rcar_du_of_lvds_patch(const struct of_device_id *of_ids) +{ + const struct rcar_du_device_info *info; + const struct of_device_id *match; + struct lvds_of_data lvds_data[2] = { }; + struct device_node *lvds_node; + struct device_node *soc_node; + struct device_node *du_node; + char compatible[22]; + const char *soc_name; + unsigned int i; + int ret; + + /* Get the DU node and exit if not present or disabled. */ + du_node = of_find_matching_node_and_match(NULL, of_ids, &match); + if (!du_node || !of_device_is_available(du_node)) { + of_node_put(du_node); + return; + } + + info = match->data; + soc_node = of_get_parent(du_node); + + if (WARN_ON(info->num_lvds > ARRAY_SIZE(lvds_data))) + goto done; + + /* + * Skip if the LVDS nodes already exists. + * + * The nodes are searched based on the compatible string, which we + * construct from the SoC name found in the DU compatible string. As a + * match has been found we know the compatible string matches the + * expected format and can thus skip some of the string manipulation + * normal safety checks. + */ + soc_name = strchr(match->compatible, '-') + 1; + sprintf(compatible, "renesas,%s-lvds", soc_name); + lvds_node = of_find_compatible_node(NULL, NULL, compatible); + if (lvds_node) { + of_node_put(lvds_node); + return; + } + + /* + * Parse the DU node and store the register specifier, the clock + * specifier and the local and remote endpoint of the LVDS link for + * later use. + */ + for (i = 0; i < info->num_lvds; ++i) { + struct lvds_of_data *lvds = &lvds_data[i]; + unsigned int port; + char name[7]; + int index; + + sprintf(name, "lvds.%u", i); + index = of_property_match_string(du_node, "clock-names", name); + if (index < 0) + continue; + + ret = of_parse_phandle_with_args(du_node, "clocks", + "#clock-cells", index, + &lvds->clkspec); + if (ret < 0) + continue; + + port = info->routes[RCAR_DU_OUTPUT_LVDS0 + i].port; + + lvds->local = of_graph_get_endpoint_by_regs(du_node, port, 0); + if (!lvds->local) + continue; + + lvds->remote = of_graph_get_remote_endpoint(lvds->local); + if (!lvds->remote) + continue; + + index = of_property_match_string(du_node, "reg-names", name); + if (index < 0) + continue; + + of_address_to_resource(du_node, index, &lvds->res); + } + + /* Parse and apply the overlay. This will resolve phandles. */ + ret = rcar_du_of_apply_overlay(rcar_du_lvds_overlays, + match->compatible); + if (ret < 0) + goto done; + + /* Patch the newly created LVDS encoder nodes. */ + for_each_child_of_node(soc_node, lvds_node) { + struct resource res; + + if (!of_device_is_compatible(lvds_node, compatible)) + continue; + + /* Locate the lvds_data entry based on the resource start. */ + ret = of_address_to_resource(lvds_node, 0, &res); + if (ret < 0) + continue; + + for (i = 0; i < ARRAY_SIZE(lvds_data); ++i) { + if (lvds_data[i].res.start == res.start) + break; + } + + if (i == ARRAY_SIZE(lvds_data)) + continue; + + /* Patch the LVDS encoder. */ + rcar_du_of_lvds_patch_one(lvds_node, &lvds_data[i].clkspec, + lvds_data[i].local, + lvds_data[i].remote); + } + +done: + for (i = 0; i < info->num_lvds; ++i) { + of_node_put(lvds_data[i].clkspec.np); + of_node_put(lvds_data[i].local); + of_node_put(lvds_data[i].remote); + } + + of_node_put(soc_node); + of_node_put(du_node); +} + +void __init rcar_du_of_init(const struct of_device_id *of_ids) +{ + rcar_du_of_lvds_patch(of_ids); +} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of.h b/drivers/gpu/drm/rcar-du/rcar_du_of.h new file mode 100644 index 000000000000..c2e65a727e91 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_of.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * rcar_du_of.h - Legacy DT bindings compatibility + * + * Copyright (C) 2018 Laurent Pinchart + */ +#ifndef __RCAR_DU_OF_H__ +#define __RCAR_DU_OF_H__ + +#include + +struct of_device_id; + +#ifdef CONFIG_DRM_RCAR_LVDS +void __init rcar_du_of_init(const struct of_device_id *of_ids); +#else +static inline void rcar_du_of_init(const struct of_device_id *of_ids) { } +#endif /* CONFIG_DRM_RCAR_LVDS */ + +#endif /* __RCAR_DU_OF_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts new file mode 100644 index 000000000000..579753e04f3b --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7790.dts @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rcar_du_of_lvds_r8a7790.dts - Legacy LVDS DT bindings conversion for R8A7790 + * + * Copyright (C) 2018 Laurent Pinchart + */ + +/dts-v1/; +/plugin/; +/ { + fragment@0 { + target-path = "/"; + __overlay__ { + #address-cells = <2>; + #size-cells = <2>; + + lvds@feb90000 { + compatible = "renesas,r8a7790-lvds"; + reg = <0 0xfeb90000 0 0x1c>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds0_input: endpoint { + }; + }; + port@1 { + reg = <1>; + lvds0_out: endpoint { + }; + }; + }; + }; + + lvds@feb94000 { + compatible = "renesas,r8a7790-lvds"; + reg = <0 0xfeb94000 0 0x1c>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds1_input: endpoint { + }; + }; + port@1 { + reg = <1>; + lvds1_out: endpoint { + }; + }; + }; + }; + }; + }; + + fragment@1 { + target-path = "/display@feb00000/ports"; + __overlay__ { + port@1 { + endpoint { + remote-endpoint = <&lvds0_input>; + }; + }; + port@2 { + endpoint { + remote-endpoint = <&lvds1_input>; + }; + }; + }; + }; +}; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts new file mode 100644 index 000000000000..cb9da1f3942b --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7791.dts @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rcar_du_of_lvds_r8a7791.dts - Legacy LVDS DT bindings conversion for R8A7791 + * + * Copyright (C) 2018 Laurent Pinchart + */ + +/dts-v1/; +/plugin/; +/ { + fragment@0 { + target-path = "/"; + __overlay__ { + #address-cells = <2>; + #size-cells = <2>; + + lvds@feb90000 { + compatible = "renesas,r8a7791-lvds"; + reg = <0 0xfeb90000 0 0x1c>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds0_input: endpoint { + }; + }; + port@1 { + reg = <1>; + lvds0_out: endpoint { + }; + }; + }; + }; + }; + }; + + fragment@1 { + target-path = "/display@feb00000/ports"; + __overlay__ { + port@1 { + endpoint { + remote-endpoint = <&lvds0_input>; + }; + }; + }; + }; +}; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts new file mode 100644 index 000000000000..e7b8804dc3c1 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7793.dts @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rcar_du_of_lvds_r8a7793.dts - Legacy LVDS DT bindings conversion for R8A7793 + * + * Copyright (C) 2018 Laurent Pinchart + */ + +/dts-v1/; +/plugin/; +/ { + fragment@0 { + target-path = "/"; + __overlay__ { + #address-cells = <2>; + #size-cells = <2>; + + lvds@feb90000 { + compatible = "renesas,r8a7793-lvds"; + reg = <0 0xfeb90000 0 0x1c>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds0_input: endpoint { + }; + }; + port@1 { + reg = <1>; + lvds0_out: endpoint { + }; + }; + }; + }; + }; + }; + + fragment@1 { + target-path = "/display@feb00000/ports"; + __overlay__ { + port@1 { + endpoint { + remote-endpoint = <&lvds0_input>; + }; + }; + }; + }; +}; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts new file mode 100644 index 000000000000..a1327443e6fa --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7795.dts @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rcar_du_of_lvds_r8a7795.dts - Legacy LVDS DT bindings conversion for R8A7795 + * + * Copyright (C) 2018 Laurent Pinchart + */ + +/dts-v1/; +/plugin/; +/ { + fragment@0 { + target-path = "/soc"; + __overlay__ { + #address-cells = <2>; + #size-cells = <2>; + + lvds@feb90000 { + compatible = "renesas,r8a7795-lvds"; + reg = <0 0xfeb90000 0 0x14>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds0_input: endpoint { + }; + }; + port@1 { + reg = <1>; + lvds0_out: endpoint { + }; + }; + }; + }; + }; + }; + + fragment@1 { + target-path = "/soc/display@feb00000/ports"; + __overlay__ { + port@3 { + endpoint { + remote-endpoint = <&lvds0_input>; + }; + }; + }; + }; +}; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts new file mode 100644 index 000000000000..b23d6466c415 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_of_lvds_r8a7796.dts @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rcar_du_of_lvds_r8a7796.dts - Legacy LVDS DT bindings conversion for R8A7796 + * + * Copyright (C) 2018 Laurent Pinchart + */ + +/dts-v1/; +/plugin/; +/ { + fragment@0 { + target-path = "/soc"; + __overlay__ { + #address-cells = <2>; + #size-cells = <2>; + + lvds@feb90000 { + compatible = "renesas,r8a7796-lvds"; + reg = <0 0xfeb90000 0 0x14>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds0_input: endpoint { + }; + }; + port@1 { + reg = <1>; + lvds0_out: endpoint { + }; + }; + }; + }; + }; + }; + + fragment@1 { + target-path = "/soc/display@feb00000/ports"; + __overlay__ { + port@3 { + endpoint { + remote-endpoint = <&lvds0_input>; + }; + }; + }; + }; +}; -- cgit v1.2.3 From c6a27fa41fabb35fcf0273c32a86f1424fa7de91 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 10 Jan 2018 05:47:42 +0200 Subject: drm: rcar-du: Convert LVDS encoder code to bridge driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LVDS encoders used to be described in DT as part of the DU. They now have their own DT node, linked to the DU using the OF graph bindings. This allows moving internal LVDS encoder support to a separate driver modelled as a DRM bridge. Backward compatibility is retained as legacy DT is patched live to move to the new bindings. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- drivers/gpu/drm/rcar-du/Kconfig | 4 +- drivers/gpu/drm/rcar-du/Makefile | 3 +- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 21 +- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 5 - drivers/gpu/drm/rcar-du/rcar_du_encoder.c | 175 +--------- drivers/gpu/drm/rcar-du/rcar_du_encoder.h | 12 - drivers/gpu/drm/rcar-du/rcar_du_kms.c | 14 +- drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c | 93 ------ drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h | 24 -- drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c | 238 -------------- drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h | 64 ---- drivers/gpu/drm/rcar-du/rcar_lvds.c | 524 ++++++++++++++++++++++++++++++ 12 files changed, 561 insertions(+), 616 deletions(-) delete mode 100644 drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c delete mode 100644 drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h delete mode 100644 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c delete mode 100644 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h create mode 100644 drivers/gpu/drm/rcar-du/rcar_lvds.c (limited to 'drivers') diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 3f83352a7313..edde8d4b87a3 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -19,8 +19,8 @@ config DRM_RCAR_DW_HDMI Enable support for R-Car Gen3 internal HDMI encoder. config DRM_RCAR_LVDS - bool "R-Car DU LVDS Encoder Support" - depends on DRM_RCAR_DU + tristate "R-Car DU LVDS Encoder Support" + depends on DRM && DRM_BRIDGE && OF select DRM_PANEL select OF_FLATTREE select OF_OVERLAY diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 86b337b4be5d..3e58ed93d5b1 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -4,10 +4,8 @@ rcar-du-drm-y := rcar_du_crtc.o \ rcar_du_encoder.o \ rcar_du_group.o \ rcar_du_kms.o \ - rcar_du_lvdscon.o \ rcar_du_plane.o -rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_lvdsenc.o rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_of.o \ rcar_du_of_lvds_r8a7790.dtb.o \ rcar_du_of_lvds_r8a7791.dtb.o \ @@ -18,3 +16,4 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_VSP) += rcar_du_vsp.o obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o +obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 6e02c762a557..06a3fbdd728a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -29,6 +29,7 @@ #include "rcar_du_drv.h" #include "rcar_du_kms.h" +#include "rcar_du_of.h" #include "rcar_du_regs.h" /* ----------------------------------------------------------------------------- @@ -74,7 +75,6 @@ static const struct rcar_du_device_info rzg1_du_r8a7745_info = { .port = 1, }, }, - .num_lvds = 0, }; static const struct rcar_du_device_info rcar_du_r8a7779_info = { @@ -95,14 +95,13 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = { .port = 1, }, }, - .num_lvds = 0, }; static const struct rcar_du_device_info rcar_du_r8a7790_info = { .gen = 2, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_EXT_CTRL_REGS, - .quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES, + .quirks = RCAR_DU_QUIRK_ALIGN_128B, .num_crtcs = 3, .routes = { /* @@ -164,7 +163,6 @@ static const struct rcar_du_device_info rcar_du_r8a7792_info = { .port = 1, }, }, - .num_lvds = 0, }; static const struct rcar_du_device_info rcar_du_r8a7794_info = { @@ -186,7 +184,6 @@ static const struct rcar_du_device_info rcar_du_r8a7794_info = { .port = 1, }, }, - .num_lvds = 0, }; static const struct rcar_du_device_info rcar_du_r8a7795_info = { @@ -434,7 +431,19 @@ static struct platform_driver rcar_du_platform_driver = { }, }; -module_platform_driver(rcar_du_platform_driver); +static int __init rcar_du_init(void) +{ + rcar_du_of_init(rcar_du_of_table); + + return platform_driver_register(&rcar_du_platform_driver); +} +module_init(rcar_du_init); + +static void __exit rcar_du_exit(void) +{ + platform_driver_unregister(&rcar_du_platform_driver); +} +module_exit(rcar_du_exit); MODULE_AUTHOR("Laurent Pinchart "); MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver"); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index f400fde65a0c..5c7ec15818c7 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -26,14 +26,12 @@ struct device; struct drm_device; struct drm_fbdev_cma; struct rcar_du_device; -struct rcar_du_lvdsenc; #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */ #define RCAR_DU_FEATURE_EXT_CTRL_REGS (1 << 1) /* Has extended control registers */ #define RCAR_DU_FEATURE_VSP1_SOURCE (1 << 2) /* Has inputs from VSP1 */ #define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */ -#define RCAR_DU_QUIRK_LVDS_LANES (1 << 1) /* LVDS lanes 1 and 3 inverted */ /* * struct rcar_du_output_routing - Output routing specification @@ -70,7 +68,6 @@ struct rcar_du_device_info { #define RCAR_DU_MAX_CRTCS 4 #define RCAR_DU_MAX_GROUPS DIV_ROUND_UP(RCAR_DU_MAX_CRTCS, 2) -#define RCAR_DU_MAX_LVDS 2 #define RCAR_DU_MAX_VSPS 4 struct rcar_du_device { @@ -96,8 +93,6 @@ struct rcar_du_device { unsigned int dpad0_source; unsigned int vspd1_sink; - - struct rcar_du_lvdsenc *lvds[RCAR_DU_MAX_LVDS]; }; static inline bool rcar_du_has(struct rcar_du_device *rcdu, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c index ba8d2804c1d1..f9c933d3bae6 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c @@ -21,134 +21,22 @@ #include "rcar_du_drv.h" #include "rcar_du_encoder.h" #include "rcar_du_kms.h" -#include "rcar_du_lvdscon.h" -#include "rcar_du_lvdsenc.h" /* ----------------------------------------------------------------------------- * Encoder */ -static void rcar_du_encoder_disable(struct drm_encoder *encoder) -{ - struct rcar_du_encoder *renc = to_rcar_encoder(encoder); - - if (renc->connector && renc->connector->panel) { - drm_panel_disable(renc->connector->panel); - drm_panel_unprepare(renc->connector->panel); - } - - if (renc->lvds) - rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, false); -} - -static void rcar_du_encoder_enable(struct drm_encoder *encoder) -{ - struct rcar_du_encoder *renc = to_rcar_encoder(encoder); - - if (renc->lvds) - rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, true); - - if (renc->connector && renc->connector->panel) { - drm_panel_prepare(renc->connector->panel); - drm_panel_enable(renc->connector->panel); - } -} - -static int rcar_du_encoder_atomic_check(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct rcar_du_encoder *renc = to_rcar_encoder(encoder); - struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; - const struct drm_display_mode *mode = &crtc_state->mode; - struct drm_connector *connector = conn_state->connector; - struct drm_device *dev = encoder->dev; - - /* - * Only panel-related encoder types require validation here, everything - * else is handled by the bridge drivers. - */ - if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) { - const struct drm_display_mode *panel_mode; - - if (list_empty(&connector->modes)) { - dev_dbg(dev->dev, "encoder: empty modes list\n"); - return -EINVAL; - } - - panel_mode = list_first_entry(&connector->modes, - struct drm_display_mode, head); - - /* We're not allowed to modify the resolution. */ - if (mode->hdisplay != panel_mode->hdisplay || - mode->vdisplay != panel_mode->vdisplay) - return -EINVAL; - - /* - * The flat panel mode is fixed, just copy it to the adjusted - * mode. - */ - drm_mode_copy(adjusted_mode, panel_mode); - } - - if (renc->lvds) - rcar_du_lvdsenc_atomic_check(renc->lvds, adjusted_mode); - - return 0; -} - static void rcar_du_encoder_mode_set(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { struct rcar_du_encoder *renc = to_rcar_encoder(encoder); - struct drm_display_info *info = &conn_state->connector->display_info; - enum rcar_lvds_mode mode; rcar_du_crtc_route_output(crtc_state->crtc, renc->output); - - if (!renc->lvds) { - /* - * The DU driver creates connectors only for the outputs of the - * internal LVDS encoders. - */ - renc->connector = NULL; - return; - } - - renc->connector = to_rcar_connector(conn_state->connector); - - if (!info->num_bus_formats || !info->bus_formats) { - dev_err(encoder->dev->dev, "no LVDS bus format reported\n"); - return; - } - - switch (info->bus_formats[0]) { - case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: - case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: - mode = RCAR_LVDS_MODE_JEIDA; - break; - case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: - mode = RCAR_LVDS_MODE_VESA; - break; - default: - dev_err(encoder->dev->dev, - "unsupported LVDS bus format 0x%04x\n", - info->bus_formats[0]); - return; - } - - if (info->bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB) - mode |= RCAR_LVDS_MODE_MIRROR; - - rcar_du_lvdsenc_set_mode(renc->lvds, mode); } static const struct drm_encoder_helper_funcs encoder_helper_funcs = { .atomic_mode_set = rcar_du_encoder_mode_set, - .disable = rcar_du_encoder_disable, - .enable = rcar_du_encoder_enable, - .atomic_check = rcar_du_encoder_atomic_check, }; static const struct drm_encoder_funcs encoder_funcs = { @@ -172,33 +60,14 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, renc->output = output; encoder = rcar_encoder_to_drm_encoder(renc); - switch (output) { - case RCAR_DU_OUTPUT_LVDS0: - renc->lvds = rcdu->lvds[0]; - break; + dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n", + enc_node, output); - case RCAR_DU_OUTPUT_LVDS1: - renc->lvds = rcdu->lvds[1]; - break; - - default: - break; - } - - if (enc_node) { - dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n", - enc_node, output); - - /* Locate the DRM bridge from the encoder DT node. */ - bridge = of_drm_find_bridge(enc_node); - if (!bridge) { - ret = -EPROBE_DEFER; - goto done; - } - } else { - dev_dbg(rcdu->dev, - "initializing internal encoder for output %u\n", - output); + /* Locate the DRM bridge from the encoder DT node. */ + bridge = of_drm_find_bridge(enc_node); + if (!bridge) { + ret = -EPROBE_DEFER; + goto done; } ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs, @@ -208,28 +77,14 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, drm_encoder_helper_add(encoder, &encoder_helper_funcs); - if (bridge) { - /* - * Attach the bridge to the encoder. The bridge will create the - * connector. - */ - ret = drm_bridge_attach(encoder, bridge, NULL); - if (ret) { - drm_encoder_cleanup(encoder); - return ret; - } - } else { - /* There's no bridge, create the connector manually. */ - switch (output) { - case RCAR_DU_OUTPUT_LVDS0: - case RCAR_DU_OUTPUT_LVDS1: - ret = rcar_du_lvds_connector_init(rcdu, renc, con_node); - break; - - default: - ret = -EINVAL; - break; - } + /* + * Attach the bridge to the encoder. The bridge will create the + * connector. + */ + ret = drm_bridge_attach(encoder, bridge, NULL); + if (ret) { + drm_encoder_cleanup(encoder); + return ret; } done: diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h index 5422fa4df272..2d2abcacd169 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h @@ -19,13 +19,10 @@ struct drm_panel; struct rcar_du_device; -struct rcar_du_lvdsenc; struct rcar_du_encoder { struct drm_encoder base; enum rcar_du_output output; - struct rcar_du_connector *connector; - struct rcar_du_lvdsenc *lvds; }; #define to_rcar_encoder(e) \ @@ -33,15 +30,6 @@ struct rcar_du_encoder { #define rcar_encoder_to_drm_encoder(e) (&(e)->base) -struct rcar_du_connector { - struct drm_connector connector; - struct rcar_du_encoder *encoder; - struct drm_panel *panel; -}; - -#define to_rcar_connector(c) \ - container_of(c, struct rcar_du_connector, connector) - int rcar_du_encoder_init(struct rcar_du_device *rcdu, enum rcar_du_output output, struct device_node *enc_node, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 566d1a948c8f..0329b354bfa0 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -27,7 +27,6 @@ #include "rcar_du_drv.h" #include "rcar_du_encoder.h" #include "rcar_du_kms.h" -#include "rcar_du_lvdsenc.h" #include "rcar_du_regs.h" #include "rcar_du_vsp.h" @@ -341,11 +340,10 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, of_node_put(entity_ep_node); if (!encoder) { - /* - * If no encoder has been found the entity must be the - * connector. - */ - connector = entity; + dev_warn(rcdu->dev, + "no encoder found for endpoint %pOF, skipping\n", + ep->local_node); + return -ENODEV; } ret = rcar_du_encoder_init(rcdu, output, encoder, connector); @@ -595,10 +593,6 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) } /* Initialize the encoders. */ - ret = rcar_du_lvdsenc_init(rcdu); - if (ret < 0) - return ret; - ret = rcar_du_encoders_init(rcdu); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c deleted file mode 100644 index e96f2df0c305..000000000000 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * rcar_du_lvdscon.c -- R-Car Display Unit LVDS Connector - * - * Copyright (C) 2013-2014 Renesas Electronics Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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. - */ - -#include -#include -#include -#include -#include - -#include