From: "Masayuki Ohtake" <masa-korg@dsn.okisemi.com> To: "Arnd Bergmann" <arnd@arndb.de> Cc: <andrew.chih.howe.khor@intel.com>, <joel.clark@intel.com>, "Wang, Yong Y" <yong.y.wang@intel.com>, <qi.wang@intel.com>, "LKML" <linux-kernel@vger.kernel.org>, <linux-i2c@vger.kernel.org>, "Ben Dooks \(embedded platforms\)" <ben-linux@fluff.org>, "Jean Delvare \(PC drivers, core\)" <khali@linux-fr.org> Subject: Re: [PATCH] I2C driver of Topcliff PCH Date: Tue, 20 Jul 2010 17:19:00 +0900 [thread overview] Message-ID: <000601cb27e4$3768c170$66f8800a@maildom.okisemi.com> (raw) In-Reply-To: 201007152135.00280.arnd@arndb.de Hi Arnd, > > @@ -147,6 +148,11 @@ static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count, > > if (tmp == NULL) > > return -ENOMEM; > > > > + if (copy_from_user(tmp, buf, count)) { > > + kfree(tmp); > > + return -EFAULT; > > + } > > + > > pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n", > > iminor(file->f_path.dentry->d_inode), count); > > > A read function should not do copy_from_user, only copy_to_user. > If you are worried about returning invalid data from kernel space, > better use kzalloc instead of kmalloc to get the buffer. Our I2C HW has special mode. To control the mode, our i2c driver has copy_from_user. Thanks, Ohtake. ----- Original Message ----- From: "Arnd Bergmann" <arnd@arndb.de> To: "Masayuki Ohtak" <masa-korg@dsn.okisemi.com> Cc: "Jean Delvare (PC drivers, core)" <khali@linux-fr.org>; "Ben Dooks (embedded platforms)" <ben-linux@fluff.org>; <linux-i2c@vger.kernel.org>; "LKML" <linux-kernel@vger.kernel.org>; <qi.wang@intel.com>; "Wang, Yong Y" <yong.y.wang@intel.com>; <joel.clark@intel.com>; <andrew.chih.howe.khor@intel.com> Sent: Friday, July 16, 2010 4:35 AM Subject: Re: [PATCH] I2C driver of Topcliff PCH > On Thursday 15 July 2010 09:42:36 Masayuki Ohtak wrote: > > I2C driver of Topcliff PCH > > > > Topcliff PCH is the platform controller hub that is going to be used in > > Intel's upcoming general embedded platform. All IO peripherals in > > Topcliff PCH are actually devices sitting on AMBA bus. > > Topcliff PCH has I2C I/F. Using this I/F, it is able to access system > > devices connected to I2C. > > Looks ok in general. Some minor comments follow: > > > +/** > > + * pch_wait_for_bus_idle() - check the status of bus. > > + * @adap: Pointer to struct i2c_algo_pch_data. > > + * @timeout: waiting time counter (us). > > + */ > > +static s32 pch_wait_for_bus_idle(struct i2c_algo_pch_data *adap, > > + s32 timeout) > > +{ > > + u32 reg_value; > > + void __iomem *p = adap->pch_base_address; > > + > > + /* get the status of bus busy */ > > + reg_value = (ioread32(p + PCH_I2CSR) & I2CMBB_BIT); > > + > > + while ((timeout != 0) && (reg_value != 0)) { > > + msleep(1); /* wait for 100 ms */ > > + reg_value = ioread32(p + PCH_I2CSR) & I2CMBB_BIT; > > + > > + timeout--; > > + } > > > If you want to wait for a maximum amount of time, a loop with > msleep(1) may end up waiting more than twice as long as you want, > because each msleep typically returns one milisecond too late. > > Better use something like: > > time_t timeout = ktime_add_ns(ktime_get(), MAX_NANOSECONDS); > > do { > if (ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0) > break; > msleep(1); > } while (ktime_lt(ktime_get(), timeout)); > > > +/** > > + * pch_wait_for_xfer_complete() - initiates a wait for the tx complete event > > + * @adap: Pointer to struct i2c_algo_pch_data. > > + */ > > +static s32 pch_wait_for_xfer_complete(struct i2c_algo_pch_data *adap) > > +{ > > + u32 temp_flag; > > + s32 ret; > > + ret = wait_event_interruptible_timeout(pch_event, > > + (adap->pch_event_flag != 0), msecs_to_jiffies(50)); > > + > > + dev_dbg(adap->pch_adapter.dev.parent, > > + "%s adap->pch_event_flag = %x", __func__, adap->pch_event_flag); > > + temp_flag = adap->pch_event_flag; > > + adap->pch_event_flag = 0; > > + > > + if (ret == 0) { > > + dev_err(adap->pch_adapter.dev.parent, > > + "%s : Timeout\n", __func__); > > + } else if (ret < 0) { > > + dev_err(adap->pch_adapter.dev.parent, > > + "%s failed : Interrupted by other signal\n", __func__); > > + ret = -ERESTARTSYS; > > + } else if ((temp_flag & I2C_ERROR_MASK) == 0) { > > + ret = 0; > > + } else { > > + dev_err(adap->pch_adapter.dev.parent, > > + "%s failed : Error in transfer\n", __func__); > > + } > > + > > + dev_err(adap->pch_adapter.dev.parent, "%s returns %d\n", __func__, ret); > > + > > + return ret; > > +} > > The control flow is much more complex than it needs to be here. > If you want to handle different kinds of error conditions, best > use goto. Also, it's very unusual to return positive values > on errors and to print dev_err messages on success. > > int ret; > ret = wait_event_interruptible_timeout(...); > if (ret < 0) > goto out; > > if (ret == 0) { > ret = -ETIMEOUT; > goto out; > } > > ret = 0; > if (adap->pch_event_flag & I2C_ERROR_MASK) { > ret = -EIO; > dev_err(adap->pch_adapter.dev.parent, "error bits set: %lx\n", adap->pch_event_flag); > } > > out: > return ret; > > > +/** > > + * pch_handler() - interrupt handler for the PCH I2C controller > > + * @irq: irq number. > > + * @pData: cookie passed back to the handler function. > > + */ > > +static irqreturn_t pch_handler(int irq, void *pData) > > +{ > > + s32 ret; > > + u32 i; > > + > > + struct adapter_info *adap_info = (struct adapter_info *)pData; > > + /* invoke the call back */ > > + > > + if (pch_cbr != NULL) { > > + for (i = 0, ret = 0; i < PCH_MAX_CHN; i++) > > + ret |= (pch_cbr) (&adap_info->pch_data[i]); > > + } else { > > + dev_err(adap_info->pch_data[0].pch_adapter.dev.parent, > > + "%s Call back pointer null ...", __func__); > > + return IRQ_NONE; > > + } > > Here you are multiplexing the interrupt yourself. If you don't > always use all the available channels, it may be better to > register the pch_cbr handler separately for each of the channels > that are actually used, so you don't have to invoke the callback > for all of them all the time. > > > + for (i = 0; i < PCH_MAX_CHN; i++) { > > + adap_info->pch_data[i].p_adapter_info = adap_info; > > + > > + adap_info->pch_data[i].pch_adapter.owner = THIS_MODULE; > > + adap_info->pch_data[i].pch_adapter.class = I2C_CLASS_HWMON; > > + strcpy(adap_info->pch_data[i].pch_adapter.name, "pch_i2c"); > > + adap_info->pch_data[i].pch_adapter.algo = &pch_algorithm; > > + adap_info->pch_data[i].pch_adapter.algo_data = > > + &adap_info->pch_data[i]; > > + > > + /* (i * 0x80) + base_addr; */ > > + adap_info->pch_data[i].pch_base_address = base_addr; > > + > > + adap_info->pch_data[i].pch_adapter.dev.parent = &pdev->dev; > > + > > + ret = i2c_add_adapter(&(adap_info->pch_data[i].pch_adapter)); > > + > > + if (ret) { > > + dev_err(&pdev->dev, "i2c_add_adapter FAILED"); > > + goto err_i2c_add_adapter; > > + } > > + > > + dev_dbg(&pdev->dev, > > + "i2c_add_adapter returns %d for channel-%d\n", ret, i); > > + pch_init(&adap_info->pch_data[i]); > > + dev_dbg(&pdev->dev, "pch_init invoked successfully\n"); > > + } > > + > > + ret = request_irq(pdev->irq, &pch_handler, IRQF_SHARED, > > + MODULE_NAME, adap_info); > > Similarly, you would create a new channel data structure for each channel here > and register it separately, and then request the interrupt with that > data structure as the info. > > > @@ -147,6 +148,11 @@ static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count, > > if (tmp == NULL) > > return -ENOMEM; > > > > + if (copy_from_user(tmp, buf, count)) { > > + kfree(tmp); > > + return -EFAULT; > > + } > > + > > pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n", > > iminor(file->f_path.dentry->d_inode), count); > > > A read function should not do copy_from_user, only copy_to_user. > If you are worried about returning invalid data from kernel space, > better use kzalloc instead of kmalloc to get the buffer. > > Arnd >
WARNING: multiple messages have this Message-ID (diff)
From: "Masayuki Ohtake" <masa-korg-ECg8zkTtlr0C6LszWs/t0g@public.gmane.org> To: Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org> Cc: andrew.chih.howe.khor-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org, joel.clark-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org, "Wang, Yong Y" <yong.y.wang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>, qi.wang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org, LKML <linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>, linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, "Ben Dooks (embedded platforms)" <ben-linux-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org>, "Jean Delvare (PC drivers, core)" <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> Subject: Re: [PATCH] I2C driver of Topcliff PCH Date: Tue, 20 Jul 2010 17:19:00 +0900 [thread overview] Message-ID: <000601cb27e4$3768c170$66f8800a@maildom.okisemi.com> (raw) In-Reply-To: 201007152135.00280.arnd@arndb.de Hi Arnd, > > @@ -147,6 +148,11 @@ static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count, > > if (tmp == NULL) > > return -ENOMEM; > > > > + if (copy_from_user(tmp, buf, count)) { > > + kfree(tmp); > > + return -EFAULT; > > + } > > + > > pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n", > > iminor(file->f_path.dentry->d_inode), count); > > > A read function should not do copy_from_user, only copy_to_user. > If you are worried about returning invalid data from kernel space, > better use kzalloc instead of kmalloc to get the buffer. Our I2C HW has special mode. To control the mode, our i2c driver has copy_from_user. Thanks, Ohtake. ----- Original Message ----- From: "Arnd Bergmann" <arnd-r2nGTMty4D4@public.gmane.org> To: "Masayuki Ohtak" <masa-korg-ECg8zkTtlr0C6LszWs/t0g@public.gmane.org> Cc: "Jean Delvare (PC drivers, core)" <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>; "Ben Dooks (embedded platforms)" <ben-linux-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org>; <linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>; "LKML" <linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>; <qi.wang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>; "Wang, Yong Y" <yong.y.wang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>; <joel.clark-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>; <andrew.chih.howe.khor-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> Sent: Friday, July 16, 2010 4:35 AM Subject: Re: [PATCH] I2C driver of Topcliff PCH > On Thursday 15 July 2010 09:42:36 Masayuki Ohtak wrote: > > I2C driver of Topcliff PCH > > > > Topcliff PCH is the platform controller hub that is going to be used in > > Intel's upcoming general embedded platform. All IO peripherals in > > Topcliff PCH are actually devices sitting on AMBA bus. > > Topcliff PCH has I2C I/F. Using this I/F, it is able to access system > > devices connected to I2C. > > Looks ok in general. Some minor comments follow: > > > +/** > > + * pch_wait_for_bus_idle() - check the status of bus. > > + * @adap: Pointer to struct i2c_algo_pch_data. > > + * @timeout: waiting time counter (us). > > + */ > > +static s32 pch_wait_for_bus_idle(struct i2c_algo_pch_data *adap, > > + s32 timeout) > > +{ > > + u32 reg_value; > > + void __iomem *p = adap->pch_base_address; > > + > > + /* get the status of bus busy */ > > + reg_value = (ioread32(p + PCH_I2CSR) & I2CMBB_BIT); > > + > > + while ((timeout != 0) && (reg_value != 0)) { > > + msleep(1); /* wait for 100 ms */ > > + reg_value = ioread32(p + PCH_I2CSR) & I2CMBB_BIT; > > + > > + timeout--; > > + } > > > If you want to wait for a maximum amount of time, a loop with > msleep(1) may end up waiting more than twice as long as you want, > because each msleep typically returns one milisecond too late. > > Better use something like: > > time_t timeout = ktime_add_ns(ktime_get(), MAX_NANOSECONDS); > > do { > if (ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0) > break; > msleep(1); > } while (ktime_lt(ktime_get(), timeout)); > > > +/** > > + * pch_wait_for_xfer_complete() - initiates a wait for the tx complete event > > + * @adap: Pointer to struct i2c_algo_pch_data. > > + */ > > +static s32 pch_wait_for_xfer_complete(struct i2c_algo_pch_data *adap) > > +{ > > + u32 temp_flag; > > + s32 ret; > > + ret = wait_event_interruptible_timeout(pch_event, > > + (adap->pch_event_flag != 0), msecs_to_jiffies(50)); > > + > > + dev_dbg(adap->pch_adapter.dev.parent, > > + "%s adap->pch_event_flag = %x", __func__, adap->pch_event_flag); > > + temp_flag = adap->pch_event_flag; > > + adap->pch_event_flag = 0; > > + > > + if (ret == 0) { > > + dev_err(adap->pch_adapter.dev.parent, > > + "%s : Timeout\n", __func__); > > + } else if (ret < 0) { > > + dev_err(adap->pch_adapter.dev.parent, > > + "%s failed : Interrupted by other signal\n", __func__); > > + ret = -ERESTARTSYS; > > + } else if ((temp_flag & I2C_ERROR_MASK) == 0) { > > + ret = 0; > > + } else { > > + dev_err(adap->pch_adapter.dev.parent, > > + "%s failed : Error in transfer\n", __func__); > > + } > > + > > + dev_err(adap->pch_adapter.dev.parent, "%s returns %d\n", __func__, ret); > > + > > + return ret; > > +} > > The control flow is much more complex than it needs to be here. > If you want to handle different kinds of error conditions, best > use goto. Also, it's very unusual to return positive values > on errors and to print dev_err messages on success. > > int ret; > ret = wait_event_interruptible_timeout(...); > if (ret < 0) > goto out; > > if (ret == 0) { > ret = -ETIMEOUT; > goto out; > } > > ret = 0; > if (adap->pch_event_flag & I2C_ERROR_MASK) { > ret = -EIO; > dev_err(adap->pch_adapter.dev.parent, "error bits set: %lx\n", adap->pch_event_flag); > } > > out: > return ret; > > > +/** > > + * pch_handler() - interrupt handler for the PCH I2C controller > > + * @irq: irq number. > > + * @pData: cookie passed back to the handler function. > > + */ > > +static irqreturn_t pch_handler(int irq, void *pData) > > +{ > > + s32 ret; > > + u32 i; > > + > > + struct adapter_info *adap_info = (struct adapter_info *)pData; > > + /* invoke the call back */ > > + > > + if (pch_cbr != NULL) { > > + for (i = 0, ret = 0; i < PCH_MAX_CHN; i++) > > + ret |= (pch_cbr) (&adap_info->pch_data[i]); > > + } else { > > + dev_err(adap_info->pch_data[0].pch_adapter.dev.parent, > > + "%s Call back pointer null ...", __func__); > > + return IRQ_NONE; > > + } > > Here you are multiplexing the interrupt yourself. If you don't > always use all the available channels, it may be better to > register the pch_cbr handler separately for each of the channels > that are actually used, so you don't have to invoke the callback > for all of them all the time. > > > + for (i = 0; i < PCH_MAX_CHN; i++) { > > + adap_info->pch_data[i].p_adapter_info = adap_info; > > + > > + adap_info->pch_data[i].pch_adapter.owner = THIS_MODULE; > > + adap_info->pch_data[i].pch_adapter.class = I2C_CLASS_HWMON; > > + strcpy(adap_info->pch_data[i].pch_adapter.name, "pch_i2c"); > > + adap_info->pch_data[i].pch_adapter.algo = &pch_algorithm; > > + adap_info->pch_data[i].pch_adapter.algo_data = > > + &adap_info->pch_data[i]; > > + > > + /* (i * 0x80) + base_addr; */ > > + adap_info->pch_data[i].pch_base_address = base_addr; > > + > > + adap_info->pch_data[i].pch_adapter.dev.parent = &pdev->dev; > > + > > + ret = i2c_add_adapter(&(adap_info->pch_data[i].pch_adapter)); > > + > > + if (ret) { > > + dev_err(&pdev->dev, "i2c_add_adapter FAILED"); > > + goto err_i2c_add_adapter; > > + } > > + > > + dev_dbg(&pdev->dev, > > + "i2c_add_adapter returns %d for channel-%d\n", ret, i); > > + pch_init(&adap_info->pch_data[i]); > > + dev_dbg(&pdev->dev, "pch_init invoked successfully\n"); > > + } > > + > > + ret = request_irq(pdev->irq, &pch_handler, IRQF_SHARED, > > + MODULE_NAME, adap_info); > > Similarly, you would create a new channel data structure for each channel here > and register it separately, and then request the interrupt with that > data structure as the info. > > > @@ -147,6 +148,11 @@ static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count, > > if (tmp == NULL) > > return -ENOMEM; > > > > + if (copy_from_user(tmp, buf, count)) { > > + kfree(tmp); > > + return -EFAULT; > > + } > > + > > pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n", > > iminor(file->f_path.dentry->d_inode), count); > > > A read function should not do copy_from_user, only copy_to_user. > If you are worried about returning invalid data from kernel space, > better use kzalloc instead of kmalloc to get the buffer. > > Arnd >
next prev parent reply other threads:[~2010-07-20 8:19 UTC|newest] Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top 2010-06-22 5:33 [PATCH] Topcliff PHUB: Generate PacketHub driver Masayuki Ohtak 2010-06-22 10:33 ` Masayuki Ohtak 2010-06-22 22:12 ` Andrew Morton 2010-06-23 0:31 ` Masayuki Ohtake 2010-06-22 11:30 ` Arnd Bergmann 2010-06-22 13:52 ` Yong Wang 2010-06-29 23:31 ` Andy Isaacson 2010-06-30 5:58 ` Masayuki Ohtake 2010-06-30 18:28 ` Andy Isaacson 2010-07-01 4:08 ` Masayuki Ohtake 2010-06-30 7:51 ` [PATCH] Packet hub driver of Topcliff PCH Masayuki Ohtak 2010-06-30 18:05 ` Randy Dunlap 2010-07-01 2:52 ` Masayuki Ohtake 2010-07-01 5:14 ` Masayuki Ohtak 2010-07-01 6:58 ` Andy Isaacson 2010-07-01 10:13 ` Masayuki Ohtake 2010-07-01 10:38 ` Masayuki Ohtak 2010-07-01 15:44 ` Randy Dunlap 2010-07-05 7:20 ` Masayuki Ohtak 2010-07-05 15:04 ` Arnd Bergmann 2010-07-06 15:58 ` Randy Dunlap 2010-07-06 6:20 ` Masayuki Ohtak 2010-07-06 6:30 ` Arnd Bergmann 2010-07-07 1:19 ` Yong Wang 2010-07-09 20:00 ` Andrew Morton 2010-07-12 1:25 ` Masayuki Ohtake 2010-07-15 7:25 ` Masayuki Ohtak 2010-07-15 7:42 ` [PATCH] I2C " Masayuki Ohtak 2010-07-15 19:35 ` Arnd Bergmann 2010-07-15 19:35 ` Arnd Bergmann 2010-07-20 0:05 ` Masayuki Ohtake 2010-07-20 0:05 ` Masayuki Ohtake 2010-07-20 4:55 ` Masayuki Ohtake 2010-07-20 4:55 ` Masayuki Ohtake 2010-07-20 9:27 ` Arnd Bergmann 2010-07-20 9:27 ` Arnd Bergmann 2010-07-20 12:38 ` Masayuki Ohtake 2010-07-20 12:38 ` Masayuki Ohtake 2010-07-20 8:19 ` Masayuki Ohtake [this message] 2010-07-20 8:19 ` Masayuki Ohtake 2010-07-20 9:29 ` Arnd Bergmann 2010-07-20 9:29 ` Arnd Bergmann 2010-07-20 12:40 ` Masayuki Ohtake 2010-07-20 12:40 ` Masayuki Ohtake 2010-07-21 6:46 ` Masayuki Ohtak 2010-07-21 6:46 ` Masayuki Ohtak
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to='000601cb27e4$3768c170$66f8800a@maildom.okisemi.com' \ --to=masa-korg@dsn.okisemi.com \ --cc=andrew.chih.howe.khor@intel.com \ --cc=arnd@arndb.de \ --cc=ben-linux@fluff.org \ --cc=joel.clark@intel.com \ --cc=khali@linux-fr.org \ --cc=linux-i2c@vger.kernel.org \ --cc=linux-kernel@vger.kernel.org \ --cc=qi.wang@intel.com \ --cc=yong.y.wang@intel.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.