Skip to content

Commit a3a39f2

Browse files
authored
Merge pull request #28 from RanderWang/ipx_fix
Fix IPC timeout issue on APL&CNL
2 parents ad3c0e1 + d597225 commit a3a39f2

10 files changed

Lines changed: 202 additions & 114 deletions

File tree

sound/soc/sof/intel/bdw.c

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ static const struct snd_sof_debugfs_map bdw_debugfs[] = {
7070
{"shim", BDW_DSP_BAR, SHIM_OFFSET, SHIM_SIZE},
7171
};
7272

73+
static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir);
74+
7375
/*
7476
* Memory copy.
7577
*/
@@ -361,15 +363,16 @@ static irqreturn_t bdw_irq_thread(int irq, void *context)
361363
/* Handle Immediate reply from DSP Core */
362364
bdw_mailbox_read(sdev, sdev->host_box.offset, &hdr,
363365
sizeof(hdr));
364-
snd_sof_ipc_reply(sdev, hdr);
365-
366-
/* clear DONE bit - tell DSP we have completed */
367-
snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCX,
368-
SHIM_IPCX_DONE, 0);
369366

370-
/* unmask Done interrupt */
371-
snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX,
372-
SHIM_IMRX_DONE, 0);
367+
/*
368+
* handle immediate reply from DSP core. If the msg is
369+
* found, set done bit in cmd_done which is called at the
370+
* end of message processing function, else set it here
371+
* because the done bit can't be set in cmd_done function
372+
* which is triggered by msg
373+
*/
374+
if (snd_sof_ipc_reply(sdev, hdr))
375+
bdw_cmd_done(sdev, SOF_IPC_DSP_REPLY);
373376
}
374377

375378
ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD);
@@ -526,7 +529,7 @@ static int bdw_is_ready(struct snd_sof_dev *sdev)
526529
u32 val;
527530

528531
val = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCX);
529-
if (val & SHIM_IPCX_BUSY)
532+
if ((val & SHIM_IPCX_BUSY) || (val & SHIM_IPCX_DONE))
530533
return 0;
531534

532535
return 1;
@@ -573,16 +576,26 @@ static int bdw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
573576
return ret;
574577
}
575578

576-
static int bdw_cmd_done(struct snd_sof_dev *sdev)
579+
static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir)
577580
{
578-
/* clear BUSY bit and set DONE bit - accept new messages */
579-
snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCD,
580-
SHIM_IPCD_BUSY | SHIM_IPCD_DONE,
581-
SHIM_IPCD_DONE);
582-
583-
/* unmask busy interrupt */
584-
snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX,
585-
SHIM_IMRX_BUSY, 0);
581+
if (dir == SOF_IPC_HOST_REPLY) {
582+
/* clear BUSY bit and set DONE bit - accept new messages */
583+
snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCD,
584+
SHIM_IPCD_BUSY | SHIM_IPCD_DONE,
585+
SHIM_IPCD_DONE);
586+
587+
/* unmask busy interrupt */
588+
snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX,
589+
SHIM_IMRX_BUSY, 0);
590+
} else {
591+
/* clear DONE bit - tell DSP we have completed */
592+
snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCX,
593+
SHIM_IPCX_DONE, 0);
594+
595+
/* unmask Done interrupt */
596+
snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX,
597+
SHIM_IMRX_DONE, 0);
598+
}
586599

587600
return 0;
588601
}

sound/soc/sof/intel/byt.c

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ static const struct snd_sof_debugfs_map cht_debugfs[] = {
9595
{"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE},
9696
};
9797

98+
static int byt_cmd_done(struct snd_sof_dev *sdev, int dir);
99+
98100
/*
99101
* Register IO
100102
*/
@@ -376,16 +378,15 @@ static irqreturn_t byt_irq_thread(int irq, void *context)
376378

377379
/* reply message from DSP */
378380
if (ipcx & SHIM_BYT_IPCX_DONE) {
379-
/* Handle Immediate reply from DSP Core */
380-
snd_sof_ipc_reply(sdev, ipcx);
381-
382-
/* clear DONE bit - tell DSP we have completed */
383-
snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCX,
384-
SHIM_BYT_IPCX_DONE, 0);
385-
386-
/* unmask Done interrupt */
387-
snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX,
388-
SHIM_IMRX_DONE, 0);
381+
/*
382+
* handle immediate reply from DSP core. If the msg is
383+
* found, set done bit in cmd_done which is called at the
384+
* end of message processing function, else set it here
385+
* because the done bit can't be set in cmd_done function
386+
* which is triggered by msg
387+
*/
388+
if (snd_sof_ipc_reply(sdev, ipcx))
389+
byt_cmd_done(sdev, SOF_IPC_DSP_REPLY);
389390
}
390391

391392
/* new message from DSP */
@@ -405,10 +406,11 @@ static irqreturn_t byt_irq_thread(int irq, void *context)
405406

406407
static int byt_is_ready(struct snd_sof_dev *sdev)
407408
{
408-
u64 imrx;
409+
u64 imrx, ipcx;
409410

410411
imrx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IMRX);
411-
if (imrx & SHIM_IMRX_DONE)
412+
ipcx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX);
413+
if ((imrx & SHIM_IMRX_DONE) || (ipcx & SHIM_BYT_IPCX_DONE))
412414
return 0;
413415

414416
return 1;
@@ -458,17 +460,27 @@ static int byt_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
458460
return ret;
459461
}
460462

461-
static int byt_cmd_done(struct snd_sof_dev *sdev)
463+
static int byt_cmd_done(struct snd_sof_dev *sdev, int dir)
462464
{
463-
/* clear BUSY bit and set DONE bit - accept new messages */
464-
snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCD,
465-
SHIM_BYT_IPCD_BUSY |
466-
SHIM_BYT_IPCD_DONE,
467-
SHIM_BYT_IPCD_DONE);
465+
if (dir == SOF_IPC_HOST_REPLY) {
466+
/* clear BUSY bit and set DONE bit - accept new messages */
467+
snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCD,
468+
SHIM_BYT_IPCD_BUSY |
469+
SHIM_BYT_IPCD_DONE,
470+
SHIM_BYT_IPCD_DONE);
468471

469-
/* unmask busy interrupt */
470-
snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX,
471-
SHIM_IMRX_BUSY, 0);
472+
/* unmask busy interrupt */
473+
snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX,
474+
SHIM_IMRX_BUSY, 0);
475+
} else {
476+
/* clear DONE bit - tell DSP we have completed */
477+
snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCX,
478+
SHIM_BYT_IPCX_DONE, 0);
479+
480+
/* unmask Done interrupt */
481+
snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX,
482+
SHIM_IMRX_DONE, 0);
483+
}
472484

473485
return 0;
474486
}

sound/soc/sof/intel/cnl.c

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = {
4040
{"dsp", HDA_DSP_BAR, 0, 0x10000},
4141
};
4242

43+
static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
44+
4345
static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
4446
{
4547
struct snd_sof_dev *sdev = (struct snd_sof_dev *)context;
@@ -69,20 +71,15 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
6971
CNL_DSP_REG_HIPCCTL,
7072
CNL_DSP_REG_HIPCCTL_DONE, 0);
7173

72-
/* handle immediate reply from DSP core */
73-
snd_sof_ipc_reply(sdev, msg);
74-
75-
/* clear DONE bit - tell DSP we have completed the operation */
76-
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
77-
CNL_DSP_REG_HIPCIDA,
78-
CNL_DSP_REG_HIPCIDA_DONE,
79-
CNL_DSP_REG_HIPCIDA_DONE);
80-
81-
/* unmask Done interrupt */
82-
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
83-
CNL_DSP_REG_HIPCCTL,
84-
CNL_DSP_REG_HIPCCTL_DONE,
85-
CNL_DSP_REG_HIPCCTL_DONE);
74+
/*
75+
* handle immediate reply from DSP core. If the msg is
76+
* found, set done bit in cmd_done which is called at the
77+
* end of message processing function, else set it here
78+
* because the done bit can't be set in cmd_done function
79+
* which is triggered by msg
80+
*/
81+
if (snd_sof_ipc_reply(sdev, msg))
82+
cnl_ipc_cmd_done(sdev, SOF_IPC_DSP_REPLY);
8683

8784
ret = IRQ_HANDLED;
8885
}
@@ -108,8 +105,10 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
108105
snd_sof_ipc_msgs_rx(sdev);
109106
}
110107

111-
/* clear busy interrupt to tell dsp controller this */
112-
/* interrupt has been accepted, not trigger it again */
108+
/*
109+
* clear busy interrupt to tell dsp controller this
110+
* interrupt has been accepted, not trigger it again
111+
*/
113112
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
114113
CNL_DSP_REG_HIPCTDR,
115114
CNL_DSP_REG_HIPCTDR_BUSY,
@@ -132,23 +131,45 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
132131
return ret;
133132
}
134133

135-
static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev)
134+
static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir)
136135
{
137-
/* set done bit to ack dsp the msg has been processed */
138-
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
139-
CNL_DSP_REG_HIPCTDA,
140-
CNL_DSP_REG_HIPCTDA_DONE,
141-
CNL_DSP_REG_HIPCTDA_DONE);
136+
if (dir == SOF_IPC_HOST_REPLY) {
137+
/*
138+
* set done bit to ack dsp the msg has been
139+
* processed and send reply msg to dsp
140+
*/
141+
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
142+
CNL_DSP_REG_HIPCTDA,
143+
CNL_DSP_REG_HIPCTDA_DONE,
144+
CNL_DSP_REG_HIPCTDA_DONE);
145+
} else {
146+
/*
147+
* set DONE bit - tell DSP we have received the reply msg
148+
* from DSP, and processed it, don't send more reply to host
149+
*/
150+
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
151+
CNL_DSP_REG_HIPCIDA,
152+
CNL_DSP_REG_HIPCIDA_DONE,
153+
CNL_DSP_REG_HIPCIDA_DONE);
154+
155+
/* unmask Done interrupt */
156+
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
157+
CNL_DSP_REG_HIPCCTL,
158+
CNL_DSP_REG_HIPCCTL_DONE,
159+
CNL_DSP_REG_HIPCCTL_DONE);
160+
}
142161

143162
return 0;
144163
}
145164

146165
static int cnl_ipc_is_ready(struct snd_sof_dev *sdev)
147166
{
148-
u64 val;
167+
u64 busy, done;
149168

150-
val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR);
151-
if (val & CNL_DSP_REG_HIPCIDR_BUSY)
169+
busy = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR);
170+
done = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA);
171+
if ((busy & CNL_DSP_REG_HIPCIDR_BUSY) ||
172+
(done & CNL_DSP_REG_HIPCIDA_DONE))
152173
return 0;
153174

154175
return 1;

sound/soc/sof/intel/hda-ipc.c

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,46 @@
3434
#include "../ops.h"
3535
#include "hda.h"
3636

37-
int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev)
37+
int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir)
3838
{
39-
/* tell DSP cmd is done - clear busy interrupt */
40-
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
41-
HDA_DSP_REG_HIPCT,
42-
HDA_DSP_REG_HIPCT_BUSY,
43-
HDA_DSP_REG_HIPCT_BUSY);
39+
if (dir == SOF_IPC_HOST_REPLY) {
40+
/*
41+
* tell DSP cmd is done - clear busy
42+
* interrupt and send reply msg to dsp
43+
*/
44+
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
45+
HDA_DSP_REG_HIPCT,
46+
HDA_DSP_REG_HIPCT_BUSY,
47+
HDA_DSP_REG_HIPCT_BUSY);
48+
} else {
49+
/*
50+
* set DONE bit - tell DSP we have received the reply msg
51+
* from DSP, and processed it, don't send more reply to host
52+
*/
53+
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
54+
HDA_DSP_REG_HIPCIE,
55+
HDA_DSP_REG_HIPCIE_DONE,
56+
HDA_DSP_REG_HIPCIE_DONE);
57+
58+
/* unmask Done interrupt */
59+
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
60+
HDA_DSP_REG_HIPCCTL,
61+
HDA_DSP_REG_HIPCCTL_DONE,
62+
HDA_DSP_REG_HIPCCTL_DONE);
63+
}
64+
4465
return 0;
4566
}
4667

4768
int hda_dsp_ipc_is_ready(struct snd_sof_dev *sdev)
4869
{
49-
u64 val;
70+
u64 busy, done;
5071

5172
/* is DSP ready for next IPC command */
52-
val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI);
53-
if (val & HDA_DSP_REG_HIPCI_BUSY)
73+
busy = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI);
74+
done = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
75+
if ((busy & HDA_DSP_REG_HIPCI_BUSY) ||
76+
(done & HDA_DSP_REG_HIPCIE_DONE))
5477
return 0;
5578

5679
return 1;
@@ -108,6 +131,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
108131
struct snd_sof_dev *sdev = (struct snd_sof_dev *)context;
109132
u32 hipci, hipcie, hipct, hipcte, msg = 0, msg_ext = 0;
110133
irqreturn_t ret = IRQ_NONE;
134+
int reply = -EINVAL;
111135

112136
/* here we handle IPC interrupts only */
113137
if (!(sdev->irq_status & HDA_DSP_ADSPIS_IPC))
@@ -137,19 +161,17 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
137161

138162
/* handle immediate reply from DSP core - ignore ROM messages */
139163
if (msg != 0x1004000)
140-
snd_sof_ipc_reply(sdev, msg);
141-
142-
/* clear DONE bit - tell DSP we have completed the operation */
143-
snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
144-
HDA_DSP_REG_HIPCIE,
145-
HDA_DSP_REG_HIPCIE_DONE,
146-
HDA_DSP_REG_HIPCIE_DONE);
147-
148-
/* unmask Done interrupt */
149-
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
150-
HDA_DSP_REG_HIPCCTL,
151-
HDA_DSP_REG_HIPCCTL_DONE,
152-
HDA_DSP_REG_HIPCCTL_DONE);
164+
reply = snd_sof_ipc_reply(sdev, msg);
165+
166+
/*
167+
* handle immediate reply from DSP core. If the msg is
168+
* found, set done bit in cmd_done which is called at the
169+
* end of message processing function, else set it here
170+
* because the done bit can't be set in cmd_done function
171+
* which is triggered by msg
172+
*/
173+
if (reply)
174+
hda_dsp_ipc_cmd_done(sdev, SOF_IPC_DSP_REPLY);
153175

154176
ret = IRQ_HANDLED;
155177
}

sound/soc/sof/intel/hda.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev,
473473
int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id);
474474
irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context);
475475
irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context);
476-
int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev);
476+
int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
477477

478478
/*
479479
* DSP Code loader.

0 commit comments

Comments
 (0)