From: Frank Seidel Subject: nozomi: cleanups, improved locking and device initialization - added trivial state machine for device state (fixes oopses on too early access to tty devices) - minor further initialization cleanup and write check - pci (ordering) cleanup - fix new locking extension - enhance locking and check return of copy_to_user - increased version to mark next step development begins here, transition from old i/o memory fonction to new ioread/iowrite fucntions Signed-off-by: Frank Seidel --- drivers/char/nozomi.c | 176 ++++++++++++++++++++++++++++--------------------- 1 files changed, 101 insertions(+), 75 deletions(-) diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c index dfaab23..688a7fe 100644 --- a/drivers/char/nozomi.c +++ b/drivers/char/nozomi.c @@ -59,7 +59,7 @@ #include -#define VERSION_STRING DRIVER_DESC " 2.1d (build date: " \ +#define VERSION_STRING DRIVER_DESC " 2.1e (build date: " \ __DATE__ " " __TIME__ ")" /* Macros definitions */ @@ -179,6 +179,11 @@ static int debug; #define NOZOMI_MAX_PORTS 5 #define NOZOMI_MAX_CARDS (NTTY_TTY_MAXMINORS / MAX_PORT) +#define NOZOMI_STATE_UKNOWN 0 +#define NOZOMI_STATE_ENABLED 1 /* pci device enabled */ +#define NOZOMI_STATE_ALLOCATED 2 /* config setup */ +#define NOZOMI_STATE_READY 3 /* flowcontrols received */ + /* Type definitions */ /* @@ -385,6 +390,7 @@ struct nozomi { spinlock_t spin_mutex; /* secures access to registers and tty */ unsigned int index_start; + unsigned int state; u32 open_ttys; }; @@ -397,7 +403,7 @@ struct buffer { /* Global variables */ static const struct pci_device_id nozomi_pci_tbl[] __devinitconst = { {PCI_DEVICE(VENDOR1, DEVICE1)}, - {}, + {0,}, }; MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); @@ -439,11 +445,11 @@ static void read_mem32(u32 *buf, const void __iomem *mem_addr_start, switch (size_bytes) { case 2: /* 2 bytes */ buf16 = (u16 *) buf; - *buf16 = __le16_to_cpu(readw((void __iomem *)ptr)); + *buf16 = __le16_to_cpu(ioread16((void __iomem *)ptr)); goto out; break; case 4: /* 4 bytes */ - *(buf) = __le32_to_cpu(readl((void __iomem *)ptr)); + *(buf) = __le32_to_cpu(ioread32((void __iomem *)ptr)); goto out; break; } @@ -452,11 +458,11 @@ static void read_mem32(u32 *buf, const void __iomem *mem_addr_start, if (size_bytes - i == 2) { /* Handle 2 bytes in the end */ buf16 = (u16 *) buf; - *(buf16) = __le16_to_cpu(readw((void __iomem *)ptr)); + *(buf16) = __le16_to_cpu(ioread16((void __iomem *)ptr)); i += 2; } else { /* Read 4 bytes */ - *(buf) = __le32_to_cpu(readl((void __iomem *)ptr)); + *(buf) = __le32_to_cpu(ioread32((void __iomem *)ptr)); i += 4; } buf++; @@ -485,7 +491,7 @@ static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, switch (size_bytes) { case 2: /* 2 bytes */ buf16 = (const u16 *)buf; - writew(__cpu_to_le16(*buf16), (void __iomem *)ptr); + iowrite16(__cpu_to_le16(*buf16), (void __iomem *)ptr); return 2; break; case 1: /* @@ -493,7 +499,7 @@ static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, * so falling through.. */ case 4: /* 4 bytes */ - writel(__cpu_to_le32(*buf), (void __iomem *)ptr); + iowrite32(__cpu_to_le32(*buf), (void __iomem *)ptr); return 4; break; } @@ -502,11 +508,11 @@ static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, if (size_bytes - i == 2) { /* 2 bytes */ buf16 = (const u16 *)buf; - writew(__cpu_to_le16(*buf16), (void __iomem *)ptr); + iowrite16(__cpu_to_le16(*buf16), (void __iomem *)ptr); i += 2; } else { /* 4 bytes */ - writel(__cpu_to_le32(*buf), (void __iomem *)ptr); + iowrite32(__cpu_to_le32(*buf), (void __iomem *)ptr); i += 4; } buf++; @@ -684,8 +690,9 @@ static int nozomi_read_config_table(struct nozomi *dc) /* Enable control channel */ dc->last_ier = dc->last_ier | CTRL_DL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); + dc->state = NOZOMI_STATE_ALLOCATED; dev_info(&dc->pdev->dev, "Initialization OK!\n"); return 1; } @@ -712,7 +719,7 @@ static int nozomi_read_config_table(struct nozomi *dc) write_mem32(dc->port[PORT_MDM].ul_addr[CH_B], (u32 *) &offset, 4); - writew(MDM_UL | DIAG_DL | MDM_DL, dc->reg_fcr); + iowrite16(MDM_UL | DIAG_DL | MDM_DL, dc->reg_fcr); DBG1("First phase done"); } @@ -727,7 +734,7 @@ static void enable_transmit_ul(enum port_type port, struct nozomi *dc) if (port < NOZOMI_MAX_PORTS) { dc->last_ier |= mask[port]; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); } else { dev_err(&dc->pdev->dev, "Called with wrong port?\n"); } @@ -741,7 +748,7 @@ static void disable_transmit_ul(enum port_type port, struct nozomi *dc) if (port < NOZOMI_MAX_PORTS) { dc->last_ier &= mask[port]; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); } else { dev_err(&dc->pdev->dev, "Called with wrong port?\n"); } @@ -754,7 +761,7 @@ static void enable_transmit_dl(enum port_type port, struct nozomi *dc) if (port < NOZOMI_MAX_PORTS) { dc->last_ier |= mask[port]; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); } else { dev_err(&dc->pdev->dev, "Called with wrong port?\n"); } @@ -768,7 +775,7 @@ static void disable_transmit_dl(enum port_type port, struct nozomi *dc) if (port < NOZOMI_MAX_PORTS) { dc->last_ier &= mask[port]; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); } else { dev_err(&dc->pdev->dev, "Called with wrong port?\n"); } @@ -944,6 +951,14 @@ static int receive_flow_control(struct nozomi *dc) case CTRL_APP2: port = PORT_APP2; enable_ier = APP2_DL; + if (dc->state == NOZOMI_STATE_ALLOCATED) { + /* + * After card initialization the flow control + * received for APP2 is always the last + */ + dc->state = NOZOMI_STATE_READY; + dev_info(&dc->pdev->dev, "Device READY!\n"); + } break; default: dev_err(&dc->pdev->dev, @@ -1056,25 +1071,25 @@ static int handle_data_dl(struct nozomi *dc, enum port_type port, u8 *toggle, { if (*toggle == 0 && read_iir & mask1) { if (receive_data(port, dc)) { - writew(mask1, dc->reg_fcr); + iowrite16(mask1, dc->reg_fcr); *toggle = !(*toggle); } if (read_iir & mask2) { if (receive_data(port, dc)) { - writew(mask2, dc->reg_fcr); + iowrite16(mask2, dc->reg_fcr); *toggle = !(*toggle); } } } else if (*toggle == 1 && read_iir & mask2) { if (receive_data(port, dc)) { - writew(mask2, dc->reg_fcr); + iowrite16(mask2, dc->reg_fcr); *toggle = !(*toggle); } if (read_iir & mask1) { if (receive_data(port, dc)) { - writew(mask1, dc->reg_fcr); + iowrite16(mask1, dc->reg_fcr); *toggle = !(*toggle); } } @@ -1097,47 +1112,47 @@ static int handle_data_ul(struct nozomi *dc, enum port_type port, u16 read_iir) if (*toggle == 0 && read_iir & MDM_UL1) { dc->last_ier &= ~MDM_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); if (send_data(port, dc)) { - writew(MDM_UL1, dc->reg_fcr); + iowrite16(MDM_UL1, dc->reg_fcr); dc->last_ier = dc->last_ier | MDM_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); *toggle = !*toggle; } if (read_iir & MDM_UL2) { dc->last_ier &= ~MDM_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); if (send_data(port, dc)) { - writew(MDM_UL2, dc->reg_fcr); + iowrite16(MDM_UL2, dc->reg_fcr); dc->last_ier = dc->last_ier | MDM_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); *toggle = !*toggle; } } } else if (*toggle == 1 && read_iir & MDM_UL2) { dc->last_ier &= ~MDM_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); if (send_data(port, dc)) { - writew(MDM_UL2, dc->reg_fcr); + iowrite16(MDM_UL2, dc->reg_fcr); dc->last_ier = dc->last_ier | MDM_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); *toggle = !*toggle; } if (read_iir & MDM_UL1) { dc->last_ier &= ~MDM_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); if (send_data(port, dc)) { - writew(MDM_UL1, dc->reg_fcr); + iowrite16(MDM_UL1, dc->reg_fcr); dc->last_ier = dc->last_ier | MDM_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); *toggle = !*toggle; } } } else { - writew(read_iir & MDM_UL, dc->reg_fcr); + iowrite16(read_iir & MDM_UL, dc->reg_fcr); dev_err(&dc->pdev->dev, "port out of sync!\n"); return 0; } @@ -1154,7 +1169,7 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id) return IRQ_NONE; spin_lock(&dc->spin_mutex); - read_iir = readw(dc->reg_iir); + read_iir = ioread16(dc->reg_iir); /* Card removed */ if (read_iir == (u16)-1) @@ -1175,11 +1190,11 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id) if (read_iir & RESET) { if (unlikely(!nozomi_read_config_table(dc))) { dc->last_ier = 0x0; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); dev_err(&dc->pdev->dev, "Could not read status from " "card, we should disable interface\n"); } else { - writew(RESET, dc->reg_fcr); + iowrite16(RESET, dc->reg_fcr); } /* No more useful info if this was the reset interrupt. */ goto exit_handler; @@ -1187,16 +1202,16 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id) if (read_iir & CTRL_UL) { DBG1("CTRL_UL"); dc->last_ier &= ~CTRL_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); if (send_flow_control(dc)) { - writew(CTRL_UL, dc->reg_fcr); + iowrite16(CTRL_UL, dc->reg_fcr); dc->last_ier = dc->last_ier | CTRL_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); } } if (read_iir & CTRL_DL) { receive_flow_control(dc); - writew(CTRL_DL, dc->reg_fcr); + iowrite16(CTRL_DL, dc->reg_fcr); } if (read_iir & MDM_DL) { if (!handle_data_dl(dc, PORT_MDM, @@ -1222,37 +1237,37 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id) } if (read_iir & DIAG_UL) { dc->last_ier &= ~DIAG_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); if (send_data(PORT_DIAG, dc)) { - writew(DIAG_UL, dc->reg_fcr); + iowrite16(DIAG_UL, dc->reg_fcr); dc->last_ier = dc->last_ier | DIAG_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); } } if (read_iir & APP1_DL) { if (receive_data(PORT_APP1, dc)) - writew(APP1_DL, dc->reg_fcr); + iowrite16(APP1_DL, dc->reg_fcr); } if (read_iir & APP1_UL) { dc->last_ier &= ~APP1_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); if (send_data(PORT_APP1, dc)) { - writew(APP1_UL, dc->reg_fcr); + iowrite16(APP1_UL, dc->reg_fcr); dc->last_ier = dc->last_ier | APP1_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); } } if (read_iir & APP2_DL) { if (receive_data(PORT_APP2, dc)) - writew(APP2_DL, dc->reg_fcr); + iowrite16(APP2_DL, dc->reg_fcr); } if (read_iir & APP2_UL) { dc->last_ier &= ~APP2_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); if (send_data(PORT_APP2, dc)) { - writew(APP2_UL, dc->reg_fcr); + iowrite16(APP2_UL, dc->reg_fcr); dc->last_ier = dc->last_ier | APP2_UL; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); } } @@ -1366,22 +1381,12 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, dc->pdev = pdev; - /* Find out what card type it is */ - nozomi_get_card_type(dc); - ret = pci_enable_device(dc->pdev); if (ret) { dev_err(&pdev->dev, "Failed to enable PCI Device\n"); goto err_free; } - start = pci_resource_start(dc->pdev, 0); - if (start == 0) { - dev_err(&pdev->dev, "No I/O address for card detected\n"); - ret = -ENODEV; - goto err_disable_device; - } - ret = pci_request_regions(dc->pdev, NOZOMI_NAME); if (ret) { dev_err(&pdev->dev, "I/O address 0x%04x already in use\n", @@ -1389,6 +1394,16 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, goto err_disable_device; } + start = pci_resource_start(dc->pdev, 0); + if (start == 0) { + dev_err(&pdev->dev, "No I/O address for card detected\n"); + ret = -ENODEV; + goto err_rel_regs; + } + + /* Find out what card type it is */ + nozomi_get_card_type(dc); + dc->base_addr = ioremap(start, dc->card_type); if (!dc->base_addr) { dev_err(&pdev->dev, "Unable to map card MMIO\n"); @@ -1407,9 +1422,13 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, nozomi_setup_private_data(dc); - /* Disable all interrupts */ + /* Disable all interrupts and check write */ dc->last_ier = 0; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); + if (ioread16(dc->reg_ier) != dc->last_ier) { + dev_err(&pdev->dev, "Consistency check failed.\n"); + goto err_free_sbuf; + } ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED, NOZOMI_NAME, dc); @@ -1425,6 +1444,14 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, dc->index_start = ndev_idx * MAX_PORT; ndevs[ndev_idx] = dc; + pci_set_drvdata(pdev, dc); + + /* Enable RESET interrupt */ + dc->last_ier = RESET; + iowrite16(dc->last_ier, dc->reg_ier); + + dc->state = NOZOMI_STATE_ENABLED; + for (i = 0; i < MAX_PORT; i++) { mutex_init(&dc->port[i].tty_sem); dc->port[i].tty_open_count = 0; @@ -1433,12 +1460,6 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, &pdev->dev); } - /* Enable RESET interrupt. */ - dc->last_ier = RESET; - writew(dc->last_ier, dc->reg_ier); - - pci_set_drvdata(pdev, dc); - return 0; err_free_sbuf: @@ -1483,7 +1504,7 @@ static void __devexit nozomi_card_exit(struct pci_dev *pdev) /* Disable all interrupts */ dc->last_ier = 0; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); tty_exit(dc); @@ -1497,7 +1518,7 @@ static void __devexit nozomi_card_exit(struct pci_dev *pdev) /* Setup dc->reg addresses to we can use defines here */ write_mem32(dc->port[PORT_CTRL].ul_addr[0], (u32 *)&ctrl, 2); - writew(CTRL_UL, dc->reg_fcr); /* push the token to the card. */ + iowrite16(CTRL_UL, dc->reg_fcr); /* push the token to the card */ remove_sysfs_files(dc); @@ -1553,7 +1574,7 @@ static int ntty_open(struct tty_struct *tty, struct file *file) struct nozomi *dc = get_dc_by_tty(tty); unsigned long flags; - if (!port || !dc) + if (!port || !dc || dc->state != NOZOMI_STATE_READY) return -ENODEV; if (mutex_lock_interruptible(&port->tty_sem)) @@ -1570,7 +1591,7 @@ static int ntty_open(struct tty_struct *tty, struct file *file) DBG1("open: %d", port->token_dl); spin_lock_irqsave(&dc->spin_mutex, flags); dc->last_ier = dc->last_ier | port->token_dl; - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); spin_unlock_irqrestore(&dc->spin_mutex, flags); } @@ -1602,7 +1623,7 @@ static void ntty_close(struct tty_struct *tty, struct file *file) DBG1("close: %d", port->token_dl); spin_lock_irqsave(&dc->spin_mutex, flags); dc->last_ier &= ~(port->token_dl); - writew(dc->last_ier, dc->reg_ier); + iowrite16(dc->last_ier, dc->reg_ier); spin_unlock_irqrestore(&dc->spin_mutex, flags); } @@ -1716,6 +1737,10 @@ static int ntty_tiocmget(struct tty_struct *tty, struct file *file) static int ntty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { + struct nozomi *dc = get_dc_by_tty(tty); + unsigned long flags; + + spin_lock_irqsave(&dc->spin_mutex, flags); if (set & TIOCM_RTS) set_rts(tty, 1); else if (clear & TIOCM_RTS) @@ -1725,6 +1750,7 @@ static int ntty_tiocmset(struct tty_struct *tty, struct file *file, set_dtr(tty, 1); else if (clear & TIOCM_DTR) set_dtr(tty, 0); + spin_unlock_irqrestore(&dc->spin_mutex, flags); return 0; } @@ -1762,7 +1788,7 @@ static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp) icount.brk = cnow.brk; icount.buf_overrun = cnow.buf_overrun; - return copy_to_user(argp, &icount, sizeof(icount)); + return copy_to_user(argp, &icount, sizeof(icount)) ? -EFAULT : 0; } static int ntty_ioctl(struct tty_struct *tty, struct file *file,