📄 pciscc.c
字号:
chipctl.iq_per_next = NULL;
chipctl.iq_cfg_next = NULL;
}
/* ------------------------------------------------------------------------- */
/*
* open one channel, the sequence of actions done here was carefully chosen,
* don't mess with it unless you know exactly what you are doing...
*/
int pciscc_channel_open(int chan, long bitrate, int mode)
{
unsigned long timer;
unsigned long l;
if (!bitrate)
return 0;
/* general chip init */
if (!pciscc_chip_open()) {
devctl[chan].stats.io_error++;
return 0;
}
if ((bitrate == devctl[chan].bitrate) && (mode == devctl[chan].mode))
return 1;
/* reset channel configuration */
pciscc_channel_close(chan);
/* RX buffer space check */
if (avail_frames() < CFG_RX_DESC) {
devctl[chan].stats.rx_overrun++;
return 0;
}
/* setup bitrate/mode for flexnet internal use */
devctl[chan].mode = mode;
devctl[chan].bitrate = bitrate;
devctl[chan].scale = 614400 / bitrate;
/* init interrupt and descriptor queues */
pciscc_init_queues(chan);
/* stop SCC */
disable();
WriteL(chipctl.io_base+SCCBASE[chan]+CCR1,0);
WriteL(chipctl.io_base+SCCBASE[chan]+CCR2,0);
WriteL(chipctl.io_base+SCCBASE[chan]+CCR0,0);
devctl[chan].ccr0 = devctl[chan].ccr1 = devctl[chan].ccr2 = 0;
WriteL(chipctl.io_base+SCCBASE[chan]+TIMR,0);
/* set IQ lengths and base addresses */
l = ReadL(chipctl.io_base+IQLENR1);
switch (chan) {
case 0: WriteL(chipctl.io_base+CH0CFG,MRFI | MTFI | MRERR | MTERR);
WriteL(chipctl.io_base+IQSCC0RXBAR,FP_TO_PHYS(devctl[chan].iq_rx));
WriteL(chipctl.io_base+IQSCC0TXBAR,FP_TO_PHYS(devctl[chan].iq_tx));
l &= 0x0fff0fff;
l |= (((CFG_IQLEN/32)-1)*IQSCC0RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC0TXLEN);
break;
case 1: WriteL(chipctl.io_base+CH1CFG,MRFI | MTFI | MRERR | MTERR);
WriteL(chipctl.io_base+IQSCC1RXBAR,FP_TO_PHYS(devctl[chan].iq_rx));
WriteL(chipctl.io_base+IQSCC1TXBAR,FP_TO_PHYS(devctl[chan].iq_tx));
l &= 0xf0fff0ff;
l |= (((CFG_IQLEN/32)-1)*IQSCC1RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC1TXLEN);
break;
case 2: WriteL(chipctl.io_base+CH2CFG,MRFI | MTFI | MRERR | MTERR);
WriteL(chipctl.io_base+IQSCC2RXBAR,FP_TO_PHYS(devctl[chan].iq_rx));
WriteL(chipctl.io_base+IQSCC2TXBAR,FP_TO_PHYS(devctl[chan].iq_tx));
l &= 0xff0fff0f;
l |= (((CFG_IQLEN/32)-1)*IQSCC2RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC2TXLEN);
break;
case 3: WriteL(chipctl.io_base+CH3CFG,MRFI | MTFI | MRERR | MTERR);
WriteL(chipctl.io_base+IQSCC3RXBAR,FP_TO_PHYS(devctl[chan].iq_rx));
WriteL(chipctl.io_base+IQSCC3TXBAR,FP_TO_PHYS(devctl[chan].iq_tx));
l &= 0xfff0fff0;
l |= (((CFG_IQLEN/32)-1)*IQSCC3RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC3TXLEN);
break;
}
WriteL(chipctl.io_base+IQLENR1,l);
enable();
chipctl.mailbox = MAILBOX_NONE;
WriteL(chipctl.io_base+GCMDR, AR /* Action Request */
| (chan == 0 ? (CFGIQSCC0RX | CFGIQSCC0TX) : 0)
| (chan == 1 ? (CFGIQSCC1RX | CFGIQSCC1TX) : 0)
| (chan == 2 ? (CFGIQSCC2RX | CFGIQSCC2TX) : 0)
| (chan == 3 ? (CFGIQSCC3RX | CFGIQSCC3TX) : 0));
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT) {
if (chipctl.mailbox) break;
}
if (chipctl.mailbox != MAILBOX_OK) { /* mailbox was written by isr */
devctl[chan].stats.io_error++;
}
/* initialize channel's SCC core */
disable();
devctl[chan].ccr0 = PU | VIS | PSD;
devctl[chan].ccr0 |= (mode & MODE_z) ? 0 : 2*SC;
devctl[chan].ccr0 |= (mode & MODE_r) ? 0 : 6*CM;
devctl[chan].ccr0 |= (mode & MODE_t) ? 0 : SSEL;
devctl[chan].ccr1 = ODS | ICD | FCTS | MDS1 | SFLAG;
devctl[chan].ccr2 = RAC | (3*RFTH) | ITF;
WriteL(chipctl.io_base+SCCBASE[chan]+CCR0,devctl[chan].ccr0);
WriteL(chipctl.io_base+SCCBASE[chan]+CCR1,devctl[chan].ccr1);
WriteL(chipctl.io_base+SCCBASE[chan]+CCR2,devctl[chan].ccr2);
pciscc_set_baud(chan,(mode & MODE_r) ? bitrate : 16*bitrate);
WriteL(chipctl.io_base+SCCBASE[chan]+RLCR,RCE | (CFG_MTU*RL));
/*
* all sent | tx device underrun | timer int | tx message repeat |
* tx pool ready | rx device overflow | receive FIFO overflow |
* frame length exceeded => interrupt mask register
*/
WriteL(chipctl.io_base+SCCBASE[chan]+IMR,~(ALLS | XDU | TIN | XMR | XPR | RDO | RFO | FLEX));
enable();
/* wait until command executing (CEC) is clear */
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT) {
l = ReadL(chipctl.io_base+SCCBASE[chan]+STAR);
if (!(l & CEC)) break;
}
/* RX and TX SCC reset */
WriteL(chipctl.io_base+SCCBASE[chan]+CMDR,RRES | XRES);
devctl[chan].tx_mailbox = 0xffffffff;
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT) {
if (devctl[chan].tx_mailbox != 0xffffffff) break;
}
if ((devctl[chan].tx_mailbox & 0x03ffffff) != 0x02001000) { /* mailbox was written by isr */
devctl[chan].stats.io_error++;
}
/* initialize DMAC channel's RX */
disable();
switch (chan) {
case 0: WriteL(chipctl.io_base+CH0CFG,IDR);
WriteL(chipctl.io_base+CH0BRDA,FP_TO_PHYS(devctl[chan].dq_rx));
WriteL(chipctl.io_base+CH0FRDA,FP_TO_PHYS(devctl[chan].dq_rx));
WriteL(chipctl.io_base+CH0LRDA,FP_TO_PHYS(devctl[chan].dq_rx_next->prev->prev));
break;
case 1: WriteL(chipctl.io_base+CH1CFG,IDR);
WriteL(chipctl.io_base+CH1BRDA,FP_TO_PHYS(devctl[chan].dq_rx));
WriteL(chipctl.io_base+CH1FRDA,FP_TO_PHYS(devctl[chan].dq_rx));
WriteL(chipctl.io_base+CH1LRDA,FP_TO_PHYS(devctl[chan].dq_rx_next->prev->prev));
break;
case 2: WriteL(chipctl.io_base+CH2CFG,IDR);
WriteL(chipctl.io_base+CH2BRDA,FP_TO_PHYS(devctl[chan].dq_rx));
WriteL(chipctl.io_base+CH2FRDA,FP_TO_PHYS(devctl[chan].dq_rx));
WriteL(chipctl.io_base+CH2LRDA,FP_TO_PHYS(devctl[chan].dq_rx_next->prev->prev));
break;
case 3: WriteL(chipctl.io_base+CH3CFG,IDR);
WriteL(chipctl.io_base+CH3BRDA,FP_TO_PHYS(devctl[chan].dq_rx));
WriteL(chipctl.io_base+CH3FRDA,FP_TO_PHYS(devctl[chan].dq_rx));
WriteL(chipctl.io_base+CH3LRDA,FP_TO_PHYS(devctl[chan].dq_rx_next->prev->prev));
break;
}
enable();
chipctl.mailbox = MAILBOX_NONE;
WriteL(chipctl.io_base+GCMDR,AR);
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT) {
if (chipctl.mailbox) break;
}
if (chipctl.mailbox != MAILBOX_OK) /* mailbox was written by isr */
devctl[chan].stats.io_error++;
/* mask all DMAC interrupts (needed) */
switch (chan) {
case 0: WriteL(chipctl.io_base+CH0CFG,MRFI | MTFI | MRERR | MTERR);
break;
case 1: WriteL(chipctl.io_base+CH1CFG,MRFI | MTFI | MRERR | MTERR);
break;
case 2: WriteL(chipctl.io_base+CH2CFG,MRFI | MTFI | MRERR | MTERR);
break;
case 3: WriteL(chipctl.io_base+CH3CFG,MRFI | MTFI | MRERR | MTERR);
break;
}
/* wait until command executing (CEC) is clear */
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT) {
l = ReadL(chipctl.io_base+SCCBASE[chan]+STAR);
if (!(l & CEC)) break;
}
/* SCC core TX reset (again) */
WriteL(chipctl.io_base+SCCBASE[chan]+CMDR,XRES);
devctl[chan].tx_mailbox = 0xffffffff;
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT) {
if (devctl[chan].tx_mailbox != 0xffffffff) break;
}
if ((devctl[chan].tx_mailbox & 0x03ffffff) != 0x02001000) { /* mailbox was written by isr */
devctl[chan].stats.io_error++;
}
/*
* initialize DMAC's TX channel, FI must stay masked all the time
* even during operation, see device errata 03/99
*/
switch (chan) {
case 0: WriteL(chipctl.io_base+CH0CFG,IDT | MTFI);
WriteL(chipctl.io_base+CH0BTDA,FP_TO_PHYS(devctl[chan].dq_tx));
WriteL(chipctl.io_base+CH0FTDA,FP_TO_PHYS(devctl[chan].dq_tx));
WriteL(chipctl.io_base+CH0LTDA,FP_TO_PHYS(devctl[chan].dq_tx));
break;
case 1: WriteL(chipctl.io_base+CH1CFG,IDT | MTFI);
WriteL(chipctl.io_base+CH1BTDA,FP_TO_PHYS(devctl[chan].dq_tx));
WriteL(chipctl.io_base+CH1FTDA,FP_TO_PHYS(devctl[chan].dq_tx));
WriteL(chipctl.io_base+CH1LTDA,FP_TO_PHYS(devctl[chan].dq_tx));
break;
case 2: WriteL(chipctl.io_base+CH2CFG,IDT | MTFI);
WriteL(chipctl.io_base+CH2BTDA,FP_TO_PHYS(devctl[chan].dq_tx));
WriteL(chipctl.io_base+CH2FTDA,FP_TO_PHYS(devctl[chan].dq_tx));
WriteL(chipctl.io_base+CH2LTDA,FP_TO_PHYS(devctl[chan].dq_tx));
break;
case 3: WriteL(chipctl.io_base+CH3CFG,IDT | MTFI);
WriteL(chipctl.io_base+CH3BTDA,FP_TO_PHYS(devctl[chan].dq_tx));
WriteL(chipctl.io_base+CH3FTDA,FP_TO_PHYS(devctl[chan].dq_tx));
WriteL(chipctl.io_base+CH3LTDA,FP_TO_PHYS(devctl[chan].dq_tx));
break;
}
chipctl.mailbox = MAILBOX_NONE;
WriteL(chipctl.io_base+GCMDR,AR);
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT) {
if (chipctl.mailbox) break;
}
if (chipctl.mailbox == MAILBOX_OK) /* mailbox was written by isr */
devctl[chan].txstate=TX_IDLE;
else
devctl[chan].stats.io_error++;
devctl[chan].tx_enqueued = 0;
devctl[chan].initialized = 1;
return 1;
}
/* ------------------------------------------------------------------------- */
/* close one channel - don't mess with it either */
void pciscc_channel_close(int chan)
{
struct rx_desc_t *rdp;
unsigned long timer;
unsigned long l;
if (!devctl[chan].initialized)
return;
devctl[chan].initialized=0;
/* at first stop timer */
WriteL(chipctl.io_base+SCCBASE[chan]+TIMR,0);
/* wait until command executing (CEC) is clear */
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT) {
l = ReadL(chipctl.io_base+SCCBASE[chan]+STAR);
if (!(l & CEC)) break;
}
/* RX and TX SCC reset */
WriteL(chipctl.io_base+SCCBASE[chan]+CMDR,RRES | XRES);
devctl[chan].tx_mailbox = 0xffffffff;
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT) {
if (devctl[chan].tx_mailbox != 0xffffffff) break;
}
if ((devctl[chan].tx_mailbox & 0x03ffffff) != 0x02001000) { /* mailbox was written by isr */
devctl[chan].stats.io_error++;
}
/* stop SCC core */
WriteL(chipctl.io_base+SCCBASE[chan]+CCR1,0);
WriteL(chipctl.io_base+SCCBASE[chan]+CCR2,0);
WriteL(chipctl.io_base+SCCBASE[chan]+CCR0,0);
devctl[chan].ccr0 = devctl[chan].ccr1 = devctl[chan].ccr2 = 0;
devctl[chan].bitrate = devctl[chan].mode = 0;
/*
* Give the isr some time to "refill" the rx-dq
* we _MUST_ guarantee that the DMAC-RX is _NOT_ in
* hold state when issuing the RESET command, otherwise the DMAC
* will crash. (DSCC-4 Rev. <= 2.1)
* In addition to that we may only issue a RESET if channel is
* currently really initialized, otherwise something horrible will
* result.
*/
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT);
/* OK, now we should be ready to put the DMAC into reset state */
switch (chan) {
case 0: WriteL(chipctl.io_base+CH0CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
break;
case 1: WriteL(chipctl.io_base+CH1CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
break;
case 2: WriteL(chipctl.io_base+CH2CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
break;
case 3: WriteL(chipctl.io_base+CH3CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
break;
}
chipctl.mailbox = MAILBOX_NONE;
WriteL(chipctl.io_base+GCMDR,AR);
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT) {
if (chipctl.mailbox) break;
}
if (chipctl.mailbox != MAILBOX_OK) /* mailbox was written by isr */
devctl[chan].stats.io_error++;
devctl[chan].txstate = TX_RESET;
/* clear IQs */
l = ReadL(chipctl.io_base+IQLENR1);
switch (chan) {
case 0: l &= 0x0fff0fff;
WriteL(chipctl.io_base+IQLENR1,l);
WriteL(chipctl.io_base+IQSCC0RXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
WriteL(chipctl.io_base+IQSCC0TXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
break;
case 1: l &= 0xf0fff0ff;
WriteL(chipctl.io_base+IQLENR1,l);
WriteL(chipctl.io_base+IQSCC1RXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
WriteL(chipctl.io_base+IQSCC1TXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
break;
case 2: l &= 0xff0fff0f;
WriteL(chipctl.io_base+IQLENR1,l);
WriteL(chipctl.io_base+IQSCC2RXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
WriteL(chipctl.io_base+IQSCC2TXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
break;
case 3: l &= 0xfff0fff0;
WriteL(chipctl.io_base+IQLENR1,l);
WriteL(chipctl.io_base+IQSCC3RXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
WriteL(chipctl.io_base+IQSCC3TXBAR,FP_TO_PHYS(chipctl.dma_buffers->dummy));
break;
}
chipctl.mailbox = MAILBOX_NONE;
WriteL(chipctl.io_base+GCMDR,AR
| (chan == 0 ? (CFGIQSCC0RX | CFGIQSCC0TX) : 0)
| (chan == 1 ? (CFGIQSCC1RX | CFGIQSCC1TX) : 0)
| (chan == 2 ? (CFGIQSCC2RX | CFGIQSCC2TX) : 0)
| (chan == 3 ? (CFGIQSCC3RX | CFGIQSCC3TX) : 0));
timer = *bios_tic;
while((*bios_tic - timer) < CHIP_TIMEOUT) {
if (chipctl.mailbox) break;
}
if (chipctl.mailbox != MAILBOX_OK) { /* mailbox was written by isr */
devctl[chan].stats.io_error++;
}
rdp = devctl[chan].dq_rx;
while(rdp->l1_frame) {
free_frame(rdp->l1_frame);
rdp->l1_frame = NULL;
rdp = rdp->next;
}
devctl[chan].iq_rx_next=NULL;
devctl[chan].iq_tx_next=NULL;
}
/* ------------------------------------------------------------------------- */
/* interrupt handler root */
void interrupt pciscc_isr(void)
{
unsigned long status;
unsigned long *iqp;
int chan;
disable();
status = ReadL(chipctl.io_base+GSTAR);
WriteL(chipctl.io_base+GSTAR,status); /* ack' irq */
/* process peripheral queue */
iqp = chipctl.iq_per_next;
while(iqp && *iqp) {
*(iqp++) = 0;
if (iqp == chipctl.iq_per+CFG_IQLEN)
iqp = chipctl.iq_per;
}
chipctl.iq_per_next = iqp;
/* process configuration queue */
chipctl.mailbox = MAILBOX_NONE;
iqp = chipctl.iq_cfg_next;
while(iqp && *iqp) {
if ((*iqp) & ARACK)
chipctl.mailbox = MAILBOX_OK;
if ((*iqp) & ARF)
chipctl.mailbox = MAILBOX_FAILURE;
*(iqp++) = 0;
if (iqp == chipctl.iq_cfg+CFG_IQLEN)
iqp = chipctl.iq_cfg;
}
chipctl.iq_cfg_next = iqp;
/* poll channel queues */
for (chan=0; chan < 4; chan++) {
/* process TX queue */
pciscc_isr_txcleanup(chan);
iqp = devctl[chan].iq_tx_next;
while(iqp && *iqp) {
if (*iqp & TIN) {
/* timer interrupt */
WriteL(chipctl.io_base+SCCBASE[chan]+TIMR,0);
/* is there something in the TX queue ? */
if (devctl[chan].tx_enqueued) {
devctl[chan].txstate=TX_XMIT;
switch (chan) {
case 0: WriteL(chipctl.io_base+CH0LTDA,FP_TO_PHYS(devctl[chan].dq_tx_last));
break;
case 1: WriteL(chipctl.io_base+CH1LTDA,FP_TO_PHYS(devctl[chan].dq_tx_last));
break;
case 2: WriteL(chipctl.io_base+CH2LTDA,FP_TO_PHYS(devctl[chan].dq_tx_last));
break;
case 3: WriteL(chipctl.io_base+CH3LTDA,FP_TO_PHYS(devctl[chan].dq_tx_last));
break;
}
} else {
devctl[chan].txstate=TX_IDLE;
devctl[chan].ccr1 &= ~RTS;
WriteL(chipctl.io_base+SCCBASE[chan]+CCR1,devctl[chan].ccr1);
}
}
if (*iqp & ALLS) {
if (devctl[chan].tx_enqueued)
devctl[chan].tx_enqueued--;
if (!devctl[chan].tx_enqueued) {
devctl[chan].txstate=TX_TAIL;
WriteL(chipctl.io_base+SCCBASE[chan]+TIMR,MIN_FLAGS*TVALUE);
WriteL(chipctl.io_base+SCCBASE[chan]+CMDR,STI);
}
}
if (*iqp & XDU) {
/* TX data underrun */
devctl[chan].stats.tx_error++;
devctl[chan].txstate=TX_STALL;
devctl[chan].ccr1 &= ~RTS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -