* [PATCH 0/3] PCI VPD changes
@ 2008-09-04 20:56 Stephen Hemminger
2008-09-04 20:56 ` [PATCH 1/3] PCI: vpd handle longer delays in access Stephen Hemminger
` (2 more replies)
0 siblings, 3 replies; 14+ messages in thread
From: Stephen Hemminger @ 2008-09-04 20:56 UTC (permalink / raw)
To: Jesse Barnes, Ben Hutchings; +Cc: linux-pci, linux-kernel
Slightly revised from my last set. Allow mutex to be killed, and
just use yield.
--
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH 1/3] PCI: vpd handle longer delays in access 2008-09-04 20:56 [PATCH 0/3] PCI VPD changes Stephen Hemminger @ 2008-09-04 20:56 ` Stephen Hemminger 2008-09-05 9:11 ` Peter Zijlstra ` (2 more replies) 2008-09-04 20:56 ` [PATCH 2/3] PCI: revise VPD access interface Stephen Hemminger 2008-09-04 20:56 ` [PATCH 3/3] PCI: add interface to set visible size of VPD Stephen Hemminger 2 siblings, 3 replies; 14+ messages in thread From: Stephen Hemminger @ 2008-09-04 20:56 UTC (permalink / raw) To: Jesse Barnes, Ben Hutchings; +Cc: linux-pci, linux-kernel [-- Attachment #1: vpd-delay.patch --] [-- Type: text/plain, Size: 3108 bytes --] Accessing the VPD area can take a long time. The existing VPD access code fails consistently on my hardware. There are comments in the SysKonnect vendor driver that it can take up to 13ms per word. Change the access routines to: * use a mutex rather than spinning with IRQ's disabled and lock held * have a longer timeout * call schedule while spinning to provide some responsivness Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> --- a/drivers/pci/access.c 2008-09-04 09:06:51.000000000 -0700 +++ b/drivers/pci/access.c 2008-09-04 10:16:52.000000000 -0700 @@ -133,7 +133,7 @@ PCI_USER_WRITE_CONFIG(dword, u32) struct pci_vpd_pci22 { struct pci_vpd base; - spinlock_t lock; /* controls access to hardware and the flags */ + struct mutex lock; u8 cap; bool busy; bool flag; /* value of F bit to wait for */ @@ -144,29 +144,33 @@ static int pci_vpd_pci22_wait(struct pci { struct pci_vpd_pci22 *vpd = container_of(dev->vpd, struct pci_vpd_pci22, base); - u16 flag, status; - int wait; + u16 flag = vpd->flag ? PCI_VPD_ADDR_F : 0; + unsigned long timeout = jiffies + (vpd->flag ? HZ/50 : HZ/10); + u16 status; int ret; if (!vpd->busy) return 0; - flag = vpd->flag ? PCI_VPD_ADDR_F : 0; - wait = vpd->flag ? 10 : 1000; /* read: 100 us; write: 10 ms */ for (;;) { - ret = pci_user_read_config_word(dev, - vpd->cap + PCI_VPD_ADDR, + ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR, &status); if (ret < 0) - return ret; + break; + if ((status & PCI_VPD_ADDR_F) == flag) { vpd->busy = false; - return 0; + break; } - if (wait-- == 0) + + if (time_after(jiffies, timeout)) return -ETIMEDOUT; - udelay(10); + if (signal_pending(current)) + return -EINTR; + yield(); } + + return ret; } static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size, @@ -183,7 +187,9 @@ static int pci_vpd_pci22_read(struct pci if (size == 0) return 0; - spin_lock_irq(&vpd->lock); + ret = mutex_lock_killable(&vpd->lock); + if (ret) + return ret; ret = pci_vpd_pci22_wait(dev); if (ret < 0) goto out; @@ -199,7 +205,7 @@ static int pci_vpd_pci22_read(struct pci ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, &val); out: - spin_unlock_irq(&vpd->lock); + mutex_unlock(&vpd->lock); if (ret < 0) return ret; @@ -231,7 +237,9 @@ static int pci_vpd_pci22_write(struct pc val |= ((u8) *buf++) << 16; val |= ((u32)(u8) *buf++) << 24; - spin_lock_irq(&vpd->lock); + ret = mutex_lock_killable(&vpd->lock); + if (ret) + return ret; ret = pci_vpd_pci22_wait(dev); if (ret < 0) goto out; @@ -247,7 +255,7 @@ static int pci_vpd_pci22_write(struct pc vpd->flag = 0; ret = pci_vpd_pci22_wait(dev); out: - spin_unlock_irq(&vpd->lock); + mutex_unlock(&vpd->lock); if (ret < 0) return ret; @@ -279,7 +287,7 @@ int pci_vpd_pci22_init(struct pci_dev *d vpd->base.len = PCI_VPD_PCI22_SIZE; vpd->base.ops = &pci_vpd_pci22_ops; - spin_lock_init(&vpd->lock); + mutex_init(&vpd->lock); vpd->cap = cap; vpd->busy = false; dev->vpd = &vpd->base; -- ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/3] PCI: vpd handle longer delays in access 2008-09-04 20:56 ` [PATCH 1/3] PCI: vpd handle longer delays in access Stephen Hemminger @ 2008-09-05 9:11 ` Peter Zijlstra 2008-09-05 12:40 ` Matthew Wilcox 2008-09-08 20:40 ` Andrew Morton 2 siblings, 0 replies; 14+ messages in thread From: Peter Zijlstra @ 2008-09-05 9:11 UTC (permalink / raw) To: Stephen Hemminger; +Cc: Jesse Barnes, Ben Hutchings, linux-pci, linux-kernel On Thu, 2008-09-04 at 13:56 -0700, Stephen Hemminger wrote: > plain text document attachment (vpd-delay.patch) > Accessing the VPD area can take a long time. The existing > VPD access code fails consistently on my hardware. There are comments > in the SysKonnect vendor driver that it can take up to 13ms per word. > > Change the access routines to: > * use a mutex rather than spinning with IRQ's disabled and lock held > * have a longer timeout > * call schedule while spinning to provide some responsivness > > Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> > > > --- a/drivers/pci/access.c 2008-09-04 09:06:51.000000000 -0700 > +++ b/drivers/pci/access.c 2008-09-04 10:16:52.000000000 -0700 > @@ -133,7 +133,7 @@ PCI_USER_WRITE_CONFIG(dword, u32) > > struct pci_vpd_pci22 { > struct pci_vpd base; > - spinlock_t lock; /* controls access to hardware and the flags */ > + struct mutex lock; > u8 cap; > bool busy; > bool flag; /* value of F bit to wait for */ > @@ -144,29 +144,33 @@ static int pci_vpd_pci22_wait(struct pci > { > struct pci_vpd_pci22 *vpd = > container_of(dev->vpd, struct pci_vpd_pci22, base); > - u16 flag, status; > - int wait; > + u16 flag = vpd->flag ? PCI_VPD_ADDR_F : 0; > + unsigned long timeout = jiffies + (vpd->flag ? HZ/50 : HZ/10); > + u16 status; > int ret; > > if (!vpd->busy) > return 0; > > - flag = vpd->flag ? PCI_VPD_ADDR_F : 0; > - wait = vpd->flag ? 10 : 1000; /* read: 100 us; write: 10 ms */ > for (;;) { > - ret = pci_user_read_config_word(dev, > - vpd->cap + PCI_VPD_ADDR, > + ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR, > &status); > if (ret < 0) > - return ret; > + break; > + > if ((status & PCI_VPD_ADDR_F) == flag) { > vpd->busy = false; > - return 0; > + break; > } > - if (wait-- == 0) > + > + if (time_after(jiffies, timeout)) > return -ETIMEDOUT; > - udelay(10); > + if (signal_pending(current)) > + return -EINTR; > + yield(); At the very least put a big comment in here that we're polling the hardware without completion event. yield() is not good either, when used with a RT task (IMHO still the only valid use of yield) it mostly doesn't spend any time away from this task at all. The other option, schedule_hrtimeout() isn't ideal either because on crappy hardware it will fall back to jiffie based timeouts and I _hope_ that most hardware is less shitty than the 13ms reported in the changelog. Can we make this a per device delay that starts out small (the previous 10 us sound good) and gets doubled every once in a while when not enough for a particular device? That way we can - at some threshold - switch to sleeping delays.. > } > + > + return ret; > } ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/3] PCI: vpd handle longer delays in access 2008-09-04 20:56 ` [PATCH 1/3] PCI: vpd handle longer delays in access Stephen Hemminger 2008-09-05 9:11 ` Peter Zijlstra @ 2008-09-05 12:40 ` Matthew Wilcox 2008-09-08 20:40 ` Andrew Morton 2 siblings, 0 replies; 14+ messages in thread From: Matthew Wilcox @ 2008-09-05 12:40 UTC (permalink / raw) To: Stephen Hemminger; +Cc: Jesse Barnes, Ben Hutchings, linux-pci, linux-kernel On Thu, Sep 04, 2008 at 01:56:37PM -0700, Stephen Hemminger wrote: > - udelay(10); > + if (signal_pending(current)) > + return -EINTR; If you're going to use _killable instead of _interruptible, this needs to be fatal_signal_pending(). Otherwise the one who owns the lock can be interrupted by _any_ signal while those waiting for the lock can only be interrupted by fatal signals. Which seems daft to me. > - spin_lock_irq(&vpd->lock); > + ret = mutex_lock_killable(&vpd->lock); > + if (ret) > + return ret; What's wrong with the shorter: if (mutex_lock_killable(&vpd->lock)) return -EINTR; ? The actual error is irrelevant here since userspace will never consume it. (I agree with Peter about use of yield()) -- Matthew Wilcox Intel Open Source Technology Centre "Bill, look, we understand that you're interested in selling us this operating system, but compare it to ours. We can't possibly take such a retrograde step." ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/3] PCI: vpd handle longer delays in access 2008-09-04 20:56 ` [PATCH 1/3] PCI: vpd handle longer delays in access Stephen Hemminger 2008-09-05 9:11 ` Peter Zijlstra 2008-09-05 12:40 ` Matthew Wilcox @ 2008-09-08 20:40 ` Andrew Morton 2008-09-08 21:08 ` Stephen Hemminger 2 siblings, 1 reply; 14+ messages in thread From: Andrew Morton @ 2008-09-08 20:40 UTC (permalink / raw) To: Stephen Hemminger; +Cc: jbarnes, bhutchings, linux-pci, linux-kernel On Thu, 04 Sep 2008 13:56:37 -0700 Stephen Hemminger <shemminger@vyatta.com> wrote: > Accessing the VPD area can take a long time. The existing > VPD access code fails consistently on my hardware. There are comments > in the SysKonnect vendor driver that it can take up to 13ms per word. > > Change the access routines to: > * use a mutex rather than spinning with IRQ's disabled and lock held > * have a longer timeout > * call schedule while spinning to provide some responsivness It doesn't call schedule() - it calls yield(). yield() is pretty notoriously badly behaved in the presence of lots of runnable tasks and there's been a general move to eradicate its in-kernel callsites. An alternative would be nice. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/3] PCI: vpd handle longer delays in access 2008-09-08 20:40 ` Andrew Morton @ 2008-09-08 21:08 ` Stephen Hemminger 2008-09-08 21:26 ` Arjan van de Ven 0 siblings, 1 reply; 14+ messages in thread From: Stephen Hemminger @ 2008-09-08 21:08 UTC (permalink / raw) To: Andrew Morton; +Cc: jbarnes, bhutchings, linux-pci, linux-kernel On Mon, 8 Sep 2008 13:40:25 -0700 Andrew Morton <akpm@linux-foundation.org> wrote: > On Thu, 04 Sep 2008 13:56:37 -0700 > Stephen Hemminger <shemminger@vyatta.com> wrote: > > > Accessing the VPD area can take a long time. The existing > > VPD access code fails consistently on my hardware. There are comments > > in the SysKonnect vendor driver that it can take up to 13ms per word. > > > > Change the access routines to: > > * use a mutex rather than spinning with IRQ's disabled and lock held > > * have a longer timeout > > * call schedule while spinning to provide some responsivness > > It doesn't call schedule() - it calls yield(). > > yield() is pretty notoriously badly behaved in the presence of lots of > runnable tasks and there's been a general move to eradicate its > in-kernel callsites. > > An alternative would be nice. What is a good way to say "i am polling for a while"? ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/3] PCI: vpd handle longer delays in access 2008-09-08 21:08 ` Stephen Hemminger @ 2008-09-08 21:26 ` Arjan van de Ven 2008-09-09 16:55 ` Stephen Hemminger 0 siblings, 1 reply; 14+ messages in thread From: Arjan van de Ven @ 2008-09-08 21:26 UTC (permalink / raw) To: Stephen Hemminger Cc: Andrew Morton, jbarnes, bhutchings, linux-pci, linux-kernel On Mon, 8 Sep 2008 14:08:24 -0700 Stephen Hemminger <shemminger@vyatta.com> wrote: > > What is a good way to say "i am polling for a while"? can you take a fixed time delay? or use cond_resched() -- If you want to reach me at my work email, use arjan@linux.intel.com For development, discussion and tips for power savings, visit http://www.lesswatts.org ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/3] PCI: vpd handle longer delays in access 2008-09-08 21:26 ` Arjan van de Ven @ 2008-09-09 16:55 ` Stephen Hemminger 2008-09-09 17:01 ` Arjan van de Ven 0 siblings, 1 reply; 14+ messages in thread From: Stephen Hemminger @ 2008-09-09 16:55 UTC (permalink / raw) To: Arjan van de Ven Cc: Andrew Morton, jbarnes, bhutchings, linux-pci, linux-kernel On Mon, 8 Sep 2008 14:26:05 -0700 Arjan van de Ven <arjan@infradead.org> wrote: > On Mon, 8 Sep 2008 14:08:24 -0700 > Stephen Hemminger <shemminger@vyatta.com> wrote: > > > > > What is a good way to say "i am polling for a while"? > > > can you take a fixed time delay? > > or use cond_resched() cond_resched sounds like the best suggestion. The problem is that this code needs to deal with hardware that could be fast, or slow depending on how the device is implemented. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/3] PCI: vpd handle longer delays in access 2008-09-09 16:55 ` Stephen Hemminger @ 2008-09-09 17:01 ` Arjan van de Ven 0 siblings, 0 replies; 14+ messages in thread From: Arjan van de Ven @ 2008-09-09 17:01 UTC (permalink / raw) To: Stephen Hemminger Cc: Andrew Morton, jbarnes, bhutchings, linux-pci, linux-kernel On Tue, 9 Sep 2008 09:55:48 -0700 Stephen Hemminger <shemminger@vyatta.com> wrote: > On Mon, 8 Sep 2008 14:26:05 -0700 > Arjan van de Ven <arjan@infradead.org> wrote: > > > On Mon, 8 Sep 2008 14:08:24 -0700 > > Stephen Hemminger <shemminger@vyatta.com> wrote: > > > > > > > > What is a good way to say "i am polling for a while"? > > > > > > can you take a fixed time delay? > > > > or use cond_resched() > cond_resched sounds like the best suggestion. The problem is that > this code needs to deal with hardware that could be fast, or slow > depending on how the device is implemented. one option is poll fast for <X jiffies> and then back off with sleeping delays -- Arjan van de Ven Intel Open Source Technology Centre For development, discussion and tips for power savings, visit http://www.lesswatts.org ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 2/3] PCI: revise VPD access interface 2008-09-04 20:56 [PATCH 0/3] PCI VPD changes Stephen Hemminger 2008-09-04 20:56 ` [PATCH 1/3] PCI: vpd handle longer delays in access Stephen Hemminger @ 2008-09-04 20:56 ` Stephen Hemminger 2008-09-05 11:02 ` Ben Hutchings 2008-09-08 20:46 ` Andrew Morton 2008-09-04 20:56 ` [PATCH 3/3] PCI: add interface to set visible size of VPD Stephen Hemminger 2 siblings, 2 replies; 14+ messages in thread From: Stephen Hemminger @ 2008-09-04 20:56 UTC (permalink / raw) To: Jesse Barnes, Ben Hutchings; +Cc: linux-pci, linux-kernel [-- Attachment #1: vpd-ops.patch --] [-- Type: text/plain, Size: 9079 bytes --] Change PCI VPD API which was only used by sysfs to something usable in drivers. * move iteration over multiple words to the low level * cleanup types of arguments * add exportable wrapper Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> --- a/drivers/pci/access.c 2008-09-04 10:16:52.000000000 -0700 +++ b/drivers/pci/access.c 2008-09-04 10:19:47.000000000 -0700 @@ -66,6 +66,39 @@ EXPORT_SYMBOL(pci_bus_write_config_byte) EXPORT_SYMBOL(pci_bus_write_config_word); EXPORT_SYMBOL(pci_bus_write_config_dword); + +/** + * pci_read_vpd - Read one entry from Vital Product Data + * @dev: pci device struct + * @pos: offset in vpd space + * @count: number of bytes to read + * @buf: pointer to where to store result + * + */ +int pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf) +{ + if (!dev->vpd || !dev->vpd->ops) + return -ENODEV; + return dev->vpd->ops->read(dev, pos, count, buf); +} +EXPORT_SYMBOL(pci_read_vpd); + +/** + * pci_write_vpd - Write entry to Vital Product Data + * @dev: pci device struct + * @pos: offset in vpd space + * @count: number of bytes to read + * @val: value to write + * + */ +int pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf) +{ + if (!dev->vpd || !dev->vpd->ops) + return -ENODEV; + return dev->vpd->ops->write(dev, pos, count, buf); +} +EXPORT_SYMBOL(pci_write_vpd); + /* * The following routines are to prevent the user from accessing PCI config * space when it's unsafe to do so. Some devices require this during BIST and @@ -173,93 +206,97 @@ static int pci_vpd_pci22_wait(struct pci return ret; } -static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size, - char *buf) +static int pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count, + void *buf) { struct pci_vpd_pci22 *vpd = container_of(dev->vpd, struct pci_vpd_pci22, base); - u32 val; int ret; - int begin, end, i; + loff_t end = pos + count; + unsigned char *p = buf; - if (pos < 0 || pos > vpd->base.len || size > vpd->base.len - pos) + if (pos < 0 || pos > vpd->base.len || count > vpd->base.len - pos) return -EINVAL; - if (size == 0) - return 0; ret = mutex_lock_killable(&vpd->lock); if (ret) return ret; - ret = pci_vpd_pci22_wait(dev); - if (ret < 0) - goto out; - ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, - pos & ~3); - if (ret < 0) - goto out; - vpd->busy = true; - vpd->flag = 1; - ret = pci_vpd_pci22_wait(dev); - if (ret < 0) - goto out; - ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, - &val); -out: - mutex_unlock(&vpd->lock); - if (ret < 0) - return ret; - /* Convert to bytes */ - begin = pos & 3; - end = min(4, begin + size); - for (i = 0; i < end; ++i) { - if (i >= begin) - *buf++ = val; - val >>= 8; + while (pos < end) { + u32 val; + unsigned int i, skip; + + ret = pci_vpd_pci22_wait(dev); + if (ret < 0) + break; + + ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, + pos & ~3); + if (ret < 0) + break; + vpd->busy = true; + vpd->flag = 1; + ret = pci_vpd_pci22_wait(dev); + if (ret < 0) + break; + + ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, &val); + if (ret < 0) + break; + + skip = pos & 3; + for (i = 0; i < sizeof(u32); i++) { + if (i >= skip) { + *p++ = val; + if (++pos == end) + break; + } + val >>= 8; + } } - return end - begin; + mutex_unlock(&vpd->lock); + return ret ? ret : count; } -static int pci_vpd_pci22_write(struct pci_dev *dev, int pos, int size, - const char *buf) +static int pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count, + const void *buf) { struct pci_vpd_pci22 *vpd = container_of(dev->vpd, struct pci_vpd_pci22, base); - u32 val; + loff_t end = pos + count; int ret; - if (pos < 0 || pos > vpd->base.len || pos & 3 || - size > vpd->base.len - pos || size < 4) + if (pos > vpd->base.len || pos & 3) return -EINVAL; - val = (u8) *buf++; - val |= ((u8) *buf++) << 8; - val |= ((u8) *buf++) << 16; - val |= ((u32)(u8) *buf++) << 24; - ret = mutex_lock_killable(&vpd->lock); if (ret) return ret; - ret = pci_vpd_pci22_wait(dev); - if (ret < 0) - goto out; - ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA, - val); - if (ret < 0) - goto out; - ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, - pos | PCI_VPD_ADDR_F); - if (ret < 0) - goto out; - vpd->busy = true; - vpd->flag = 0; - ret = pci_vpd_pci22_wait(dev); -out: - mutex_unlock(&vpd->lock); - if (ret < 0) - return ret; - return 4; + while (pos < end) { + u32 val; + + ret = pci_vpd_pci22_wait(dev); + if (ret < 0) + break; + memcpy(&val, buf, sizeof(u32)); + + ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA, val); + if (ret < 0) + break; + ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, + pos | PCI_VPD_ADDR_F); + if (ret < 0) + break; + vpd->busy = true; + vpd->flag = 0; + ret = pci_vpd_pci22_wait(dev); + + buf += sizeof(u32); + pos += sizeof(u32); + } + mutex_unlock(&vpd->lock); + return ret ? ret : count; } static void pci_vpd_pci22_release(struct pci_dev *dev) @@ -267,7 +304,7 @@ static void pci_vpd_pci22_release(struct kfree(container_of(dev->vpd, struct pci_vpd_pci22, base)); } -static struct pci_vpd_ops pci_vpd_pci22_ops = { +static const struct pci_vpd_ops pci_vpd_pci22_ops = { .read = pci_vpd_pci22_read, .write = pci_vpd_pci22_write, .release = pci_vpd_pci22_release, --- a/drivers/pci/pci.h 2008-09-04 10:14:59.000000000 -0700 +++ b/drivers/pci/pci.h 2008-09-04 10:17:01.000000000 -0700 @@ -44,14 +44,14 @@ extern int pci_user_write_config_word(st extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val); struct pci_vpd_ops { - int (*read)(struct pci_dev *dev, int pos, int size, char *buf); - int (*write)(struct pci_dev *dev, int pos, int size, const char *buf); + int (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf); + int (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); void (*release)(struct pci_dev *dev); }; struct pci_vpd { unsigned int len; - struct pci_vpd_ops *ops; + const struct pci_vpd_ops *ops; struct bin_attribute *attr; /* descriptor for sysfs VPD entry */ }; --- a/drivers/pci/pci-sysfs.c 2008-09-04 10:14:59.000000000 -0700 +++ b/drivers/pci/pci-sysfs.c 2008-09-04 10:17:01.000000000 -0700 @@ -360,55 +360,33 @@ pci_write_config(struct kobject *kobj, s } static ssize_t -pci_read_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +read_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) { struct pci_dev *dev = to_pci_dev(container_of(kobj, struct device, kobj)); - int end; - int ret; if (off > bin_attr->size) count = 0; else if (count > bin_attr->size - off) count = bin_attr->size - off; - end = off + count; - while (off < end) { - ret = dev->vpd->ops->read(dev, off, end - off, buf); - if (ret < 0) - return ret; - buf += ret; - off += ret; - } - - return count; + return pci_read_vpd(dev, off, count, buf); } static ssize_t -pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +write_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) { struct pci_dev *dev = to_pci_dev(container_of(kobj, struct device, kobj)); - int end; - int ret; if (off > bin_attr->size) count = 0; else if (count > bin_attr->size - off) count = bin_attr->size - off; - end = off + count; - - while (off < end) { - ret = dev->vpd->ops->write(dev, off, end - off, buf); - if (ret < 0) - return ret; - buf += ret; - off += ret; - } - return count; + return pci_write_vpd(dev, off, count, buf); } #ifdef HAVE_PCI_LEGACY @@ -739,8 +717,8 @@ int __must_check pci_create_sysfs_dev_fi attr->size = pdev->vpd->len; attr->attr.name = "vpd"; attr->attr.mode = S_IRUSR | S_IWUSR; - attr->read = pci_read_vpd; - attr->write = pci_write_vpd; + attr->read = read_vpd_attr; + attr->write = write_vpd_attr; retval = sysfs_create_bin_file(&pdev->dev.kobj, attr); if (retval) goto err_vpd; --- a/include/linux/pci.h 2008-09-04 10:14:59.000000000 -0700 +++ b/include/linux/pci.h 2008-09-04 10:17:01.000000000 -0700 @@ -650,6 +650,10 @@ int pci_back_from_sleep(struct pci_dev * /* Functions for PCI Hotplug drivers to use */ int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap); +/* Vital product data routines */ +int pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf); +int pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); + /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ void pci_bus_assign_resources(struct pci_bus *bus); void pci_bus_size_bridges(struct pci_bus *bus); -- ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 2/3] PCI: revise VPD access interface 2008-09-04 20:56 ` [PATCH 2/3] PCI: revise VPD access interface Stephen Hemminger @ 2008-09-05 11:02 ` Ben Hutchings 2008-09-08 20:46 ` Andrew Morton 1 sibling, 0 replies; 14+ messages in thread From: Ben Hutchings @ 2008-09-05 11:02 UTC (permalink / raw) To: Stephen Hemminger; +Cc: Jesse Barnes, linux-pci, linux-kernel Stephen Hemminger wrote: > Change PCI VPD API which was only used by sysfs to something usable > in drivers. > * move iteration over multiple words to the low level > * cleanup types of arguments > * add exportable wrapper > > Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> > > --- a/drivers/pci/access.c 2008-09-04 10:16:52.000000000 -0700 > +++ b/drivers/pci/access.c 2008-09-04 10:19:47.000000000 -0700 [...] > -static int pci_vpd_pci22_write(struct pci_dev *dev, int pos, int size, > - const char *buf) > +static int pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count, > + const void *buf) > { > struct pci_vpd_pci22 *vpd = > container_of(dev->vpd, struct pci_vpd_pci22, base); > - u32 val; > + loff_t end = pos + count; > int ret; > > - if (pos < 0 || pos > vpd->base.len || pos & 3 || > - size > vpd->base.len - pos || size < 4) > + if (pos > vpd->base.len || pos & 3) > return -EINVAL; > > - val = (u8) *buf++; > - val |= ((u8) *buf++) << 8; > - val |= ((u8) *buf++) << 16; > - val |= ((u32)(u8) *buf++) << 24; > - > ret = mutex_lock_killable(&vpd->lock); > if (ret) > return ret; > - ret = pci_vpd_pci22_wait(dev); > - if (ret < 0) > - goto out; > - ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA, > - val); > - if (ret < 0) > - goto out; > - ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, > - pos | PCI_VPD_ADDR_F); > - if (ret < 0) > - goto out; > - vpd->busy = true; > - vpd->flag = 0; > - ret = pci_vpd_pci22_wait(dev); > -out: > - mutex_unlock(&vpd->lock); > - if (ret < 0) > - return ret; > > - return 4; > + while (pos < end) { > + u32 val; > + > + ret = pci_vpd_pci22_wait(dev); > + if (ret < 0) > + break; > + memcpy(&val, buf, sizeof(u32)); [...] I'm not sure this is correct. pci_user_write_config_dword() expects a value in host byte order, but this memcpy() makes val always little-endian. Ben. -- Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 2/3] PCI: revise VPD access interface 2008-09-04 20:56 ` [PATCH 2/3] PCI: revise VPD access interface Stephen Hemminger 2008-09-05 11:02 ` Ben Hutchings @ 2008-09-08 20:46 ` Andrew Morton 1 sibling, 0 replies; 14+ messages in thread From: Andrew Morton @ 2008-09-08 20:46 UTC (permalink / raw) To: Stephen Hemminger; +Cc: jbarnes, bhutchings, linux-pci, linux-kernel On Thu, 04 Sep 2008 13:56:38 -0700 Stephen Hemminger <shemminger@vyatta.com> wrote: > Change PCI VPD API which was only used by sysfs to something usable > in drivers. > * move iteration over multiple words to the low level > * cleanup types of arguments > * add exportable wrapper > > Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> > > --- a/drivers/pci/access.c 2008-09-04 10:16:52.000000000 -0700 > +++ b/drivers/pci/access.c 2008-09-04 10:19:47.000000000 -0700 > @@ -66,6 +66,39 @@ EXPORT_SYMBOL(pci_bus_write_config_byte) > EXPORT_SYMBOL(pci_bus_write_config_word); > EXPORT_SYMBOL(pci_bus_write_config_dword); > > + > +/** > + * pci_read_vpd - Read one entry from Vital Product Data > + * @dev: pci device struct > + * @pos: offset in vpd space > + * @count: number of bytes to read > + * @buf: pointer to where to store result > + * > + */ > +int pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf) > +{ > + if (!dev->vpd || !dev->vpd->ops) > + return -ENODEV; > + return dev->vpd->ops->read(dev, pos, count, buf); > +} > +EXPORT_SYMBOL(pci_read_vpd); "read" functions normally return ssize_t, not int. > > ... > > static ssize_t > -pci_read_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, > - char *buf, loff_t off, size_t count) > +read_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr, > + char *buf, loff_t off, size_t count) > { This returns size_t. > static ssize_t > -pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, > - char *buf, loff_t off, size_t count) > +write_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr, > + char *buf, loff_t off, size_t count) as does this. > @@ -739,8 +717,8 @@ int __must_check pci_create_sysfs_dev_fi > attr->size = pdev->vpd->len; > attr->attr.name = "vpd"; > attr->attr.mode = S_IRUSR | S_IWUSR; > - attr->read = pci_read_vpd; > - attr->write = pci_write_vpd; > + attr->read = read_vpd_attr; > + attr->write = write_vpd_attr; But this (I think) is assigning a ssize_t-returning function to an int-returning function pointer. ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 3/3] PCI: add interface to set visible size of VPD 2008-09-04 20:56 [PATCH 0/3] PCI VPD changes Stephen Hemminger 2008-09-04 20:56 ` [PATCH 1/3] PCI: vpd handle longer delays in access Stephen Hemminger 2008-09-04 20:56 ` [PATCH 2/3] PCI: revise VPD access interface Stephen Hemminger @ 2008-09-04 20:56 ` Stephen Hemminger 2008-09-05 11:07 ` Ben Hutchings 2 siblings, 1 reply; 14+ messages in thread From: Stephen Hemminger @ 2008-09-04 20:56 UTC (permalink / raw) To: Jesse Barnes, Ben Hutchings; +Cc: linux-pci, linux-kernel [-- Attachment #1: vpd-size.patch --] [-- Type: text/plain, Size: 1460 bytes --] The VPD on all devices may not be 32K. Unfortunately, there is no generic way to find the size, so this adds a simple API hook to reset it. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> --- a/drivers/pci/access.c 2008-09-04 11:29:22.000000000 -0700 +++ b/drivers/pci/access.c 2008-09-04 11:38:29.000000000 -0700 @@ -332,6 +332,24 @@ int pci_vpd_pci22_init(struct pci_dev *d } /** + * pci_vpd_size - Set available Vital Product Data size + * @dev: pci device struct + * @size: available memory in bytes + * + * Adjust size of available VPD area. + */ +int pci_vpd_size(struct pci_dev *dev, size_t size) +{ + if (!dev->vpd) + return -EINVAL; + if (size > PCI_VPD_PCI22_SIZE) + return -EINVAL; + dev->vpd->len = size; + return 0; +} +EXPORT_SYMBOL(pci_vpd_size); + +/** * pci_block_user_cfg_access - Block userspace PCI config reads/writes * @dev: pci device struct * --- a/include/linux/pci.h 2008-09-04 11:28:45.000000000 -0700 +++ b/include/linux/pci.h 2008-09-04 11:29:15.000000000 -0700 @@ -653,6 +653,7 @@ int pci_bus_find_capability(struct pci_b /* Vital product data routines */ int pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf); int pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); +int pci_vpd_size(struct pci_dev *dev, size_t size); /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ void pci_bus_assign_resources(struct pci_bus *bus); -- ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] PCI: add interface to set visible size of VPD 2008-09-04 20:56 ` [PATCH 3/3] PCI: add interface to set visible size of VPD Stephen Hemminger @ 2008-09-05 11:07 ` Ben Hutchings 0 siblings, 0 replies; 14+ messages in thread From: Ben Hutchings @ 2008-09-05 11:07 UTC (permalink / raw) To: Stephen Hemminger; +Cc: Jesse Barnes, linux-pci, linux-kernel Stephen Hemminger wrote: > The VPD on all devices may not be 32K. Unfortunately, there is no > generic way to find the size, so this adds a simple API hook > to reset it. > > Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> > > --- a/drivers/pci/access.c 2008-09-04 11:29:22.000000000 -0700 > +++ b/drivers/pci/access.c 2008-09-04 11:38:29.000000000 -0700 > @@ -332,6 +332,24 @@ int pci_vpd_pci22_init(struct pci_dev *d > } > > /** > + * pci_vpd_size - Set available Vital Product Data size > + * @dev: pci device struct > + * @size: available memory in bytes > + * > + * Adjust size of available VPD area. > + */ > +int pci_vpd_size(struct pci_dev *dev, size_t size) > +{ > + if (!dev->vpd) > + return -EINVAL; > + if (size > PCI_VPD_PCI22_SIZE) > + return -EINVAL; This assumes that PCI 2.2 VPD is the only VPD implementation (which is true at the moment, but at least PCI 2.1 VPD should be added). Maybe this should compare with the current length instead? Ben. > + dev->vpd->len = size; > + return 0; > +} > +EXPORT_SYMBOL(pci_vpd_size); > + > +/** > * pci_block_user_cfg_access - Block userspace PCI config reads/writes > * @dev: pci device struct > * > --- a/include/linux/pci.h 2008-09-04 11:28:45.000000000 -0700 > +++ b/include/linux/pci.h 2008-09-04 11:29:15.000000000 -0700 > @@ -653,6 +653,7 @@ int pci_bus_find_capability(struct pci_b > /* Vital product data routines */ > int pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf); > int pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); > +int pci_vpd_size(struct pci_dev *dev, size_t size); > > /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ > void pci_bus_assign_resources(struct pci_bus *bus); > > -- > -- Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked. ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2008-09-09 17:02 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-09-04 20:56 [PATCH 0/3] PCI VPD changes Stephen Hemminger 2008-09-04 20:56 ` [PATCH 1/3] PCI: vpd handle longer delays in access Stephen Hemminger 2008-09-05 9:11 ` Peter Zijlstra 2008-09-05 12:40 ` Matthew Wilcox 2008-09-08 20:40 ` Andrew Morton 2008-09-08 21:08 ` Stephen Hemminger 2008-09-08 21:26 ` Arjan van de Ven 2008-09-09 16:55 ` Stephen Hemminger 2008-09-09 17:01 ` Arjan van de Ven 2008-09-04 20:56 ` [PATCH 2/3] PCI: revise VPD access interface Stephen Hemminger 2008-09-05 11:02 ` Ben Hutchings 2008-09-08 20:46 ` Andrew Morton 2008-09-04 20:56 ` [PATCH 3/3] PCI: add interface to set visible size of VPD Stephen Hemminger 2008-09-05 11:07 ` Ben Hutchings
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox