aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2018-09-10 10:20:25 -0400
committerTakashi Iwai <tiwai@suse.de>2018-09-13 11:58:30 -0400
commit37a3a98ef601f89100e3bb657fb0e190b857028c (patch)
treee2240c2283f9122ef89f011218800821adec43a9
parent498fe23aad8e3b5a9554f55719c537603b4476ea (diff)
ALSA: hda - Enable runtime PM only for discrete GPU
The recent change of vga_switcheroo allowed the runtime PM for HD-audio on AMD GPUs, but this also resulted in a regression. When the HD-audio controller driver gets runtime-suspended, HD-audio link is turned off, and the hotplug notification is ignored. This leads to the inconsistent audio state (the connection isn't notified and ELD is ignored). The best fix would be to implement the proper ELD notification via the audio component, but it's still not ready. As a quick workaround, this patch adds the check of runtime_idle and allows the runtime suspend only when the vga_switcheroo is bound with discrete GPU. That is, a system with a single GPU and APU would be again without runtime PM to keep the HD-audio link for the hotplug notification and ELD read out. Also, the codec->auto_runtime_pm flag is set only for the discrete GPU at the time GPU gets bound via vga_switcheroo (i.e. only dGPU is forcibly runtime-PM enabled), so that APU can still get the ELD notification. For identifying which GPU is bound, a new vga_switcheroo client callback, gpu_bound, is implemented. The vga_switcheroo simply calls this when GPU is bound, and tells whether it's dGPU or APU. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=200945 Fixes: 07f4f97d7b4b ("vga_switcheroo: Use device link for HDA controller") Reported-by: Jian-Hong Pan <jian-hong@endlessm.com> Tested-by: Jian-Hong Pan <jian-hong@endlessm.com> Acked-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c2
-rw-r--r--include/linux/vga_switcheroo.h3
-rw-r--r--sound/pci/hda/hda_intel.c86
-rw-r--r--sound/pci/hda/hda_intel.h1
4 files changed, 69 insertions, 23 deletions
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index a96bf46bc483..cf2a18571d48 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -215,6 +215,8 @@ static void vga_switcheroo_enable(void)
215 return; 215 return;
216 216
217 client->id = ret | ID_BIT_AUDIO; 217 client->id = ret | ID_BIT_AUDIO;
218 if (client->ops->gpu_bound)
219 client->ops->gpu_bound(client->pdev, ret);
218 } 220 }
219 221
220 vga_switcheroo_debugfs_init(&vgasr_priv); 222 vga_switcheroo_debugfs_init(&vgasr_priv);
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index a34539b7f750..7e6ac0114d55 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -133,15 +133,18 @@ struct vga_switcheroo_handler {
133 * @can_switch: check if the device is in a position to switch now. 133 * @can_switch: check if the device is in a position to switch now.
134 * Mandatory. The client should return false if a user space process 134 * Mandatory. The client should return false if a user space process
135 * has one of its device files open 135 * has one of its device files open
136 * @gpu_bound: notify the client id to audio client when the GPU is bound.
136 * 137 *
137 * Client callbacks. A client can be either a GPU or an audio device on a GPU. 138 * Client callbacks. A client can be either a GPU or an audio device on a GPU.
138 * The @set_gpu_state and @can_switch methods are mandatory, @reprobe may be 139 * The @set_gpu_state and @can_switch methods are mandatory, @reprobe may be
139 * set to NULL. For audio clients, the @reprobe member is bogus. 140 * set to NULL. For audio clients, the @reprobe member is bogus.
141 * OTOH, @gpu_bound is only for audio clients, and not used for GPU clients.
140 */ 142 */
141struct vga_switcheroo_client_ops { 143struct vga_switcheroo_client_ops {
142 void (*set_gpu_state)(struct pci_dev *dev, enum vga_switcheroo_state); 144 void (*set_gpu_state)(struct pci_dev *dev, enum vga_switcheroo_state);
143 void (*reprobe)(struct pci_dev *dev); 145 void (*reprobe)(struct pci_dev *dev);
144 bool (*can_switch)(struct pci_dev *dev); 146 bool (*can_switch)(struct pci_dev *dev);
147 void (*gpu_bound)(struct pci_dev *dev, enum vga_switcheroo_client_id);
145}; 148};
146 149
147#if defined(CONFIG_VGA_SWITCHEROO) 150#if defined(CONFIG_VGA_SWITCHEROO)
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 1b2ce304152a..aa4c672dbaf7 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -365,8 +365,10 @@ enum {
365 */ 365 */
366#ifdef SUPPORT_VGA_SWITCHEROO 366#ifdef SUPPORT_VGA_SWITCHEROO
367#define use_vga_switcheroo(chip) ((chip)->use_vga_switcheroo) 367#define use_vga_switcheroo(chip) ((chip)->use_vga_switcheroo)
368#define needs_eld_notify_link(chip) ((chip)->need_eld_notify_link)
368#else 369#else
369#define use_vga_switcheroo(chip) 0 370#define use_vga_switcheroo(chip) 0
371#define needs_eld_notify_link(chip) false
370#endif 372#endif
371 373
372#define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \ 374#define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \
@@ -453,6 +455,7 @@ static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
453#endif 455#endif
454 456
455static int azx_acquire_irq(struct azx *chip, int do_disconnect); 457static int azx_acquire_irq(struct azx *chip, int do_disconnect);
458static void set_default_power_save(struct azx *chip);
456 459
457/* 460/*
458 * initialize the PCI registers 461 * initialize the PCI registers
@@ -1201,6 +1204,10 @@ static int azx_runtime_idle(struct device *dev)
1201 azx_bus(chip)->codec_powered || !chip->running) 1204 azx_bus(chip)->codec_powered || !chip->running)
1202 return -EBUSY; 1205 return -EBUSY;
1203 1206
1207 /* ELD notification gets broken when HD-audio bus is off */
1208 if (needs_eld_notify_link(hda))
1209 return -EBUSY;
1210
1204 return 0; 1211 return 0;
1205} 1212}
1206 1213
@@ -1298,6 +1305,36 @@ static bool azx_vs_can_switch(struct pci_dev *pci)
1298 return true; 1305 return true;
1299} 1306}
1300 1307
1308/*
1309 * The discrete GPU cannot power down unless the HDA controller runtime
1310 * suspends, so activate runtime PM on codecs even if power_save == 0.
1311 */
1312static void setup_vga_switcheroo_runtime_pm(struct azx *chip)
1313{
1314 struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
1315 struct hda_codec *codec;
1316
1317 if (hda->use_vga_switcheroo && !hda->need_eld_notify_link) {
1318 list_for_each_codec(codec, &chip->bus)
1319 codec->auto_runtime_pm = 1;
1320 /* reset the power save setup */
1321 if (chip->running)
1322 set_default_power_save(chip);
1323 }
1324}
1325
1326static void azx_vs_gpu_bound(struct pci_dev *pci,
1327 enum vga_switcheroo_client_id client_id)
1328{
1329 struct snd_card *card = pci_get_drvdata(pci);
1330 struct azx *chip = card->private_data;
1331 struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
1332
1333 if (client_id == VGA_SWITCHEROO_DIS)
1334 hda->need_eld_notify_link = 0;
1335 setup_vga_switcheroo_runtime_pm(chip);
1336}
1337
1301static void init_vga_switcheroo(struct azx *chip) 1338static void init_vga_switcheroo(struct azx *chip)
1302{ 1339{
1303 struct hda_intel *hda = container_of(chip, struct hda_intel, chip); 1340 struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
@@ -1306,6 +1343,7 @@ static void init_vga_switcheroo(struct azx *chip)
1306 dev_info(chip->card->dev, 1343 dev_info(chip->card->dev,
1307 "Handle vga_switcheroo audio client\n"); 1344 "Handle vga_switcheroo audio client\n");
1308 hda->use_vga_switcheroo = 1; 1345 hda->use_vga_switcheroo = 1;
1346 hda->need_eld_notify_link = 1; /* cleared in gpu_bound op */
1309 chip->driver_caps |= AZX_DCAPS_PM_RUNTIME; 1347 chip->driver_caps |= AZX_DCAPS_PM_RUNTIME;
1310 pci_dev_put(p); 1348 pci_dev_put(p);
1311 } 1349 }
@@ -1314,6 +1352,7 @@ static void init_vga_switcheroo(struct azx *chip)
1314static const struct vga_switcheroo_client_ops azx_vs_ops = { 1352static const struct vga_switcheroo_client_ops azx_vs_ops = {
1315 .set_gpu_state = azx_vs_set_state, 1353 .set_gpu_state = azx_vs_set_state,
1316 .can_switch = azx_vs_can_switch, 1354 .can_switch = azx_vs_can_switch,
1355 .gpu_bound = azx_vs_gpu_bound,
1317}; 1356};
1318 1357
1319static int register_vga_switcheroo(struct azx *chip) 1358static int register_vga_switcheroo(struct azx *chip)
@@ -1339,6 +1378,7 @@ static int register_vga_switcheroo(struct azx *chip)
1339#define init_vga_switcheroo(chip) /* NOP */ 1378#define init_vga_switcheroo(chip) /* NOP */
1340#define register_vga_switcheroo(chip) 0 1379#define register_vga_switcheroo(chip) 0
1341#define check_hdmi_disabled(pci) false 1380#define check_hdmi_disabled(pci) false
1381#define setup_vga_switcheroo_runtime_pm(chip) /* NOP */
1342#endif /* SUPPORT_VGA_SWITCHER */ 1382#endif /* SUPPORT_VGA_SWITCHER */
1343 1383
1344/* 1384/*
@@ -1352,6 +1392,7 @@ static int azx_free(struct azx *chip)
1352 1392
1353 if (azx_has_pm_runtime(chip) && chip->running) 1393 if (azx_has_pm_runtime(chip) && chip->running)
1354 pm_runtime_get_noresume(&pci->dev); 1394 pm_runtime_get_noresume(&pci->dev);
1395 chip->running = 0;
1355 1396
1356 azx_del_card_list(chip); 1397 azx_del_card_list(chip);
1357 1398
@@ -2230,6 +2271,25 @@ static struct snd_pci_quirk power_save_blacklist[] = {
2230}; 2271};
2231#endif /* CONFIG_PM */ 2272#endif /* CONFIG_PM */
2232 2273
2274static void set_default_power_save(struct azx *chip)
2275{
2276 int val = power_save;
2277
2278#ifdef CONFIG_PM
2279 if (pm_blacklist) {
2280 const struct snd_pci_quirk *q;
2281
2282 q = snd_pci_quirk_lookup(chip->pci, power_save_blacklist);
2283 if (q && val) {
2284 dev_info(chip->card->dev, "device %04x:%04x is on the power_save blacklist, forcing power_save to 0\n",
2285 q->subvendor, q->subdevice);
2286 val = 0;
2287 }
2288 }
2289#endif /* CONFIG_PM */
2290 snd_hda_set_power_save(&chip->bus, val * 1000);
2291}
2292
2233/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */ 2293/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
2234static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = { 2294static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {
2235 [AZX_DRIVER_NVIDIA] = 8, 2295 [AZX_DRIVER_NVIDIA] = 8,
@@ -2241,9 +2301,7 @@ static int azx_probe_continue(struct azx *chip)
2241 struct hda_intel *hda = container_of(chip, struct hda_intel, chip); 2301 struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
2242 struct hdac_bus *bus = azx_bus(chip); 2302 struct hdac_bus *bus = azx_bus(chip);
2243 struct pci_dev *pci = chip->pci; 2303 struct pci_dev *pci = chip->pci;
2244 struct hda_codec *codec;
2245 int dev = chip->dev_index; 2304 int dev = chip->dev_index;
2246 int val;
2247 int err; 2305 int err;
2248 2306
2249 hda->probe_continued = 1; 2307 hda->probe_continued = 1;
@@ -2322,31 +2380,13 @@ static int azx_probe_continue(struct azx *chip)
2322 if (err < 0) 2380 if (err < 0)
2323 goto out_free; 2381 goto out_free;
2324 2382
2383 setup_vga_switcheroo_runtime_pm(chip);
2384
2325 chip->running = 1; 2385 chip->running = 1;
2326 azx_add_card_list(chip); 2386 azx_add_card_list(chip);
2327 2387
2328 val = power_save; 2388 set_default_power_save(chip);
2329#ifdef CONFIG_PM
2330 if (pm_blacklist) {
2331 const struct snd_pci_quirk *q;
2332
2333 q = snd_pci_quirk_lookup(chip->pci, power_save_blacklist);
2334 if (q && val) {
2335 dev_info(chip->card->dev, "device %04x:%04x is on the power_save blacklist, forcing power_save to 0\n",
2336 q->subvendor, q->subdevice);
2337 val = 0;
2338 }
2339 }
2340#endif /* CONFIG_PM */
2341 /*
2342 * The discrete GPU cannot power down unless the HDA controller runtime
2343 * suspends, so activate runtime PM on codecs even if power_save == 0.
2344 */
2345 if (use_vga_switcheroo(hda))
2346 list_for_each_codec(codec, &chip->bus)
2347 codec->auto_runtime_pm = 1;
2348 2389
2349 snd_hda_set_power_save(&chip->bus, val * 1000);
2350 if (azx_has_pm_runtime(chip)) 2390 if (azx_has_pm_runtime(chip))
2351 pm_runtime_put_autosuspend(&pci->dev); 2391 pm_runtime_put_autosuspend(&pci->dev);
2352 2392
diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h
index e3a3d318d2e5..f59719e06b91 100644
--- a/sound/pci/hda/hda_intel.h
+++ b/sound/pci/hda/hda_intel.h
@@ -37,6 +37,7 @@ struct hda_intel {
37 37
38 /* vga_switcheroo setup */ 38 /* vga_switcheroo setup */
39 unsigned int use_vga_switcheroo:1; 39 unsigned int use_vga_switcheroo:1;
40 unsigned int need_eld_notify_link:1;
40 unsigned int vga_switcheroo_registered:1; 41 unsigned int vga_switcheroo_registered:1;
41 unsigned int init_failed:1; /* delayed init failed */ 42 unsigned int init_failed:1; /* delayed init failed */
42 43