0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/interrupt.h>
0011 #include <linux/mutex.h>
0012 #include <linux/pci.h>
0013 #include <linux/io.h>
0014
0015 #include <sound/core.h>
0016 #include "mixart.h"
0017 #include "mixart_hwdep.h"
0018 #include "mixart_core.h"
0019
0020
0021 #define MSG_TIMEOUT_JIFFIES (400 * HZ) / 1000
0022
0023 #define MSG_DESCRIPTOR_SIZE 0x24
0024 #define MSG_HEADER_SIZE (MSG_DESCRIPTOR_SIZE + 4)
0025
0026 #define MSG_TYPE_MASK 0x00000003
0027 #define MSG_TYPE_NOTIFY 0
0028 #define MSG_TYPE_COMMAND 1
0029 #define MSG_TYPE_REQUEST 2
0030 #define MSG_TYPE_ANSWER 3
0031 #define MSG_CANCEL_NOTIFY_MASK 0x80000000
0032
0033
0034 static int retrieve_msg_frame(struct mixart_mgr *mgr, u32 *msg_frame)
0035 {
0036
0037 u32 headptr, tailptr;
0038
0039 tailptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL));
0040 headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_HEAD));
0041
0042 if (tailptr == headptr)
0043 return 0;
0044
0045 if (tailptr < MSG_OUTBOUND_POST_STACK)
0046 return 0;
0047 if (tailptr >= MSG_OUTBOUND_POST_STACK + MSG_BOUND_STACK_SIZE)
0048 return 0;
0049
0050 *msg_frame = readl_be(MIXART_MEM(mgr, tailptr));
0051
0052
0053 tailptr += 4;
0054 if( tailptr >= (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) )
0055 tailptr = MSG_OUTBOUND_POST_STACK;
0056 writel_be(tailptr, MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL));
0057
0058 return 1;
0059 }
0060
0061 static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp,
0062 u32 msg_frame_address )
0063 {
0064 u32 headptr;
0065 u32 size;
0066 int err;
0067 #ifndef __BIG_ENDIAN
0068 unsigned int i;
0069 #endif
0070
0071 err = 0;
0072
0073
0074 size = readl_be(MIXART_MEM(mgr, msg_frame_address));
0075 resp->message_id = readl_be(MIXART_MEM(mgr, msg_frame_address + 4));
0076 resp->uid.object_id = readl_be(MIXART_MEM(mgr, msg_frame_address + 8));
0077 resp->uid.desc = readl_be(MIXART_MEM(mgr, msg_frame_address + 12));
0078
0079 if( (size < MSG_DESCRIPTOR_SIZE) || (resp->size < (size - MSG_DESCRIPTOR_SIZE))) {
0080 err = -EINVAL;
0081 dev_err(&mgr->pci->dev,
0082 "problem with response size = %d\n", size);
0083 goto _clean_exit;
0084 }
0085 size -= MSG_DESCRIPTOR_SIZE;
0086
0087 memcpy_fromio(resp->data, MIXART_MEM(mgr, msg_frame_address + MSG_HEADER_SIZE ), size);
0088 resp->size = size;
0089
0090
0091 #ifndef __BIG_ENDIAN
0092 size /= 4;
0093 for(i=0; i < size; i++) {
0094 ((u32*)resp->data)[i] = be32_to_cpu(((__be32*)resp->data)[i]);
0095 }
0096 #endif
0097
0098
0099
0100
0101 headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
0102
0103 if( (headptr < MSG_OUTBOUND_FREE_STACK) || ( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) {
0104 err = -EINVAL;
0105 goto _clean_exit;
0106 }
0107
0108
0109 writel_be(msg_frame_address, MIXART_MEM(mgr, headptr));
0110
0111
0112 headptr += 4;
0113 if( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) )
0114 headptr = MSG_OUTBOUND_FREE_STACK;
0115
0116 writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
0117
0118 _clean_exit:
0119 return err;
0120 }
0121
0122
0123
0124
0125
0126
0127 static int send_msg( struct mixart_mgr *mgr,
0128 struct mixart_msg *msg,
0129 int max_answersize,
0130 int mark_pending,
0131 u32 *msg_event)
0132 {
0133 u32 headptr, tailptr;
0134 u32 msg_frame_address;
0135 int i;
0136
0137 if (snd_BUG_ON(msg->size % 4))
0138 return -EINVAL;
0139
0140
0141 tailptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL));
0142 headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD));
0143
0144 if (tailptr == headptr) {
0145 dev_err(&mgr->pci->dev, "error: no message frame available\n");
0146 return -EBUSY;
0147 }
0148
0149 if( (tailptr < MSG_INBOUND_FREE_STACK) || (tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) {
0150 return -EINVAL;
0151 }
0152
0153 msg_frame_address = readl_be(MIXART_MEM(mgr, tailptr));
0154 writel(0, MIXART_MEM(mgr, tailptr));
0155
0156
0157 tailptr += 4;
0158 if( tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) )
0159 tailptr = MSG_INBOUND_FREE_STACK;
0160
0161 writel_be(tailptr, MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL));
0162
0163
0164
0165
0166 writel_be( msg->size + MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address) );
0167 writel_be( msg->message_id , MIXART_MEM(mgr, msg_frame_address + 4) );
0168 writel_be( msg->uid.object_id, MIXART_MEM(mgr, msg_frame_address + 8) );
0169 writel_be( msg->uid.desc, MIXART_MEM(mgr, msg_frame_address + 12) );
0170 writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 16) );
0171 writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 20) );
0172 writel_be( msg->size, MIXART_MEM(mgr, msg_frame_address + 24) );
0173 writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 28) );
0174 writel_be( 0, MIXART_MEM(mgr, msg_frame_address + 32) );
0175 writel_be( MSG_DESCRIPTOR_SIZE + max_answersize, MIXART_MEM(mgr, msg_frame_address + 36) );
0176
0177
0178 for( i=0; i < msg->size; i+=4 ) {
0179 writel_be( *(u32*)(msg->data + i), MIXART_MEM(mgr, MSG_HEADER_SIZE + msg_frame_address + i) );
0180 }
0181
0182 if( mark_pending ) {
0183 if( *msg_event ) {
0184
0185 mgr->pending_event = *msg_event;
0186 }
0187 else {
0188
0189 mgr->pending_event = msg_frame_address;
0190
0191
0192 *msg_event = msg_frame_address;
0193 }
0194 }
0195
0196
0197 msg_frame_address |= MSG_TYPE_REQUEST;
0198
0199
0200 headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD));
0201
0202 if( (headptr < MSG_INBOUND_POST_STACK) || (headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE))) {
0203 return -EINVAL;
0204 }
0205
0206 writel_be(msg_frame_address, MIXART_MEM(mgr, headptr));
0207
0208
0209 headptr += 4;
0210 if( headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) )
0211 headptr = MSG_INBOUND_POST_STACK;
0212
0213 writel_be(headptr, MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD));
0214
0215 return 0;
0216 }
0217
0218
0219 int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int max_resp_size, void *resp_data)
0220 {
0221 struct mixart_msg resp;
0222 u32 msg_frame = 0;
0223 int err;
0224 wait_queue_entry_t wait;
0225 long timeout;
0226
0227 init_waitqueue_entry(&wait, current);
0228
0229 mutex_lock(&mgr->msg_lock);
0230
0231 err = send_msg(mgr, request, max_resp_size, 1, &msg_frame);
0232 if (err) {
0233 mutex_unlock(&mgr->msg_lock);
0234 return err;
0235 }
0236
0237 set_current_state(TASK_UNINTERRUPTIBLE);
0238 add_wait_queue(&mgr->msg_sleep, &wait);
0239 mutex_unlock(&mgr->msg_lock);
0240 timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
0241 remove_wait_queue(&mgr->msg_sleep, &wait);
0242
0243 if (! timeout) {
0244
0245 dev_err(&mgr->pci->dev,
0246 "error: no response on msg %x\n", msg_frame);
0247 return -EIO;
0248 }
0249
0250
0251 resp.message_id = 0;
0252 resp.uid = (struct mixart_uid){0,0};
0253 resp.data = resp_data;
0254 resp.size = max_resp_size;
0255
0256 mutex_lock(&mgr->msg_lock);
0257 err = get_msg(mgr, &resp, msg_frame);
0258 mutex_unlock(&mgr->msg_lock);
0259
0260 if( request->message_id != resp.message_id )
0261 dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n");
0262
0263 return err;
0264 }
0265
0266
0267 int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr,
0268 struct mixart_msg *request, u32 notif_event)
0269 {
0270 int err;
0271 wait_queue_entry_t wait;
0272 long timeout;
0273
0274 if (snd_BUG_ON(!notif_event))
0275 return -EINVAL;
0276 if (snd_BUG_ON((notif_event & MSG_TYPE_MASK) != MSG_TYPE_NOTIFY))
0277 return -EINVAL;
0278 if (snd_BUG_ON(notif_event & MSG_CANCEL_NOTIFY_MASK))
0279 return -EINVAL;
0280
0281 init_waitqueue_entry(&wait, current);
0282
0283 mutex_lock(&mgr->msg_lock);
0284
0285 err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, ¬if_event);
0286 if(err) {
0287 mutex_unlock(&mgr->msg_lock);
0288 return err;
0289 }
0290
0291 set_current_state(TASK_UNINTERRUPTIBLE);
0292 add_wait_queue(&mgr->msg_sleep, &wait);
0293 mutex_unlock(&mgr->msg_lock);
0294 timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
0295 remove_wait_queue(&mgr->msg_sleep, &wait);
0296
0297 if (! timeout) {
0298
0299 dev_err(&mgr->pci->dev,
0300 "error: notification %x not received\n", notif_event);
0301 return -EIO;
0302 }
0303
0304 return 0;
0305 }
0306
0307
0308 int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request)
0309 {
0310 u32 message_frame;
0311 int err;
0312
0313
0314 mutex_lock(&mgr->msg_lock);
0315 err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame);
0316 mutex_unlock(&mgr->msg_lock);
0317
0318
0319 atomic_inc(&mgr->msg_processed);
0320
0321 return err;
0322 }
0323
0324
0325
0326 static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4];
0327
0328
0329 static void snd_mixart_process_msg(struct mixart_mgr *mgr)
0330 {
0331 struct mixart_msg resp;
0332 u32 msg, addr, type;
0333 int err;
0334
0335 while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) {
0336 msg = mgr->msg_fifo[mgr->msg_fifo_readptr];
0337 mgr->msg_fifo_readptr++;
0338 mgr->msg_fifo_readptr %= MSG_FIFO_SIZE;
0339
0340
0341 addr = msg & ~MSG_TYPE_MASK;
0342 type = msg & MSG_TYPE_MASK;
0343
0344 switch (type) {
0345 case MSG_TYPE_ANSWER:
0346
0347 resp.message_id = 0;
0348 resp.data = mixart_msg_data;
0349 resp.size = sizeof(mixart_msg_data);
0350 err = get_msg(mgr, &resp, addr);
0351 if( err < 0 ) {
0352 dev_err(&mgr->pci->dev,
0353 "error(%d) reading mf %x\n",
0354 err, msg);
0355 break;
0356 }
0357
0358 switch(resp.message_id) {
0359 case MSG_STREAM_START_INPUT_STAGE_PACKET:
0360 case MSG_STREAM_START_OUTPUT_STAGE_PACKET:
0361 case MSG_STREAM_STOP_INPUT_STAGE_PACKET:
0362 case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET:
0363 if(mixart_msg_data[0])
0364 dev_err(&mgr->pci->dev,
0365 "error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n",
0366 mixart_msg_data[0]);
0367 break;
0368 default:
0369 dev_dbg(&mgr->pci->dev,
0370 "received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n",
0371 msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size);
0372 break;
0373 }
0374 break;
0375 case MSG_TYPE_NOTIFY:
0376
0377 case MSG_TYPE_COMMAND:
0378
0379 default:
0380 dev_err(&mgr->pci->dev,
0381 "doesn't know what to do with message %x\n",
0382 msg);
0383 }
0384
0385
0386 atomic_dec(&mgr->msg_processed);
0387
0388 }
0389 }
0390
0391
0392 irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
0393 {
0394 struct mixart_mgr *mgr = dev_id;
0395 u32 it_reg;
0396
0397 it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET));
0398 if( !(it_reg & MIXART_OIDI) ) {
0399
0400 return IRQ_NONE;
0401 }
0402
0403
0404 writel_le(MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG(mgr, MIXART_PCI_OMIMR_OFFSET));
0405
0406
0407 it_reg = readl(MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET));
0408 writel(it_reg, MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET));
0409
0410
0411 writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) );
0412
0413 return IRQ_WAKE_THREAD;
0414 }
0415
0416 irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id)
0417 {
0418 struct mixart_mgr *mgr = dev_id;
0419 int err;
0420 struct mixart_msg resp;
0421 u32 msg;
0422
0423 mutex_lock(&mgr->lock);
0424
0425 while (retrieve_msg_frame(mgr, &msg)) {
0426
0427 switch (msg & MSG_TYPE_MASK) {
0428 case MSG_TYPE_COMMAND:
0429 resp.message_id = 0;
0430 resp.data = mixart_msg_data;
0431 resp.size = sizeof(mixart_msg_data);
0432 err = get_msg(mgr, &resp, msg & ~MSG_TYPE_MASK);
0433 if( err < 0 ) {
0434 dev_err(&mgr->pci->dev,
0435 "interrupt: error(%d) reading mf %x\n",
0436 err, msg);
0437 break;
0438 }
0439
0440 if(resp.message_id == MSG_SERVICES_TIMER_NOTIFY) {
0441 int i;
0442 struct mixart_timer_notify *notify;
0443 notify = (struct mixart_timer_notify *)mixart_msg_data;
0444
0445 BUILD_BUG_ON(sizeof(notify) > sizeof(mixart_msg_data));
0446 if (snd_BUG_ON(notify->stream_count > ARRAY_SIZE(notify->streams)))
0447 break;
0448 for(i=0; i<notify->stream_count; i++) {
0449
0450 u32 buffer_id = notify->streams[i].buffer_id;
0451 unsigned int chip_number = (buffer_id & MIXART_NOTIFY_CARD_MASK) >> MIXART_NOTIFY_CARD_OFFSET;
0452 unsigned int pcm_number = (buffer_id & MIXART_NOTIFY_PCM_MASK ) >> MIXART_NOTIFY_PCM_OFFSET;
0453 unsigned int sub_number = buffer_id & MIXART_NOTIFY_SUBS_MASK;
0454 unsigned int is_capture = ((buffer_id & MIXART_NOTIFY_CAPT_MASK) != 0);
0455
0456 struct snd_mixart *chip = mgr->chip[chip_number];
0457 struct mixart_stream *stream;
0458
0459 if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) {
0460 dev_err(&mgr->pci->dev,
0461 "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n",
0462 buffer_id, notify->streams[i].sample_pos_low_part);
0463 break;
0464 }
0465
0466 if (is_capture)
0467 stream = &chip->capture_stream[pcm_number];
0468 else
0469 stream = &chip->playback_stream[pcm_number][sub_number];
0470
0471 if (stream->substream && (stream->status == MIXART_STREAM_STATUS_RUNNING)) {
0472 struct snd_pcm_runtime *runtime = stream->substream->runtime;
0473 int elapsed = 0;
0474 u64 sample_count = ((u64)notify->streams[i].sample_pos_high_part) << 32;
0475 sample_count |= notify->streams[i].sample_pos_low_part;
0476
0477 while (1) {
0478 u64 new_elapse_pos = stream->abs_period_elapsed + runtime->period_size;
0479
0480 if (new_elapse_pos > sample_count) {
0481 break;
0482 }
0483 else {
0484 elapsed = 1;
0485 stream->buf_periods++;
0486 if (stream->buf_periods >= runtime->periods)
0487 stream->buf_periods = 0;
0488
0489 stream->abs_period_elapsed = new_elapse_pos;
0490 }
0491 }
0492 stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed );
0493
0494 if(elapsed) {
0495 mutex_unlock(&mgr->lock);
0496 snd_pcm_period_elapsed(stream->substream);
0497 mutex_lock(&mgr->lock);
0498 }
0499 }
0500 }
0501 break;
0502 }
0503 if(resp.message_id == MSG_SERVICES_REPORT_TRACES) {
0504 if(resp.size > 1) {
0505 #ifndef __BIG_ENDIAN
0506
0507 int i;
0508 for(i=0; i<(resp.size/4); i++) {
0509 ((__be32*)mixart_msg_data)[i] = cpu_to_be32((mixart_msg_data)[i]);
0510 }
0511 #endif
0512 ((char*)mixart_msg_data)[resp.size - 1] = 0;
0513 dev_dbg(&mgr->pci->dev,
0514 "MIXART TRACE : %s\n",
0515 (char *)mixart_msg_data);
0516 }
0517 break;
0518 }
0519
0520 dev_dbg(&mgr->pci->dev, "command %x not handled\n",
0521 resp.message_id);
0522 break;
0523
0524 case MSG_TYPE_NOTIFY:
0525 if(msg & MSG_CANCEL_NOTIFY_MASK) {
0526 msg &= ~MSG_CANCEL_NOTIFY_MASK;
0527 dev_err(&mgr->pci->dev,
0528 "canceled notification %x !\n", msg);
0529 }
0530 fallthrough;
0531 case MSG_TYPE_ANSWER:
0532
0533 mutex_lock(&mgr->msg_lock);
0534 if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) {
0535 wake_up(&mgr->msg_sleep);
0536 mgr->pending_event = 0;
0537 }
0538
0539 else {
0540 mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg;
0541 mgr->msg_fifo_writeptr++;
0542 mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE;
0543 snd_mixart_process_msg(mgr);
0544 }
0545 mutex_unlock(&mgr->msg_lock);
0546 break;
0547 case MSG_TYPE_REQUEST:
0548 default:
0549 dev_dbg(&mgr->pci->dev,
0550 "interrupt received request %x\n", msg);
0551
0552 break;
0553 }
0554 }
0555
0556
0557 writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
0558
0559 mutex_unlock(&mgr->lock);
0560
0561 return IRQ_HANDLED;
0562 }
0563
0564
0565 void snd_mixart_init_mailbox(struct mixart_mgr *mgr)
0566 {
0567 writel( 0, MIXART_MEM( mgr, MSG_HOST_RSC_PROTECTION ) );
0568 writel( 0, MIXART_MEM( mgr, MSG_AGENT_RSC_PROTECTION ) );
0569
0570
0571 if(mgr->irq >= 0) {
0572 writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
0573 }
0574 return;
0575 }
0576
0577 void snd_mixart_exit_mailbox(struct mixart_mgr *mgr)
0578 {
0579
0580 writel_le( MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
0581 return;
0582 }
0583
0584 void snd_mixart_reset_board(struct mixart_mgr *mgr)
0585 {
0586
0587 writel_be( 1, MIXART_REG(mgr, MIXART_BA1_BRUTAL_RESET_OFFSET) );
0588 return;
0589 }