diff mbox series

[RFC,8/9] PCI/PME: Add RCEC PME handling

Message ID 20200724172223.145608-9-sean.v.kelley@intel.com
State New
Headers show
Series Add RCEC handling to PCI/AER | expand

Commit Message

Kelley, Sean V July 24, 2020, 5:22 p.m. UTC
The Root Complex Event Collectors(RCEC) appear as peers of Root Ports
and also have the PME capability. So add RCEC support to the current PME
service driver and attach the PME service driver to the RCEC device.

Co-developed-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Signed-off-by: Sean V Kelley <sean.v.kelley@intel.com>
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
---
 drivers/pci/pcie/pme.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

Comments

Jay Fang Aug. 4, 2020, 8:35 a.m. UTC | #1
在 2020/7/25 1:22, Sean V Kelley 写道:
> The Root Complex Event Collectors(RCEC) appear as peers of Root Ports
> and also have the PME capability. So add RCEC support to the current PME
> service driver and attach the PME service driver to the RCEC device.
> 
> Co-developed-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
> Signed-off-by: Sean V Kelley <sean.v.kelley@intel.com>
> Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
> ---
>  drivers/pci/pcie/pme.c | 15 +++++++++++----
>  1 file changed, 11 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
> index 6a32970bb731..87799166c96a 100644
> --- a/drivers/pci/pcie/pme.c
> +++ b/drivers/pci/pcie/pme.c
> @@ -310,7 +310,10 @@ static int pcie_pme_can_wakeup(struct pci_dev *dev, void *ign)
>  static void pcie_pme_mark_devices(struct pci_dev *port)
>  {
>  	pcie_pme_can_wakeup(port, NULL);
> -	if (port->subordinate)
> +
> +	if (pci_pcie_type(port) == PCI_EXP_TYPE_RC_EC)
> +		pcie_walk_rcec(port, pcie_pme_can_wakeup, NULL);
> +	else if (port->subordinate)
>  		pci_walk_bus(port->subordinate, pcie_pme_can_wakeup, NULL);
>  }
>  
> @@ -320,10 +323,15 @@ static void pcie_pme_mark_devices(struct pci_dev *port)
>   */
>  static int pcie_pme_probe(struct pcie_device *srv)
>  {
> -	struct pci_dev *port;
> +	struct pci_dev *port = srv->port;
>  	struct pcie_pme_service_data *data;
>  	int ret;
>  
> +	/* Limit to Root Ports or Root Complex Event Collectors */
> +	if ((pci_pcie_type(port) != PCI_EXP_TYPE_RC_EC) &&
> +	    (pci_pcie_type(port) != PCI_EXP_TYPE_ROOT_PORT))
> +		return -ENODEV;
> +
>  	data = kzalloc(sizeof(*data), GFP_KERNEL);
>  	if (!data)
>  		return -ENOMEM;
> @@ -333,7 +341,6 @@ static int pcie_pme_probe(struct pcie_device *srv)
>  	data->srv = srv;
>  	set_service_data(srv, data);
>  
> -	port = srv->port;
>  	pcie_pme_interrupt_enable(port, false);
>  	pcie_clear_root_pme_status(port);
>  
> @@ -445,7 +452,7 @@ static void pcie_pme_remove(struct pcie_device *srv)
>  
>  static struct pcie_port_service_driver pcie_pme_driver = {
>  	.name		= "pcie_pme",
> -	.port_type	= PCI_EXP_TYPE_ROOT_PORT,
> +	.port_type	= PCIE_ANY_PORT,
Maybe we can use port_type for driver matching. There is no need
to check the type of port in pcie_pme_probe function.


Jay

>  	.service	= PCIE_PORT_SERVICE_PME,
>  
>  	.probe		= pcie_pme_probe,
>
Jonathan Cameron Aug. 4, 2020, 9:47 a.m. UTC | #2
On Tue, 4 Aug 2020 16:35:59 +0800
Jay Fang <f.fangjian@huawei.com> wrote:

> 在 2020/7/25 1:22, Sean V Kelley 写道:
> > The Root Complex Event Collectors(RCEC) appear as peers of Root Ports
> > and also have the PME capability. So add RCEC support to the current PME
> > service driver and attach the PME service driver to the RCEC device.
> > 
> > Co-developed-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
> > Signed-off-by: Sean V Kelley <sean.v.kelley@intel.com>
> > Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
> > ---
> >  drivers/pci/pcie/pme.c | 15 +++++++++++----
> >  1 file changed, 11 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
> > index 6a32970bb731..87799166c96a 100644
> > --- a/drivers/pci/pcie/pme.c
> > +++ b/drivers/pci/pcie/pme.c
> > @@ -310,7 +310,10 @@ static int pcie_pme_can_wakeup(struct pci_dev *dev, void *ign)
> >  static void pcie_pme_mark_devices(struct pci_dev *port)
> >  {
> >  	pcie_pme_can_wakeup(port, NULL);
> > -	if (port->subordinate)
> > +
> > +	if (pci_pcie_type(port) == PCI_EXP_TYPE_RC_EC)
> > +		pcie_walk_rcec(port, pcie_pme_can_wakeup, NULL);
> > +	else if (port->subordinate)
> >  		pci_walk_bus(port->subordinate, pcie_pme_can_wakeup, NULL);
> >  }
> >  
> > @@ -320,10 +323,15 @@ static void pcie_pme_mark_devices(struct pci_dev *port)
> >   */
> >  static int pcie_pme_probe(struct pcie_device *srv)
> >  {
> > -	struct pci_dev *port;
> > +	struct pci_dev *port = srv->port;
> >  	struct pcie_pme_service_data *data;
> >  	int ret;
> >  
> > +	/* Limit to Root Ports or Root Complex Event Collectors */
> > +	if ((pci_pcie_type(port) != PCI_EXP_TYPE_RC_EC) &&
> > +	    (pci_pcie_type(port) != PCI_EXP_TYPE_ROOT_PORT))
> > +		return -ENODEV;
> > +
> >  	data = kzalloc(sizeof(*data), GFP_KERNEL);
> >  	if (!data)
> >  		return -ENOMEM;
> > @@ -333,7 +341,6 @@ static int pcie_pme_probe(struct pcie_device *srv)
> >  	data->srv = srv;
> >  	set_service_data(srv, data);
> >  
> > -	port = srv->port;
> >  	pcie_pme_interrupt_enable(port, false);
> >  	pcie_clear_root_pme_status(port);
> >  
> > @@ -445,7 +452,7 @@ static void pcie_pme_remove(struct pcie_device *srv)
> >  
> >  static struct pcie_port_service_driver pcie_pme_driver = {
> >  	.name		= "pcie_pme",
> > -	.port_type	= PCI_EXP_TYPE_ROOT_PORT,
> > +	.port_type	= PCIE_ANY_PORT,  
> Maybe we can use port_type for driver matching. There is no need
> to check the type of port in pcie_pme_probe function.
> 

I walked into the same hole for the AER case.  
port_type is effectively an enum so there is no way of specifying several
types unless you want to register different instances of pcie_port_service_driver
and that isn't currently possible.

The PCIE_ANY_PORT is a special case value.

https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/pci_regs.h#L477
https://elixir.bootlin.com/linux/latest/source/drivers/pci/pci-driver.c#L1651

So odd corner case, but I think this is the right solution. Anything better
would require a lot more code to change.

Jonathan





> 
> Jay
> 
> >  	.service	= PCIE_PORT_SERVICE_PME,
> >  
> >  	.probe		= pcie_pme_probe,
> >
diff mbox series

Patch

diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
index 6a32970bb731..87799166c96a 100644
--- a/drivers/pci/pcie/pme.c
+++ b/drivers/pci/pcie/pme.c
@@ -310,7 +310,10 @@  static int pcie_pme_can_wakeup(struct pci_dev *dev, void *ign)
 static void pcie_pme_mark_devices(struct pci_dev *port)
 {
 	pcie_pme_can_wakeup(port, NULL);
-	if (port->subordinate)
+
+	if (pci_pcie_type(port) == PCI_EXP_TYPE_RC_EC)
+		pcie_walk_rcec(port, pcie_pme_can_wakeup, NULL);
+	else if (port->subordinate)
 		pci_walk_bus(port->subordinate, pcie_pme_can_wakeup, NULL);
 }
 
@@ -320,10 +323,15 @@  static void pcie_pme_mark_devices(struct pci_dev *port)
  */
 static int pcie_pme_probe(struct pcie_device *srv)
 {
-	struct pci_dev *port;
+	struct pci_dev *port = srv->port;
 	struct pcie_pme_service_data *data;
 	int ret;
 
+	/* Limit to Root Ports or Root Complex Event Collectors */
+	if ((pci_pcie_type(port) != PCI_EXP_TYPE_RC_EC) &&
+	    (pci_pcie_type(port) != PCI_EXP_TYPE_ROOT_PORT))
+		return -ENODEV;
+
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
@@ -333,7 +341,6 @@  static int pcie_pme_probe(struct pcie_device *srv)
 	data->srv = srv;
 	set_service_data(srv, data);
 
-	port = srv->port;
 	pcie_pme_interrupt_enable(port, false);
 	pcie_clear_root_pme_status(port);
 
@@ -445,7 +452,7 @@  static void pcie_pme_remove(struct pcie_device *srv)
 
 static struct pcie_port_service_driver pcie_pme_driver = {
 	.name		= "pcie_pme",
-	.port_type	= PCI_EXP_TYPE_ROOT_PORT,
+	.port_type	= PCIE_ANY_PORT,
 	.service	= PCIE_PORT_SERVICE_PME,
 
 	.probe		= pcie_pme_probe,