Message ID | 5339FF99.2050200@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
Hello Bjorn, Was wanting to check your interest on up streaming this one. This one is fairly self-contained and simple, and allows to use polling on a per-port basis. Please let me know you have any comments. Thanks, Rajat > -----Original Message----- > From: Rajat Jain [mailto:rajatxjain@gmail.com] > Sent: Monday, March 31, 2014 4:52 PM > To: Bjorn Helgaas; linux-pci@vger.kernel.org; linux-kernel@vger.kernel.org > Cc: Rajat Jain; Guenter Roeck > Subject: [PATCH] pci/pciehp: Allow polling/irq mode to be decided on a per- > port basis > > Today, there is a global pciehp_poll_mode module parameter using which > either _all_ the hot-pluggable ports are to use polling, or _all_ the ports are > to use interrupts. > > In a system where a certain port has IRQ issues, today the only option is to > use the parameter that converts ALL the ports to use polling mode. > This is not good, and hence this patch intruduces a bit field that can be set > using a PCI quirk that indicates that polling should always be used for this > particular PCIe port. The remaining ports can still hoose to continue to > operate in whatever mode they wish to. > > Signed-off-by: Rajat Jain <rajatxjain@gmail.com> > Signed-off-by: Rajat Jain <rajatjain@juniper.net> > Signed-off-by: Guenter Roeck <groeck@juniper.net> > --- > drivers/pci/hotplug/pciehp.h | 1 + > drivers/pci/hotplug/pciehp_hpc.c | 16 ++++++++++------ > include/linux/pci.h | 1 + > 3 files changed, 12 insertions(+), 6 deletions(-) > > diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h > index d208791..753a3b4 100644 > --- a/drivers/pci/hotplug/pciehp.h > +++ b/drivers/pci/hotplug/pciehp.h > @@ -98,6 +98,7 @@ struct controller { > unsigned int no_cmd_complete:1; > unsigned int link_active_reporting:1; > unsigned int notification_enabled:1; > + unsigned int use_polling:1; /* Always uses polling for this slot */ > unsigned int power_fault_detected; > }; > > diff --git a/drivers/pci/hotplug/pciehp_hpc.c > b/drivers/pci/hotplug/pciehp_hpc.c > index d7d058f..d210d23 100644 > --- a/drivers/pci/hotplug/pciehp_hpc.c > +++ b/drivers/pci/hotplug/pciehp_hpc.c > @@ -82,7 +82,7 @@ static inline int pciehp_request_irq(struct controller > *ctrl) > int retval, irq = ctrl->pcie->irq; > > /* Install interrupt polling timer. Start with 10 sec delay */ > - if (pciehp_poll_mode) { > + if (ctrl->use_polling) { > init_timer(&ctrl->poll_timer); > start_int_poll_timer(ctrl, 10); > return 0; > @@ -98,7 +98,7 @@ static inline int pciehp_request_irq(struct controller > *ctrl) > > static inline void pciehp_free_irq(struct controller *ctrl) { > - if (pciehp_poll_mode) > + if (ctrl->use_polling) > del_timer_sync(&ctrl->poll_timer); > else > free_irq(ctrl->pcie->irq, ctrl); > @@ -131,7 +131,7 @@ static int pcie_poll_cmd(struct controller *ctrl) > > static void pcie_wait_cmd(struct controller *ctrl, int poll) { > - unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; > + unsigned int msecs = ctrl->use_polling ? 2500 : 1000; > unsigned long timeout = msecs_to_jiffies(msecs); > int rc; > > @@ -595,7 +595,7 @@ void pcie_enable_notification(struct controller *ctrl) > cmd |= PCI_EXP_SLTCTL_PDCE; > if (MRL_SENS(ctrl)) > cmd |= PCI_EXP_SLTCTL_MRLSCE; > - if (!pciehp_poll_mode) > + if (!ctrl->use_polling) > cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE; > > mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | @@ - > 642,14 +642,14 @@ int pciehp_reset_slot(struct slot *slot, int probe) > stat_mask |= PCI_EXP_SLTSTA_DLLSC; > > pcie_write_cmd(ctrl, 0, ctrl_mask); > - if (pciehp_poll_mode) > + if (ctrl->use_polling) > del_timer_sync(&ctrl->poll_timer); > > pci_reset_bridge_secondary_bus(ctrl->pcie->port); > > pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask); > pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask); > - if (pciehp_poll_mode) > + if (ctrl->use_polling) > int_poll_timeout(ctrl->poll_timer.data); > > return 0; > @@ -789,6 +789,10 @@ struct controller *pcie_init(struct pcie_device *dev) > ctrl_dbg(ctrl, "Link Active Reporting supported\n"); > ctrl->link_active_reporting = 1; > } > + if (pciehp_poll_mode || dev->port->hotplug_polling) { > + ctrl_info(ctrl, "will use polling\n"); > + ctrl->use_polling = 1; > + } > > /* Clear all remaining event bits in Slot Status register */ > pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, diff --git > a/include/linux/pci.h b/include/linux/pci.h index a13d682..b2ec72e 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -336,6 +336,7 @@ struct pci_dev { > unsigned int is_virtfn:1; > unsigned int reset_fn:1; > unsigned int is_hotplug_bridge:1; > + unsigned int hotplug_polling:1; /* Port uses polling for hotplug */ > unsigned int __aer_firmware_first_valid:1; > unsigned int __aer_firmware_first:1; > unsigned int broken_intx_masking:1; > -- > 1.7.9.5 > > -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, Mar 31, 2014 at 04:51:53PM -0700, Rajat Jain wrote: > Today, there is a global pciehp_poll_mode module parameter using which > either _all_ the hot-pluggable ports are to use polling, or _all_ the > ports are to use interrupts. > > In a system where a certain port has IRQ issues, today the only option > is to use the parameter that converts ALL the ports to use polling mode. > This is not good, and hence this patch intruduces a bit field that can > be set using a PCI quirk that indicates that polling should always be > used for this particular PCIe port. The remaining ports can still > hoose to continue to operate in whatever mode they wish to. > > Signed-off-by: Rajat Jain <rajatxjain@gmail.com> > Signed-off-by: Rajat Jain <rajatjain@juniper.net> > Signed-off-by: Guenter Roeck <groeck@juniper.net> I'm willing to merge this, but I'd prefer to merge it along with a quirk that actually sets dev->hotplug_polling. Otherwise it's dead code and I'll have no way to tell whether we need to keep it. Bjorn > --- > drivers/pci/hotplug/pciehp.h | 1 + > drivers/pci/hotplug/pciehp_hpc.c | 16 ++++++++++------ > include/linux/pci.h | 1 + > 3 files changed, 12 insertions(+), 6 deletions(-) > > diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h > index d208791..753a3b4 100644 > --- a/drivers/pci/hotplug/pciehp.h > +++ b/drivers/pci/hotplug/pciehp.h > @@ -98,6 +98,7 @@ struct controller { > unsigned int no_cmd_complete:1; > unsigned int link_active_reporting:1; > unsigned int notification_enabled:1; > + unsigned int use_polling:1; /* Always uses polling for this slot */ > unsigned int power_fault_detected; > }; > > diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c > index d7d058f..d210d23 100644 > --- a/drivers/pci/hotplug/pciehp_hpc.c > +++ b/drivers/pci/hotplug/pciehp_hpc.c > @@ -82,7 +82,7 @@ static inline int pciehp_request_irq(struct controller *ctrl) > int retval, irq = ctrl->pcie->irq; > > /* Install interrupt polling timer. Start with 10 sec delay */ > - if (pciehp_poll_mode) { > + if (ctrl->use_polling) { > init_timer(&ctrl->poll_timer); > start_int_poll_timer(ctrl, 10); > return 0; > @@ -98,7 +98,7 @@ static inline int pciehp_request_irq(struct controller *ctrl) > > static inline void pciehp_free_irq(struct controller *ctrl) > { > - if (pciehp_poll_mode) > + if (ctrl->use_polling) > del_timer_sync(&ctrl->poll_timer); > else > free_irq(ctrl->pcie->irq, ctrl); > @@ -131,7 +131,7 @@ static int pcie_poll_cmd(struct controller *ctrl) > > static void pcie_wait_cmd(struct controller *ctrl, int poll) > { > - unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; > + unsigned int msecs = ctrl->use_polling ? 2500 : 1000; > unsigned long timeout = msecs_to_jiffies(msecs); > int rc; > > @@ -595,7 +595,7 @@ void pcie_enable_notification(struct controller *ctrl) > cmd |= PCI_EXP_SLTCTL_PDCE; > if (MRL_SENS(ctrl)) > cmd |= PCI_EXP_SLTCTL_MRLSCE; > - if (!pciehp_poll_mode) > + if (!ctrl->use_polling) > cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE; > > mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | > @@ -642,14 +642,14 @@ int pciehp_reset_slot(struct slot *slot, int probe) > stat_mask |= PCI_EXP_SLTSTA_DLLSC; > > pcie_write_cmd(ctrl, 0, ctrl_mask); > - if (pciehp_poll_mode) > + if (ctrl->use_polling) > del_timer_sync(&ctrl->poll_timer); > > pci_reset_bridge_secondary_bus(ctrl->pcie->port); > > pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask); > pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask); > - if (pciehp_poll_mode) > + if (ctrl->use_polling) > int_poll_timeout(ctrl->poll_timer.data); > > return 0; > @@ -789,6 +789,10 @@ struct controller *pcie_init(struct pcie_device *dev) > ctrl_dbg(ctrl, "Link Active Reporting supported\n"); > ctrl->link_active_reporting = 1; > } > + if (pciehp_poll_mode || dev->port->hotplug_polling) { > + ctrl_info(ctrl, "will use polling\n"); > + ctrl->use_polling = 1; > + } > > /* Clear all remaining event bits in Slot Status register */ > pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, > diff --git a/include/linux/pci.h b/include/linux/pci.h > index a13d682..b2ec72e 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -336,6 +336,7 @@ struct pci_dev { > unsigned int is_virtfn:1; > unsigned int reset_fn:1; > unsigned int is_hotplug_bridge:1; > + unsigned int hotplug_polling:1; /* Port uses polling for hotplug */ > unsigned int __aer_firmware_first_valid:1; > unsigned int __aer_firmware_first:1; > unsigned int broken_intx_masking:1; > -- > 1.7.9.5 > -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
> -----Original Message----- > From: Bjorn Helgaas [mailto:bhelgaas@google.com] > Sent: Thursday, April 24, 2014 2:31 PM > To: Rajat Jain > Cc: linux-pci@vger.kernel.org; linux-kernel@vger.kernel.org; Rajat > Jain; Guenter Roeck > Subject: Re: [PATCH] pci/pciehp: Allow polling/irq mode to be decided > on a per-port basis > > On Mon, Mar 31, 2014 at 04:51:53PM -0700, Rajat Jain wrote: > > Today, there is a global pciehp_poll_mode module parameter using > which > > either _all_ the hot-pluggable ports are to use polling, or _all_ the > > ports are to use interrupts. > > > > In a system where a certain port has IRQ issues, today the only > option > > is to use the parameter that converts ALL the ports to use polling > mode. > > This is not good, and hence this patch intruduces a bit field that > can > > be set using a PCI quirk that indicates that polling should always be > > used for this particular PCIe port. The remaining ports can still > > hoose to continue to operate in whatever mode they wish to. > > > > Signed-off-by: Rajat Jain <rajatxjain@gmail.com> > > Signed-off-by: Rajat Jain <rajatjain@juniper.net> > > Signed-off-by: Guenter Roeck <groeck@juniper.net> > > I'm willing to merge this, but I'd prefer to merge it along with a > quirk that actually sets dev->hotplug_polling. Otherwise it's dead > code and I'll have no way to tell whether we need to keep it. > Bjorn, what would be the proper location for such a quirk ? We use it to help simulating hotplug support on an IDT PES12NT3. The code is a bit more invasive than just the quirk itself, since it also needs to touch link and slot status registers, so quirks.c doesn't seem appropriate. drivers/pci/pes12nt3.c, maybe, with a separate configuration option ? Or in the hotplug directory ? Guenter -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, Apr 25, 2014 at 10:34 AM, Guenter Roeck <groeck@juniper.net> wrote: > > >> -----Original Message----- >> From: Bjorn Helgaas [mailto:bhelgaas@google.com] >> Sent: Thursday, April 24, 2014 2:31 PM >> To: Rajat Jain >> Cc: linux-pci@vger.kernel.org; linux-kernel@vger.kernel.org; Rajat >> Jain; Guenter Roeck >> Subject: Re: [PATCH] pci/pciehp: Allow polling/irq mode to be decided >> on a per-port basis >> >> On Mon, Mar 31, 2014 at 04:51:53PM -0700, Rajat Jain wrote: >> > Today, there is a global pciehp_poll_mode module parameter using >> which >> > either _all_ the hot-pluggable ports are to use polling, or _all_ the >> > ports are to use interrupts. >> > >> > In a system where a certain port has IRQ issues, today the only >> option >> > is to use the parameter that converts ALL the ports to use polling >> mode. >> > This is not good, and hence this patch intruduces a bit field that >> can >> > be set using a PCI quirk that indicates that polling should always be >> > used for this particular PCIe port. The remaining ports can still >> > hoose to continue to operate in whatever mode they wish to. >> > >> > Signed-off-by: Rajat Jain <rajatxjain@gmail.com> >> > Signed-off-by: Rajat Jain <rajatjain@juniper.net> >> > Signed-off-by: Guenter Roeck <groeck@juniper.net> >> >> I'm willing to merge this, but I'd prefer to merge it along with a >> quirk that actually sets dev->hotplug_polling. Otherwise it's dead >> code and I'll have no way to tell whether we need to keep it. >> > Bjorn, > > what would be the proper location for such a quirk ? > We use it to help simulating hotplug support on an IDT PES12NT3. > The code is a bit more invasive than just the quirk itself, > since it also needs to touch link and slot status registers, > so quirks.c doesn't seem appropriate. > > drivers/pci/pes12nt3.c, maybe, with a separate configuration > option ? Or in the hotplug directory ? If this is only for debug, i.e., you don't intend to ship a product using this simulated hotplug, maybe you should just keep both the quirk and this patch out of tree. If you do want to eventually ship this code for some product, I think it'd be fine to put the quirk in drivers/pci/quirks.c, maybe with a config option to enable it. But without seeing the quirk, I can't really tell. A new file seems overkill unless it's something really huge -- I don't think we really have examples of dedicated files for other chip idiosyncrasies. Bjorn -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
> -----Original Message----- > From: Bjorn Helgaas [mailto:bhelgaas@google.com] > Sent: Friday, April 25, 2014 9:44 AM > To: Guenter Roeck > Cc: Rajat Jain; linux-pci@vger.kernel.org; linux- > kernel@vger.kernel.org; Rajat Jain > Subject: Re: [PATCH] pci/pciehp: Allow polling/irq mode to be decided > on a per-port basis > > On Fri, Apr 25, 2014 at 10:34 AM, Guenter Roeck <groeck@juniper.net> > wrote: > > > > > >> -----Original Message----- > >> From: Bjorn Helgaas [mailto:bhelgaas@google.com] > >> Sent: Thursday, April 24, 2014 2:31 PM > >> To: Rajat Jain > >> Cc: linux-pci@vger.kernel.org; linux-kernel@vger.kernel.org; Rajat > >> Jain; Guenter Roeck > >> Subject: Re: [PATCH] pci/pciehp: Allow polling/irq mode to be > decided > >> on a per-port basis > >> > >> On Mon, Mar 31, 2014 at 04:51:53PM -0700, Rajat Jain wrote: > >> > Today, there is a global pciehp_poll_mode module parameter using > >> which > >> > either _all_ the hot-pluggable ports are to use polling, or _all_ > >> > the ports are to use interrupts. > >> > > >> > In a system where a certain port has IRQ issues, today the only > >> option > >> > is to use the parameter that converts ALL the ports to use polling > >> mode. > >> > This is not good, and hence this patch intruduces a bit field that > >> can > >> > be set using a PCI quirk that indicates that polling should always > >> > be used for this particular PCIe port. The remaining ports can > >> > still hoose to continue to operate in whatever mode they wish to. > >> > > >> > Signed-off-by: Rajat Jain <rajatxjain@gmail.com> > >> > Signed-off-by: Rajat Jain <rajatjain@juniper.net> > >> > Signed-off-by: Guenter Roeck <groeck@juniper.net> > >> > >> I'm willing to merge this, but I'd prefer to merge it along with a > >> quirk that actually sets dev->hotplug_polling. Otherwise it's dead > >> code and I'll have no way to tell whether we need to keep it. > >> > > Bjorn, > > > > what would be the proper location for such a quirk ? > > We use it to help simulating hotplug support on an IDT PES12NT3. > > The code is a bit more invasive than just the quirk itself, since it > > also needs to touch link and slot status registers, so quirks.c > > doesn't seem appropriate. > > > > drivers/pci/pes12nt3.c, maybe, with a separate configuration option ? > > Or in the hotplug directory ? > > If this is only for debug, i.e., you don't intend to ship a product > using this simulated hotplug, maybe you should just keep both the quirk > and this patch out of tree. > > If you do want to eventually ship this code for some product, I think > it'd be fine to put the quirk in drivers/pci/quirks.c, maybe with a > config option to enable it. But without seeing the quirk, I can't > really tell. A new file seems overkill unless it's something really > huge -- I don't think we really have examples of dedicated files for > other chip idiosyncrasies. > I'd give it a 50:50 probability that it will ship. Current plan is that it is for development only, but I suspect that may change at some point. I agree, this is kind of an outlier. If we push it upstream, it might mostly serve as a reference for others who might have similar problems - not just for the quirk itself, but as an example on how to intercept and manipulate pci configuration register accesses. I attached the file so you can have a look. Guenter /* * PTX5000 SIB - PCI fixup code * * Rajat Jain <rajatjain@juniper.net> * Copyright 2014 Juniper Networks * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License v2 as published by the * Free Software Foundation */ #include <linux/list.h> #include <linux/pci.h> #include <linux/jnx/pci_ids.h> #include <linux/spinlock.h> #define IDT_PES12NT3_DLSTS 0x268 #define IDT_PES12NT3_DLSTS_DLFSM 0x7 #define IDT_PES12NT3_DLSTS_LINKACTIVE 0x4 struct pes12nt3_pci_data { struct list_head list; struct device *dev; struct pci_ops ops; struct pci_ops *old_ops; bool lnksta_dllla; bool sltsta_dllsc; }; static LIST_HEAD(pes12nt3_list); static DEFINE_SPINLOCK(pes12nt3_lock); static int pes12nt3_update_linkstatus(struct pes12nt3_pci_data *data, struct pci_bus *bus, unsigned int devfn) { u32 linkactive; bool dllla; int retval; retval = data->old_ops->read(bus, devfn, IDT_PES12NT3_DLSTS, 4, &linkactive); if (retval) return retval; if (linkactive == 0xffffffff) dllla = false; else dllla = (linkactive & IDT_PES12NT3_DLSTS_DLFSM) == IDT_PES12NT3_DLSTS_LINKACTIVE; if (dllla != data->lnksta_dllla) data->sltsta_dllsc = true; data->lnksta_dllla = dllla; return 0; } static int pes12nt3_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { struct pes12nt3_pci_data *data = container_of(bus->ops, struct pes12nt3_pci_data, ops); int retval, pos; retval = data->old_ops->read(bus, devfn, where, size, val); /* Only need to change the registers at port leading to TF chip */ if (retval || devfn != 0) return retval; retval = pes12nt3_update_linkstatus(data, bus, devfn); if (retval) return retval; pos = where - 0x40; /* * PCI registers smaller than 32 bits may be read using * different lengths at diferent offsets. Consider: * * +-----------------------------------+ * | Reg-1 | Reg-2 | Reg-3 | Reg-4 | * +-----------------------------------+ * ^ ^ ^ ^ * ptr ptr+1 ptr+2 ptr+3 * * Reg-4 may be read by using a: * 1 byte read at (ptr+3) * 2 byte read at (ptr+2) * 4 byte read at (ptr) * etc * * We need to take of this here. */ switch (size) { case 4: switch (pos) { case 0: if (*val == 0xffffffff) *val = 0; else *val |= (PCI_EXP_FLAGS_SLOT << 16); break; case PCI_EXP_LNKCAP: if (*val == 0xffffffff) *val = 0; else *val |= PCI_EXP_LNKCAP_DLLLARC; break; case PCI_EXP_SLTCAP: if (*val == 0xffffffff) { *val = 0; } else { *val |= PCI_EXP_SLTCAP_HPC; *val = (*val & ~PCI_EXP_SLTCAP_PSN) | (bus->number << 19); } break; case PCI_EXP_LNKCTL: if (*val == 0xffffffff) { *val = 0; } else { if (data->lnksta_dllla) *val |= PCI_EXP_LNKSTA_DLLLA << 16; else *val &= ~(PCI_EXP_LNKSTA_DLLLA << 16); } break; } break; case 2: switch (pos) { case PCI_EXP_FLAGS_SLOT: if (*val == 0xffff) *val = 0; else *val |= PCI_EXP_FLAGS_SLOT; break; case PCI_EXP_LNKSTA: if (*val == 0xffff) { *val = 0; } else { if (data->lnksta_dllla) *val |= PCI_EXP_LNKSTA_DLLLA; else *val &= ~PCI_EXP_LNKSTA_DLLLA; } break; case PCI_EXP_SLTSTA: if (*val == 0xffff) *val = PCI_EXP_SLTSTA_DLLSC; else if (data->sltsta_dllsc) *val |= PCI_EXP_SLTSTA_DLLSC; break; } break; } return 0; } static int pes12nt3_pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { struct pes12nt3_pci_data *data = container_of(bus->ops, struct pes12nt3_pci_data, ops); int pos = where - 0x40; int retval; if (devfn == 0 && size == 2) { switch (pos) { case PCI_EXP_SLTSTA: if (val & PCI_EXP_SLTSTA_DLLSC) data->sltsta_dllsc = false; break; } } retval = data->old_ops->write(bus, devfn, where, size, val); if (retval || devfn != 0) return retval; /* Catch situations where the link status changed after being handled */ return pes12nt3_update_linkstatus(data, bus, devfn); } static void pes12nt3_fake_linkstate_hotplug(struct pci_dev *dev) { struct pes12nt3_pci_data *data; if (pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM) { data = kzalloc(sizeof(*data), GFP_KERNEL); if (data == NULL) return; data->ops.read = pes12nt3_pci_read; data->ops.write = pes12nt3_pci_write; data->old_ops = pci_bus_set_ops(dev->subordinate, &data->ops); data->dev = &dev->dev; spin_lock(&pes12nt3_lock); list_add(&data->list, &pes12nt3_list); spin_unlock(&pes12nt3_lock); } else if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) { dev->hotplug_polling = 1; /* No IRQ support */ dev->pcie_flags_reg |= PCI_EXP_FLAGS_SLOT; } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_IDT_PES12NT3_TRANS_AB, pes12nt3_fake_linkstate_hotplug); static void pes12nt3_cleanup_entry(struct device *dev) { struct pes12nt3_pci_data *data, *tmp; spin_lock(&pes12nt3_lock); list_for_each_entry_safe(data, tmp, &pes12nt3_list, list) { if (data->dev == dev) { list_del(&data->list); kfree(data); break; } } spin_unlock(&pes12nt3_lock); } static int pes12nt3_notifier_call(struct notifier_block *n, unsigned long action, void *dev) { if (action == BUS_NOTIFY_DEL_DEVICE) pes12nt3_cleanup_entry(dev); return NOTIFY_DONE; } static struct notifier_block pes12nt3_nb = { .notifier_call = pes12nt3_notifier_call, }; static int __init pes12nt3_init(void) { bus_register_notifier(&pci_bus_type, &pes12nt3_nb); return 0; } subsys_initcall(pes12nt3_init);
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index d208791..753a3b4 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -98,6 +98,7 @@ struct controller { unsigned int no_cmd_complete:1; unsigned int link_active_reporting:1; unsigned int notification_enabled:1; + unsigned int use_polling:1; /* Always uses polling for this slot */ unsigned int power_fault_detected; }; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index d7d058f..d210d23 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -82,7 +82,7 @@ static inline int pciehp_request_irq(struct controller *ctrl) int retval, irq = ctrl->pcie->irq; /* Install interrupt polling timer. Start with 10 sec delay */ - if (pciehp_poll_mode) { + if (ctrl->use_polling) { init_timer(&ctrl->poll_timer); start_int_poll_timer(ctrl, 10); return 0; @@ -98,7 +98,7 @@ static inline int pciehp_request_irq(struct controller *ctrl) static inline void pciehp_free_irq(struct controller *ctrl) { - if (pciehp_poll_mode) + if (ctrl->use_polling) del_timer_sync(&ctrl->poll_timer); else free_irq(ctrl->pcie->irq, ctrl); @@ -131,7 +131,7 @@ static int pcie_poll_cmd(struct controller *ctrl) static void pcie_wait_cmd(struct controller *ctrl, int poll) { - unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; + unsigned int msecs = ctrl->use_polling ? 2500 : 1000; unsigned long timeout = msecs_to_jiffies(msecs); int rc; @@ -595,7 +595,7 @@ void pcie_enable_notification(struct controller *ctrl) cmd |= PCI_EXP_SLTCTL_PDCE; if (MRL_SENS(ctrl)) cmd |= PCI_EXP_SLTCTL_MRLSCE; - if (!pciehp_poll_mode) + if (!ctrl->use_polling) cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE; mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | @@ -642,14 +642,14 @@ int pciehp_reset_slot(struct slot *slot, int probe) stat_mask |= PCI_EXP_SLTSTA_DLLSC; pcie_write_cmd(ctrl, 0, ctrl_mask); - if (pciehp_poll_mode) + if (ctrl->use_polling) del_timer_sync(&ctrl->poll_timer); pci_reset_bridge_secondary_bus(ctrl->pcie->port); pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask); pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask); - if (pciehp_poll_mode) + if (ctrl->use_polling) int_poll_timeout(ctrl->poll_timer.data); return 0; @@ -789,6 +789,10 @@ struct controller *pcie_init(struct pcie_device *dev) ctrl_dbg(ctrl, "Link Active Reporting supported\n"); ctrl->link_active_reporting = 1; } + if (pciehp_poll_mode || dev->port->hotplug_polling) { + ctrl_info(ctrl, "will use polling\n"); + ctrl->use_polling = 1; + } /* Clear all remaining event bits in Slot Status register */ pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, diff --git a/include/linux/pci.h b/include/linux/pci.h index a13d682..b2ec72e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -336,6 +336,7 @@ struct pci_dev { unsigned int is_virtfn:1; unsigned int reset_fn:1; unsigned int is_hotplug_bridge:1; + unsigned int hotplug_polling:1; /* Port uses polling for hotplug */ unsigned int __aer_firmware_first_valid:1; unsigned int __aer_firmware_first:1; unsigned int broken_intx_masking:1;