diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-09-10 06:21:38 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-09-15 09:52:09 -0400 |
commit | 9bef72bdb26e291d6dffb04768741a0e49582666 (patch) | |
tree | 84d04d67bd5b9c2a7785ae4e9dc65f3e125fe548 /sound/pci/pcxhr/pcxhr_core.c | |
parent | 8d3a8b5cb57da4e327bdaf7c81a90d4105b73205 (diff) |
ALSA: pcxhr: Use nonatomic PCM ops
This time PCXHR, another Digigram boards: like the previous patches,
the conversion is straightforward, replacing spinlocks with mutexes,
merging the irq tasklet into the threaded irq handler and the PCM
trigger tasklet back to the trigger callback.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/pcxhr/pcxhr_core.c')
-rw-r--r-- | sound/pci/pcxhr/pcxhr_core.c | 102 |
1 files changed, 56 insertions, 46 deletions
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index df9371918601..a584acb61c00 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c | |||
@@ -767,11 +767,11 @@ void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh *rmh, int capture, | |||
767 | */ | 767 | */ |
768 | int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) | 768 | int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) |
769 | { | 769 | { |
770 | unsigned long flags; | ||
771 | int err; | 770 | int err; |
772 | spin_lock_irqsave(&mgr->msg_lock, flags); | 771 | |
772 | mutex_lock(&mgr->msg_lock); | ||
773 | err = pcxhr_send_msg_nolock(mgr, rmh); | 773 | err = pcxhr_send_msg_nolock(mgr, rmh); |
774 | spin_unlock_irqrestore(&mgr->msg_lock, flags); | 774 | mutex_unlock(&mgr->msg_lock); |
775 | return err; | 775 | return err; |
776 | } | 776 | } |
777 | 777 | ||
@@ -971,17 +971,16 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask, | |||
971 | unsigned int value, int *changed) | 971 | unsigned int value, int *changed) |
972 | { | 972 | { |
973 | struct pcxhr_rmh rmh; | 973 | struct pcxhr_rmh rmh; |
974 | unsigned long flags; | ||
975 | int err; | 974 | int err; |
976 | 975 | ||
977 | spin_lock_irqsave(&mgr->msg_lock, flags); | 976 | mutex_lock(&mgr->msg_lock); |
978 | if ((mgr->io_num_reg_cont & mask) == value) { | 977 | if ((mgr->io_num_reg_cont & mask) == value) { |
979 | dev_dbg(&mgr->pci->dev, | 978 | dev_dbg(&mgr->pci->dev, |
980 | "IO_NUM_REG_CONT mask %x already is set to %x\n", | 979 | "IO_NUM_REG_CONT mask %x already is set to %x\n", |
981 | mask, value); | 980 | mask, value); |
982 | if (changed) | 981 | if (changed) |
983 | *changed = 0; | 982 | *changed = 0; |
984 | spin_unlock_irqrestore(&mgr->msg_lock, flags); | 983 | mutex_unlock(&mgr->msg_lock); |
985 | return 0; /* already programmed */ | 984 | return 0; /* already programmed */ |
986 | } | 985 | } |
987 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); | 986 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); |
@@ -996,7 +995,7 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask, | |||
996 | if (changed) | 995 | if (changed) |
997 | *changed = 1; | 996 | *changed = 1; |
998 | } | 997 | } |
999 | spin_unlock_irqrestore(&mgr->msg_lock, flags); | 998 | mutex_unlock(&mgr->msg_lock); |
1000 | return err; | 999 | return err; |
1001 | } | 1000 | } |
1002 | 1001 | ||
@@ -1043,22 +1042,21 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err, | |||
1043 | } | 1042 | } |
1044 | 1043 | ||
1045 | 1044 | ||
1046 | void pcxhr_msg_tasklet(unsigned long arg) | 1045 | static void pcxhr_msg_thread(struct pcxhr_mgr *mgr) |
1047 | { | 1046 | { |
1048 | struct pcxhr_mgr *mgr = (struct pcxhr_mgr *)(arg); | ||
1049 | struct pcxhr_rmh *prmh = mgr->prmh; | 1047 | struct pcxhr_rmh *prmh = mgr->prmh; |
1050 | int err; | 1048 | int err; |
1051 | int i, j; | 1049 | int i, j; |
1052 | 1050 | ||
1053 | if (mgr->src_it_dsp & PCXHR_IRQ_FREQ_CHANGE) | 1051 | if (mgr->src_it_dsp & PCXHR_IRQ_FREQ_CHANGE) |
1054 | dev_dbg(&mgr->pci->dev, | 1052 | dev_dbg(&mgr->pci->dev, |
1055 | "TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n"); | 1053 | "PCXHR_IRQ_FREQ_CHANGE event occurred\n"); |
1056 | if (mgr->src_it_dsp & PCXHR_IRQ_TIME_CODE) | 1054 | if (mgr->src_it_dsp & PCXHR_IRQ_TIME_CODE) |
1057 | dev_dbg(&mgr->pci->dev, | 1055 | dev_dbg(&mgr->pci->dev, |
1058 | "TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n"); | 1056 | "PCXHR_IRQ_TIME_CODE event occurred\n"); |
1059 | if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY) | 1057 | if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY) |
1060 | dev_dbg(&mgr->pci->dev, | 1058 | dev_dbg(&mgr->pci->dev, |
1061 | "TASKLET : PCXHR_IRQ_NOTIFY event occurred\n"); | 1059 | "PCXHR_IRQ_NOTIFY event occurred\n"); |
1062 | if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) { | 1060 | if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) { |
1063 | /* clear events FREQ_CHANGE and TIME_CODE */ | 1061 | /* clear events FREQ_CHANGE and TIME_CODE */ |
1064 | pcxhr_init_rmh(prmh, CMD_TEST_IT); | 1062 | pcxhr_init_rmh(prmh, CMD_TEST_IT); |
@@ -1068,7 +1066,7 @@ void pcxhr_msg_tasklet(unsigned long arg) | |||
1068 | } | 1066 | } |
1069 | if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) { | 1067 | if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) { |
1070 | dev_dbg(&mgr->pci->dev, | 1068 | dev_dbg(&mgr->pci->dev, |
1071 | "TASKLET : PCXHR_IRQ_ASYNC event occurred\n"); | 1069 | "PCXHR_IRQ_ASYNC event occurred\n"); |
1072 | 1070 | ||
1073 | pcxhr_init_rmh(prmh, CMD_ASYNC); | 1071 | pcxhr_init_rmh(prmh, CMD_ASYNC); |
1074 | prmh->cmd[0] |= 1; /* add SEL_ASYNC_EVENTS */ | 1072 | prmh->cmd[0] |= 1; /* add SEL_ASYNC_EVENTS */ |
@@ -1076,7 +1074,7 @@ void pcxhr_msg_tasklet(unsigned long arg) | |||
1076 | prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS; | 1074 | prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS; |
1077 | err = pcxhr_send_msg(mgr, prmh); | 1075 | err = pcxhr_send_msg(mgr, prmh); |
1078 | if (err) | 1076 | if (err) |
1079 | dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_tasklet=%x;\n", | 1077 | dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_thread=%x;\n", |
1080 | err); | 1078 | err); |
1081 | i = 1; | 1079 | i = 1; |
1082 | while (i < prmh->stat_len) { | 1080 | while (i < prmh->stat_len) { |
@@ -1220,9 +1218,9 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, | |||
1220 | } | 1218 | } |
1221 | 1219 | ||
1222 | if (elapsed) { | 1220 | if (elapsed) { |
1223 | spin_unlock(&mgr->lock); | 1221 | mutex_unlock(&mgr->lock); |
1224 | snd_pcm_period_elapsed(stream->substream); | 1222 | snd_pcm_period_elapsed(stream->substream); |
1225 | spin_lock(&mgr->lock); | 1223 | mutex_lock(&mgr->lock); |
1226 | } | 1224 | } |
1227 | } | 1225 | } |
1228 | } | 1226 | } |
@@ -1231,14 +1229,10 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) | |||
1231 | { | 1229 | { |
1232 | struct pcxhr_mgr *mgr = dev_id; | 1230 | struct pcxhr_mgr *mgr = dev_id; |
1233 | unsigned int reg; | 1231 | unsigned int reg; |
1234 | int i, j; | 1232 | bool wake_thread = false; |
1235 | struct snd_pcxhr *chip; | ||
1236 | |||
1237 | spin_lock(&mgr->lock); | ||
1238 | 1233 | ||
1239 | reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS); | 1234 | reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS); |
1240 | if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) { | 1235 | if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) { |
1241 | spin_unlock(&mgr->lock); | ||
1242 | /* this device did not cause the interrupt */ | 1236 | /* this device did not cause the interrupt */ |
1243 | return IRQ_NONE; | 1237 | return IRQ_NONE; |
1244 | } | 1238 | } |
@@ -1250,6 +1244,44 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) | |||
1250 | /* timer irq occurred */ | 1244 | /* timer irq occurred */ |
1251 | if (reg & PCXHR_IRQ_TIMER) { | 1245 | if (reg & PCXHR_IRQ_TIMER) { |
1252 | int timer_toggle = reg & PCXHR_IRQ_TIMER; | 1246 | int timer_toggle = reg & PCXHR_IRQ_TIMER; |
1247 | if (timer_toggle == mgr->timer_toggle) { | ||
1248 | dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n"); | ||
1249 | mgr->dsp_time_err++; | ||
1250 | } | ||
1251 | |||
1252 | mgr->timer_toggle = timer_toggle; | ||
1253 | mgr->src_it_dsp = reg; | ||
1254 | wake_thread = true; | ||
1255 | } | ||
1256 | |||
1257 | /* other irq's handled in the thread */ | ||
1258 | if (reg & PCXHR_IRQ_MASK) { | ||
1259 | if (reg & PCXHR_IRQ_ASYNC) { | ||
1260 | /* as we didn't request any async notifications, | ||
1261 | * some kind of xrun error will probably occurred | ||
1262 | */ | ||
1263 | /* better resynchronize all streams next interrupt : */ | ||
1264 | mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; | ||
1265 | } | ||
1266 | mgr->src_it_dsp = reg; | ||
1267 | wake_thread = true; | ||
1268 | } | ||
1269 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
1270 | if (reg & PCXHR_FATAL_DSP_ERR) | ||
1271 | dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg); | ||
1272 | #endif | ||
1273 | |||
1274 | return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED; | ||
1275 | } | ||
1276 | |||
1277 | irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id) | ||
1278 | { | ||
1279 | struct pcxhr_mgr *mgr = dev_id; | ||
1280 | int i, j; | ||
1281 | struct snd_pcxhr *chip; | ||
1282 | |||
1283 | mutex_lock(&mgr->lock); | ||
1284 | if (mgr->src_it_dsp & PCXHR_IRQ_TIMER) { | ||
1253 | /* is a 24 bit counter */ | 1285 | /* is a 24 bit counter */ |
1254 | int dsp_time_new = | 1286 | int dsp_time_new = |
1255 | PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK; | 1287 | PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK; |
@@ -1290,13 +1322,6 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) | |||
1290 | #endif | 1322 | #endif |
1291 | mgr->dsp_time_last = dsp_time_new; | 1323 | mgr->dsp_time_last = dsp_time_new; |
1292 | 1324 | ||
1293 | if (timer_toggle == mgr->timer_toggle) { | ||
1294 | dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n"); | ||
1295 | mgr->dsp_time_err++; | ||
1296 | } | ||
1297 | mgr->timer_toggle = timer_toggle; | ||
1298 | |||
1299 | reg &= ~PCXHR_IRQ_TIMER; | ||
1300 | for (i = 0; i < mgr->num_cards; i++) { | 1325 | for (i = 0; i < mgr->num_cards; i++) { |
1301 | chip = mgr->chip[i]; | 1326 | chip = mgr->chip[i]; |
1302 | for (j = 0; j < chip->nb_streams_capt; j++) | 1327 | for (j = 0; j < chip->nb_streams_capt; j++) |
@@ -1312,22 +1337,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) | |||
1312 | dsp_time_diff); | 1337 | dsp_time_diff); |
1313 | } | 1338 | } |
1314 | } | 1339 | } |
1315 | /* other irq's handled in the tasklet */ | 1340 | |
1316 | if (reg & PCXHR_IRQ_MASK) { | 1341 | pcxhr_msg_thread(mgr); |
1317 | if (reg & PCXHR_IRQ_ASYNC) { | 1342 | return IRQ_HANDLED; |
1318 | /* as we didn't request any async notifications, | ||
1319 | * some kind of xrun error will probably occurred | ||
1320 | */ | ||
1321 | /* better resynchronize all streams next interrupt : */ | ||
1322 | mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; | ||
1323 | } | ||
1324 | mgr->src_it_dsp = reg; | ||
1325 | tasklet_schedule(&mgr->msg_taskq); | ||
1326 | } | ||
1327 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
1328 | if (reg & PCXHR_FATAL_DSP_ERR) | ||
1329 | dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg); | ||
1330 | #endif | ||
1331 | spin_unlock(&mgr->lock); | ||
1332 | return IRQ_HANDLED; /* this device caused the interrupt */ | ||
1333 | } | 1343 | } |