Commit 43eef00a authored by Paul Fulghum's avatar Paul Fulghum Committed by Linus Torvalds

[PATCH] synclinkmp transmit eom fix

Bug Fixes:

* Fix transmit end of message (EOM) processing to work correctly with
  hardware auto CTS feature

* Fix oops in error path if hardware diags fail during device
  initialization

Cosmetic change:

* Use existing macros for address space size instead of hardcoded values
Signed-off-by: default avatarPaul Fulghum <paulkf@microgate.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent a3f5b14e
/* /*
* $Id: synclinkmp.c,v 4.26 2004/08/11 19:30:02 paulkf Exp $ * $Id: synclinkmp.c,v 4.29 2004/08/27 20:06:41 paulkf Exp $
* *
* Device driver for Microgate SyncLink Multiport * Device driver for Microgate SyncLink Multiport
* high speed multiprotocol serial adapter. * high speed multiprotocol serial adapter.
...@@ -489,7 +489,7 @@ MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICES) "i"); ...@@ -489,7 +489,7 @@ MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICES) "i");
MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i"); MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i");
static char *driver_name = "SyncLink MultiPort driver"; static char *driver_name = "SyncLink MultiPort driver";
static char *driver_version = "$Revision: 4.26 $"; static char *driver_version = "$Revision: 4.29 $";
static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
static void synclinkmp_remove_one(struct pci_dev *dev); static void synclinkmp_remove_one(struct pci_dev *dev);
...@@ -651,7 +651,7 @@ static unsigned char tx_active_fifo_level = 16; // tx request FIFO activation le ...@@ -651,7 +651,7 @@ static unsigned char tx_active_fifo_level = 16; // tx request FIFO activation le
static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes
static u32 misc_ctrl_value = 0x007e4040; static u32 misc_ctrl_value = 0x007e4040;
static u32 lcr1_brdr_value = 0x0080002d; static u32 lcr1_brdr_value = 0x00800029;
static u32 read_ahead_count = 8; static u32 read_ahead_count = 8;
...@@ -2182,16 +2182,15 @@ void isr_rxint(SLMP_INFO * info) ...@@ -2182,16 +2182,15 @@ void isr_rxint(SLMP_INFO * info)
{ {
struct tty_struct *tty = info->tty; struct tty_struct *tty = info->tty;
struct mgsl_icount *icount = &info->icount; struct mgsl_icount *icount = &info->icount;
unsigned char status = read_reg(info, SR1); unsigned char status = read_reg(info, SR1) & info->ie1_value & (FLGD + IDLD + CDCD + BRKD);
unsigned char status2 = read_reg(info, SR2); unsigned char status2 = read_reg(info, SR2) & info->ie2_value & OVRN;
/* clear status bits */ /* clear status bits */
if ( status & (FLGD + IDLD + CDCD + BRKD) ) if (status)
write_reg(info, SR1, write_reg(info, SR1, status);
(unsigned char)(status & (FLGD + IDLD + CDCD + BRKD)));
if ( status2 & OVRN ) if (status2)
write_reg(info, SR2, (unsigned char)(status2 & OVRN)); write_reg(info, SR2, status2);
if ( debug_level >= DEBUG_LEVEL_ISR ) if ( debug_level >= DEBUG_LEVEL_ISR )
printk("%s(%d):%s isr_rxint status=%02X %02x\n", printk("%s(%d):%s isr_rxint status=%02X %02x\n",
...@@ -2328,15 +2327,22 @@ void isr_txeom(SLMP_INFO * info, unsigned char status) ...@@ -2328,15 +2327,22 @@ void isr_txeom(SLMP_INFO * info, unsigned char status)
printk("%s(%d):%s isr_txeom status=%02x\n", printk("%s(%d):%s isr_txeom status=%02x\n",
__FILE__,__LINE__,info->device_name,status); __FILE__,__LINE__,info->device_name,status);
/* disable and clear MSCI interrupts */
info->ie1_value &= ~(IDLE + UDRN);
write_reg(info, IE1, info->ie1_value);
write_reg(info, SR1, (unsigned char)(UDRN + IDLE));
write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */
write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */ write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */
write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */
if (status & UDRN) {
write_reg(info, CMD, TXRESET);
write_reg(info, CMD, TXENABLE);
} else
write_reg(info, CMD, TXBUFCLR);
/* disable and clear tx interrupts */
info->ie0_value &= ~TXRDYE;
info->ie1_value &= ~(IDLE + UDRN);
write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value));
write_reg(info, SR1, (unsigned char)(UDRN + IDLE));
if ( info->tx_active ) { if ( info->tx_active ) {
if (info->params.mode != MGSL_MODE_ASYNC) { if (info->params.mode != MGSL_MODE_ASYNC) {
if (status & UDRN) if (status & UDRN)
...@@ -2377,10 +2383,10 @@ void isr_txeom(SLMP_INFO * info, unsigned char status) ...@@ -2377,10 +2383,10 @@ void isr_txeom(SLMP_INFO * info, unsigned char status)
*/ */
void isr_txint(SLMP_INFO * info) void isr_txint(SLMP_INFO * info)
{ {
unsigned char status = read_reg(info, SR1); unsigned char status = read_reg(info, SR1) & info->ie1_value & (UDRN + IDLE + CCTS);
/* clear status bits */ /* clear status bits */
write_reg(info, SR1, (unsigned char)(status & (UDRN + IDLE + CCTS))); write_reg(info, SR1, status);
if ( debug_level >= DEBUG_LEVEL_ISR ) if ( debug_level >= DEBUG_LEVEL_ISR )
printk("%s(%d):%s isr_txint status=%02x\n", printk("%s(%d):%s isr_txint status=%02x\n",
...@@ -2409,6 +2415,14 @@ void isr_txrdy(SLMP_INFO * info) ...@@ -2409,6 +2415,14 @@ void isr_txrdy(SLMP_INFO * info)
printk("%s(%d):%s isr_txrdy() tx_count=%d\n", printk("%s(%d):%s isr_txrdy() tx_count=%d\n",
__FILE__,__LINE__,info->device_name,info->tx_count); __FILE__,__LINE__,info->device_name,info->tx_count);
if (info->params.mode != MGSL_MODE_ASYNC) {
/* disable TXRDY IRQ, enable IDLE IRQ */
info->ie0_value &= ~TXRDYE;
info->ie1_value |= IDLE;
write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value));
return;
}
if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) {
tx_stop(info); tx_stop(info);
return; return;
...@@ -2463,13 +2477,6 @@ void isr_rxdmaerror(SLMP_INFO * info) ...@@ -2463,13 +2477,6 @@ void isr_rxdmaerror(SLMP_INFO * info)
void isr_txdmaok(SLMP_INFO * info) void isr_txdmaok(SLMP_INFO * info)
{ {
/* BIT7 = EOT (end of transfer, used for async mode)
* BIT6 = EOM (end of message/frame, used for sync mode)
*
* We don't look at DMA status because only EOT is enabled
* and we always clear and disable all tx DMA IRQs.
*/
// unsigned char dma_status = read_reg(info,TXDMA + DSR) & 0xc0;
unsigned char status_reg1 = read_reg(info, SR1); unsigned char status_reg1 = read_reg(info, SR1);
write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */
...@@ -2480,19 +2487,10 @@ void isr_txdmaok(SLMP_INFO * info) ...@@ -2480,19 +2487,10 @@ void isr_txdmaok(SLMP_INFO * info)
printk("%s(%d):%s isr_txdmaok(), status=%02x\n", printk("%s(%d):%s isr_txdmaok(), status=%02x\n",
__FILE__,__LINE__,info->device_name,status_reg1); __FILE__,__LINE__,info->device_name,status_reg1);
/* If transmitter already idle, do end of frame processing, /* program TXRDY as FIFO empty flag, enable TXRDY IRQ */
* otherwise enable interrupt for tx IDLE. write_reg16(info, TRC0, 0);
*/ info->ie0_value |= TXRDYE;
if (status_reg1 & IDLE) write_reg(info, IE0, info->ie0_value);
isr_txeom(info, IDLE);
else {
/* disable and clear underrun IRQ, enable IDLE interrupt */
info->ie1_value |= IDLE;
info->ie1_value &= ~UDRN;
write_reg(info, IE1, info->ie1_value);
write_reg(info, SR1, UDRN);
}
} }
void isr_txdmaerror(SLMP_INFO * info) void isr_txdmaerror(SLMP_INFO * info)
...@@ -3176,7 +3174,7 @@ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr) ...@@ -3176,7 +3174,7 @@ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr)
unsigned char oldval = info->ie1_value; unsigned char oldval = info->ie1_value;
unsigned char newval = oldval + unsigned char newval = oldval +
(mask & MgslEvent_ExitHuntMode ? FLGD:0) + (mask & MgslEvent_ExitHuntMode ? FLGD:0) +
(mask & MgslEvent_IdleReceived ? IDLE:0); (mask & MgslEvent_IdleReceived ? IDLD:0);
if ( oldval != newval ) { if ( oldval != newval ) {
info->ie1_value = newval; info->ie1_value = newval;
write_reg(info, IE1, info->ie1_value); write_reg(info, IE1, info->ie1_value);
...@@ -3243,7 +3241,7 @@ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr) ...@@ -3243,7 +3241,7 @@ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr)
spin_lock_irqsave(&info->lock,flags); spin_lock_irqsave(&info->lock,flags);
if (!waitqueue_active(&info->event_wait_q)) { if (!waitqueue_active(&info->event_wait_q)) {
/* disable enable exit hunt mode/idle rcvd IRQs */ /* disable enable exit hunt mode/idle rcvd IRQs */
info->ie1_value &= ~(FLGD|IDLE); info->ie1_value &= ~(FLGD|IDLD);
write_reg(info, IE1, info->ie1_value); write_reg(info, IE1, info->ie1_value);
} }
spin_unlock_irqrestore(&info->lock,flags); spin_unlock_irqrestore(&info->lock,flags);
...@@ -3637,9 +3635,10 @@ void free_tmp_rx_buf(SLMP_INFO *info) ...@@ -3637,9 +3635,10 @@ void free_tmp_rx_buf(SLMP_INFO *info)
int claim_resources(SLMP_INFO *info) int claim_resources(SLMP_INFO *info)
{ {
if (request_mem_region(info->phys_memory_base,0x40000,"synclinkmp") == NULL) { if (request_mem_region(info->phys_memory_base,SCA_MEM_SIZE,"synclinkmp") == NULL) {
printk( "%s(%d):%s mem addr conflict, Addr=%08X\n", printk( "%s(%d):%s mem addr conflict, Addr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base); __FILE__,__LINE__,info->device_name, info->phys_memory_base);
info->init_error = DiagStatus_AddressConflict;
goto errout; goto errout;
} }
else else
...@@ -3648,22 +3647,25 @@ int claim_resources(SLMP_INFO *info) ...@@ -3648,22 +3647,25 @@ int claim_resources(SLMP_INFO *info)
if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) { if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) {
printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n", printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_lcr_base); __FILE__,__LINE__,info->device_name, info->phys_lcr_base);
info->init_error = DiagStatus_AddressConflict;
goto errout; goto errout;
} }
else else
info->lcr_mem_requested = 1; info->lcr_mem_requested = 1;
if (request_mem_region(info->phys_sca_base + info->sca_offset,512,"synclinkmp") == NULL) { if (request_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE,"synclinkmp") == NULL) {
printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n", printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_sca_base); __FILE__,__LINE__,info->device_name, info->phys_sca_base);
info->init_error = DiagStatus_AddressConflict;
goto errout; goto errout;
} }
else else
info->sca_base_requested = 1; info->sca_base_requested = 1;
if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,16,"synclinkmp") == NULL) { if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE,"synclinkmp") == NULL) {
printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n", printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_statctrl_base); __FILE__,__LINE__,info->device_name, info->phys_statctrl_base);
info->init_error = DiagStatus_AddressConflict;
goto errout; goto errout;
} }
else else
...@@ -3673,33 +3675,41 @@ int claim_resources(SLMP_INFO *info) ...@@ -3673,33 +3675,41 @@ int claim_resources(SLMP_INFO *info)
if (!info->memory_base) { if (!info->memory_base) {
printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n", printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base ); __FILE__,__LINE__,info->device_name, info->phys_memory_base );
info->init_error = DiagStatus_CantAssignPciResources;
goto errout; goto errout;
} }
if ( !memory_test(info) ) { info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE);
printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
goto errout;
}
info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset;
if (!info->lcr_base) { if (!info->lcr_base) {
printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n", printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_lcr_base ); __FILE__,__LINE__,info->device_name, info->phys_lcr_base );
info->init_error = DiagStatus_CantAssignPciResources;
goto errout; goto errout;
} }
info->lcr_base += info->lcr_offset;
info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE) + info->sca_offset; info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE);
if (!info->sca_base) { if (!info->sca_base) {
printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n", printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_sca_base ); __FILE__,__LINE__,info->device_name, info->phys_sca_base );
info->init_error = DiagStatus_CantAssignPciResources;
goto errout; goto errout;
} }
info->sca_base += info->sca_offset;
info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE) + info->statctrl_offset; info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE);
if (!info->statctrl_base) { if (!info->statctrl_base) {
printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n", printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_statctrl_base ); __FILE__,__LINE__,info->device_name, info->phys_statctrl_base );
info->init_error = DiagStatus_CantAssignPciResources;
goto errout;
}
info->statctrl_base += info->statctrl_offset;
if ( !memory_test(info) ) {
printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
info->init_error = DiagStatus_MemoryError;
goto errout; goto errout;
} }
...@@ -3722,7 +3732,7 @@ void release_resources(SLMP_INFO *info) ...@@ -3722,7 +3732,7 @@ void release_resources(SLMP_INFO *info)
} }
if ( info->shared_mem_requested ) { if ( info->shared_mem_requested ) {
release_mem_region(info->phys_memory_base,0x40000); release_mem_region(info->phys_memory_base,SCA_MEM_SIZE);
info->shared_mem_requested = 0; info->shared_mem_requested = 0;
} }
if ( info->lcr_mem_requested ) { if ( info->lcr_mem_requested ) {
...@@ -3730,11 +3740,11 @@ void release_resources(SLMP_INFO *info) ...@@ -3730,11 +3740,11 @@ void release_resources(SLMP_INFO *info)
info->lcr_mem_requested = 0; info->lcr_mem_requested = 0;
} }
if ( info->sca_base_requested ) { if ( info->sca_base_requested ) {
release_mem_region(info->phys_sca_base + info->sca_offset,512); release_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE);
info->sca_base_requested = 0; info->sca_base_requested = 0;
} }
if ( info->sca_statctrl_requested ) { if ( info->sca_statctrl_requested ) {
release_mem_region(info->phys_statctrl_base + info->statctrl_offset,16); release_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE);
info->sca_statctrl_requested = 0; info->sca_statctrl_requested = 0;
} }
...@@ -3975,7 +3985,6 @@ static struct tty_operations ops = { ...@@ -3975,7 +3985,6 @@ static struct tty_operations ops = {
static void synclinkmp_cleanup(void) static void synclinkmp_cleanup(void)
{ {
unsigned long flags;
int rc; int rc;
SLMP_INFO *info; SLMP_INFO *info;
SLMP_INFO *tmp; SLMP_INFO *tmp;
...@@ -3989,33 +3998,24 @@ static void synclinkmp_cleanup(void) ...@@ -3989,33 +3998,24 @@ static void synclinkmp_cleanup(void)
put_tty_driver(serial_driver); put_tty_driver(serial_driver);
} }
/* reset devices */
info = synclinkmp_device_list; info = synclinkmp_device_list;
while(info) { while(info) {
#ifdef CONFIG_HDLC
hdlcdev_exit(info);
#endif
reset_port(info); reset_port(info);
if ( info->port_num == 0 ) {
if ( info->irq_requested ) {
free_irq(info->irq_level, info);
info->irq_requested = 0;
}
}
info = info->next_device; info = info->next_device;
} }
/* port 0 of each adapter originally claimed /* release devices */
* all resources, release those now
*/
info = synclinkmp_device_list; info = synclinkmp_device_list;
while(info) { while(info) {
#ifdef CONFIG_HDLC
hdlcdev_exit(info);
#endif
free_dma_bufs(info); free_dma_bufs(info);
free_tmp_rx_buf(info); free_tmp_rx_buf(info);
if ( info->port_num == 0 ) { if ( info->port_num == 0 ) {
spin_lock_irqsave(&info->lock,flags); if (info->sca_base)
reset_adapter(info); write_reg(info, LPR, 1); /* set low power mode */
write_reg(info, LPR, 1); /* set low power mode */
spin_unlock_irqrestore(&info->lock,flags);
release_resources(info); release_resources(info);
} }
tmp = info; tmp = info;
...@@ -4298,6 +4298,9 @@ void tx_start(SLMP_INFO *info) ...@@ -4298,6 +4298,9 @@ void tx_start(SLMP_INFO *info)
} }
} }
write_reg16(info, TRC0,
(unsigned short)(((tx_negate_fifo_level-1)<<8) + tx_active_fifo_level));
write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */
write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */
...@@ -4309,11 +4312,10 @@ void tx_start(SLMP_INFO *info) ...@@ -4309,11 +4312,10 @@ void tx_start(SLMP_INFO *info)
write_reg16(info, TXDMA + EDA, write_reg16(info, TXDMA + EDA,
info->tx_buf_list_ex[info->last_tx_buf].phys_entry); info->tx_buf_list_ex[info->last_tx_buf].phys_entry);
/* clear IDLE and UDRN status bit */ /* enable underrun IRQ */
info->ie1_value &= ~(IDLE + UDRN); info->ie1_value &= ~IDLE;
if (info->params.mode != MGSL_MODE_ASYNC) info->ie1_value |= UDRN;
info->ie1_value |= UDRN; /* HDLC, IRQ on underrun */ write_reg(info, IE1, info->ie1_value);
write_reg(info, IE1, info->ie1_value); /* enable MSCI interrupts */
write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); write_reg(info, SR1, (unsigned char)(IDLE + UDRN));
write_reg(info, TXDMA + DIR, 0x40); /* enable Tx DMA interrupts (EOM) */ write_reg(info, TXDMA + DIR, 0x40); /* enable Tx DMA interrupts (EOM) */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment