LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH] nozomi: fix initialization and early flow control access
@ 2008-03-06 20:45 Frank Seidel
  2008-03-06 21:31 ` patch nozomi-fix-initialization-and-early-flow-control-access.patch added to gregkh-2.6 tree gregkh
  0 siblings, 1 reply; 2+ messages in thread
From: Frank Seidel @ 2008-03-06 20:45 UTC (permalink / raw)
  To: Greg KH, LKML

From: Frank Seidel <fseidel@suse.de>

Due to some flaws in the initialization and flow control
code kernel oopses could be triggered e.g. when accessing
the card too early after insertion.
See e.g. kernel.org bug #10077.
The main part of the fix is a trivial state management
making sure the card is realy ready to use before allowing
any access.

Signed-off-by: Frank Seidel <fseidel@suse.de>
---
 drivers/char/nozomi.c |   61 ++++++++++++++++++++++++++++++++++--------------
 1 files changed, 43 insertions(+), 18 deletions(-)

--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -190,6 +190,14 @@ enum card_type {
 	F32_8 = 8192,	/* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */
 };
 
+/* Initialization states a card can be in */
+enum card_state {
+	NOZOMI_STATE_UKNOWN	= 0,
+	NOZOMI_STATE_ENABLED	= 1,	/* pci device enabled */
+	NOZOMI_STATE_ALLOCATED	= 2,	/* config setup done */
+	NOZOMI_STATE_READY	= 3,	/* flowcontrols received */
+};
+
 /* Two different toggle channels exist */
 enum channel_type {
 	CH_A = 0,
@@ -385,6 +393,7 @@ struct nozomi {
 	spinlock_t spin_mutex;	/* secures access to registers and tty */
 
 	unsigned int index_start;
+	enum card_state state;
 	u32 open_ttys;
 };
 
@@ -686,6 +695,7 @@ static int nozomi_read_config_table(struct nozomi *dc)
 		dc->last_ier = dc->last_ier | CTRL_DL;
 		writew(dc->last_ier, dc->reg_ier);
 
+		dc->state = NOZOMI_STATE_ALLOCATED;
 		dev_info(&dc->pdev->dev, "Initialization OK!\n");
 		return 1;
 	}
@@ -944,6 +954,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,
@@ -1366,22 +1384,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 +1397,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");
@@ -1425,6 +1443,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 +1459,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:
@@ -1553,7 +1573,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))
@@ -1716,6 +1736,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 +1749,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 +1787,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,

^ permalink raw reply	[flat|nested] 2+ messages in thread

* patch nozomi-fix-initialization-and-early-flow-control-access.patch added to gregkh-2.6 tree
  2008-03-06 20:45 [PATCH] nozomi: fix initialization and early flow control access Frank Seidel
@ 2008-03-06 21:31 ` gregkh
  0 siblings, 0 replies; 2+ messages in thread
From: gregkh @ 2008-03-06 21:31 UTC (permalink / raw)
  To: fseidel, greg, gregkh, linux-kernel


This is a note to let you know that I've just added the patch titled

     Subject: nozomi: fix initialization and early flow control access

to my gregkh-2.6 tree.  Its filename is

     nozomi-fix-initialization-and-early-flow-control-access.patch

This tree can be found at 
    http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/


>From fseidel@suse.de  Thu Mar  6 13:20:29 2008
From: Frank Seidel <fseidel@suse.de>
Date: Thu, 06 Mar 2008 21:45:57 +0100
Subject: nozomi: fix initialization and early flow control access
To: Greg KH <greg@kroah.com>, LKML <linux-kernel@vger.kernel.org>
Message-ID: <47D05805.7010003@suse.de>


From: Frank Seidel <fseidel@suse.de>

Due to some flaws in the initialization and flow control
code kernel oopses could be triggered e.g. when accessing
the card too early after insertion.
See e.g. kernel.org bug #10077.
The main part of the fix is a trivial state management
making sure the card is realy ready to use before allowing
any access.

Signed-off-by: Frank Seidel <fseidel@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
 drivers/char/nozomi.c |   61 +++++++++++++++++++++++++++++++++++---------------
 1 file changed, 43 insertions(+), 18 deletions(-)

--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -190,6 +190,14 @@ enum card_type {
 	F32_8 = 8192,	/* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */
 };
 
+/* Initialization states a card can be in */
+enum card_state {
+	NOZOMI_STATE_UKNOWN	= 0,
+	NOZOMI_STATE_ENABLED	= 1,	/* pci device enabled */
+	NOZOMI_STATE_ALLOCATED	= 2,	/* config setup done */
+	NOZOMI_STATE_READY	= 3,	/* flowcontrols received */
+};
+
 /* Two different toggle channels exist */
 enum channel_type {
 	CH_A = 0,
@@ -385,6 +393,7 @@ struct nozomi {
 	spinlock_t spin_mutex;	/* secures access to registers and tty */
 
 	unsigned int index_start;
+	enum card_state state;
 	u32 open_ttys;
 };
 
@@ -686,6 +695,7 @@ static int nozomi_read_config_table(stru
 		dc->last_ier = dc->last_ier | CTRL_DL;
 		writew(dc->last_ier, dc->reg_ier);
 
+		dc->state = NOZOMI_STATE_ALLOCATED;
 		dev_info(&dc->pdev->dev, "Initialization OK!\n");
 		return 1;
 	}
@@ -944,6 +954,14 @@ static int receive_flow_control(struct n
 	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,
@@ -1366,22 +1384,12 @@ static int __devinit nozomi_card_init(st
 
 	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 +1397,16 @@ static int __devinit nozomi_card_init(st
 		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");
@@ -1425,6 +1443,14 @@ static int __devinit nozomi_card_init(st
 	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 +1459,6 @@ static int __devinit nozomi_card_init(st
 							&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:
@@ -1553,7 +1573,7 @@ static int ntty_open(struct tty_struct *
 	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))
@@ -1716,6 +1736,10 @@ static int ntty_tiocmget(struct tty_stru
 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 +1749,7 @@ static int ntty_tiocmset(struct tty_stru
 		set_dtr(tty, 1);
 	else if (clear & TIOCM_DTR)
 		set_dtr(tty, 0);
+	spin_unlock_irqrestore(&dc->spin_mutex, flags);
 
 	return 0;
 }
@@ -1762,7 +1787,7 @@ static int ntty_ioctl_tiocgicount(struct
 	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,


Patches currently in gregkh-2.6 which might be from fseidel@suse.de are

driver-core/nozomi-fix-initialization-and-early-flow-control-access.patch

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2008-03-06 21:32 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-06 20:45 [PATCH] nozomi: fix initialization and early flow control access Frank Seidel
2008-03-06 21:31 ` patch nozomi-fix-initialization-and-early-flow-control-access.patch added to gregkh-2.6 tree gregkh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).