Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vga_switcheroo: Add missing locking

The following functions iterate over the client list, invoke client
callbacks or invoke handler callbacks without locking anything at all:

- Introduced by c8e9cf7bb240 ("vga_switcheroo: Add a helper function to
get the client state"):
vga_switcheroo_get_client_state()

- Introduced by 0d69704ae348 ("gpu/vga_switcheroo: add driver control
power feature. (v3)"):
vga_switcheroo_set_dynamic_switch()
vga_switcheroo_runtime_suspend()
vga_switcheroo_runtime_resume()
vga_switcheroo_runtime_resume_hdmi_audio()

Refactor vga_switcheroo_runtime_resume_hdmi_audio() a bit to be able to
release vgasr_mutex immediately after iterating over the client list.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

authored by

Lukas Wunner and committed by
Daniel Vetter
8f12a311 945ef5bb

+32 -18
+32 -18
drivers/gpu/vga/vga_switcheroo.c
··· 347 347 int vga_switcheroo_get_client_state(struct pci_dev *pdev) 348 348 { 349 349 struct vga_switcheroo_client *client; 350 + enum vga_switcheroo_state ret; 350 351 352 + mutex_lock(&vgasr_mutex); 351 353 client = find_client_from_pci(&vgasr_priv.clients, pdev); 352 354 if (!client) 353 - return VGA_SWITCHEROO_NOT_FOUND; 354 - if (!vgasr_priv.active) 355 - return VGA_SWITCHEROO_INIT; 356 - return client->pwr_state; 355 + ret = VGA_SWITCHEROO_NOT_FOUND; 356 + else if (!vgasr_priv.active) 357 + ret = VGA_SWITCHEROO_INIT; 358 + else 359 + ret = client->pwr_state; 360 + mutex_unlock(&vgasr_mutex); 361 + return ret; 357 362 } 358 363 EXPORT_SYMBOL(vga_switcheroo_get_client_state); 359 364 ··· 850 845 { 851 846 struct vga_switcheroo_client *client; 852 847 848 + mutex_lock(&vgasr_mutex); 853 849 client = find_client_from_pci(&vgasr_priv.clients, pdev); 854 - if (!client) 850 + if (!client || !client->driver_power_control) { 851 + mutex_unlock(&vgasr_mutex); 855 852 return; 856 - 857 - if (!client->driver_power_control) 858 - return; 853 + } 859 854 860 855 client->pwr_state = dynamic; 861 856 set_audio_state(client->id, dynamic); 857 + mutex_unlock(&vgasr_mutex); 862 858 } 863 859 EXPORT_SYMBOL(vga_switcheroo_set_dynamic_switch); 864 860 ··· 872 866 ret = dev->bus->pm->runtime_suspend(dev); 873 867 if (ret) 874 868 return ret; 869 + mutex_lock(&vgasr_mutex); 875 870 if (vgasr_priv.handler->switchto) 876 871 vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD); 877 872 vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF); 873 + mutex_unlock(&vgasr_mutex); 878 874 return 0; 879 875 } 880 876 ··· 885 877 struct pci_dev *pdev = to_pci_dev(dev); 886 878 int ret; 887 879 880 + mutex_lock(&vgasr_mutex); 888 881 vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON); 882 + mutex_unlock(&vgasr_mutex); 889 883 ret = dev->bus->pm->runtime_resume(dev); 890 884 if (ret) 891 885 return ret; ··· 933 923 static int vga_switcheroo_runtime_resume_hdmi_audio(struct device *dev) 934 924 { 935 925 struct pci_dev *pdev = to_pci_dev(dev); 926 + struct vga_switcheroo_client *client; 927 + struct device *video_dev = NULL; 936 928 int ret; 937 - struct vga_switcheroo_client *client, *found = NULL; 938 929 939 930 /* we need to check if we have to switch back on the video 940 931 device so the audio device can come back */ 932 + mutex_lock(&vgasr_mutex); 941 933 list_for_each_entry(client, &vgasr_priv.clients, list) { 942 934 if (PCI_SLOT(client->pdev->devfn) == PCI_SLOT(pdev->devfn) && 943 935 client_is_vga(client)) { 944 - found = client; 945 - ret = pm_runtime_get_sync(&client->pdev->dev); 946 - if (ret) { 947 - if (ret != 1) 948 - return ret; 949 - } 936 + video_dev = &client->pdev->dev; 950 937 break; 951 938 } 939 + } 940 + mutex_unlock(&vgasr_mutex); 941 + 942 + if (video_dev) { 943 + ret = pm_runtime_get_sync(video_dev); 944 + if (ret && ret != 1) 945 + return ret; 952 946 } 953 947 ret = dev->bus->pm->runtime_resume(dev); 954 948 955 949 /* put the reference for the gpu */ 956 - if (found) { 957 - pm_runtime_mark_last_busy(&found->pdev->dev); 958 - pm_runtime_put_autosuspend(&found->pdev->dev); 950 + if (video_dev) { 951 + pm_runtime_mark_last_busy(video_dev); 952 + pm_runtime_put_autosuspend(video_dev); 959 953 } 960 954 return ret; 961 955 }