ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/target/linux/generic/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch b/target/linux/generic/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch
new file mode 100644
index 0000000..907b9dc
--- /dev/null
+++ b/target/linux/generic/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch
@@ -0,0 +1,254 @@
+From 863b5b6941f9f43b924393b6ba2b36647e7dee42 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 7 Nov 2019 17:06:08 +0000
+Subject: [PATCH 615/660] net: sfp: rework upstream interface
+
+The current upstream interface is an all-or-nothing, which is
+sub-optimal for future changes, as it doesn't allow the upstream driver
+to prepare for the SFP module becoming available, as it is at boot.
+
+Switch to a find-sfp-bus, add-upstream, del-upstream, put-sfp-bus
+interface structure instead, which allows the upstream driver to
+prepare for a module being available as soon as add-upstream is called.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 10 +++--
+ drivers/net/phy/sfp-bus.c | 92 +++++++++++++++++++++++++++------------
+ include/linux/sfp.h       | 25 +++++++----
+ 3 files changed, 88 insertions(+), 39 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -568,7 +568,7 @@ static int phylink_register_sfp(struct p
+ 	struct sfp_bus *bus;
+ 	int ret;
+ 
+-	bus = sfp_register_upstream_node(fwnode, pl, &sfp_phylink_ops);
++	bus = sfp_bus_find_fwnode(fwnode);
+ 	if (IS_ERR(bus)) {
+ 		ret = PTR_ERR(bus);
+ 		phylink_err(pl, "unable to attach SFP bus: %d\n", ret);
+@@ -577,7 +577,10 @@ static int phylink_register_sfp(struct p
+ 
+ 	pl->sfp_bus = bus;
+ 
+-	return 0;
++	ret = sfp_bus_add_upstream(bus, pl, &sfp_phylink_ops);
++	sfp_bus_put(bus);
++
++	return ret;
+ }
+ 
+ /**
+@@ -675,8 +678,7 @@ EXPORT_SYMBOL_GPL(phylink_create);
+  */
+ void phylink_destroy(struct phylink *pl)
+ {
+-	if (pl->sfp_bus)
+-		sfp_unregister_upstream(pl->sfp_bus);
++	sfp_bus_del_upstream(pl->sfp_bus);
+ 	if (pl->link_gpio)
+ 		gpiod_put(pl->link_gpio);
+ 
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -404,10 +404,19 @@ static void sfp_bus_release(struct kref
+ 	kfree(bus);
+ }
+ 
+-static void sfp_bus_put(struct sfp_bus *bus)
++/**
++ * sfp_bus_put() - put a reference on the &struct sfp_bus
++ * bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
++ *
++ * Put a reference on the &struct sfp_bus and free the underlying structure
++ * if this was the last reference.
++ */
++void sfp_bus_put(struct sfp_bus *bus)
+ {
+-	kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex);
++	if (bus)
++		kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex);
+ }
++EXPORT_SYMBOL_GPL(sfp_bus_put);
+ 
+ static int sfp_register_bus(struct sfp_bus *bus)
+ {
+@@ -423,11 +432,11 @@ static int sfp_register_bus(struct sfp_b
+ 				return ret;
+ 		}
+ 	}
++	bus->registered = true;
+ 	bus->socket_ops->attach(bus->sfp);
+ 	if (bus->started)
+ 		bus->socket_ops->start(bus->sfp);
+ 	bus->upstream_ops->attach(bus->upstream, bus);
+-	bus->registered = true;
+ 	return 0;
+ }
+ 
+@@ -521,13 +530,12 @@ static void sfp_upstream_clear(struct sf
+ }
+ 
+ /**
+- * sfp_register_upstream_node() - parse and register the neighbouring device
++ * sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode
+  * @fwnode: firmware node for the parent device (MAC or PHY)
+- * @upstream: the upstream private data
+- * @ops: the upstream's &struct sfp_upstream_ops
+  *
+- * Parse the parent device's firmware node for a SFP bus, and register the
+- * SFP bus using sfp_register_upstream().
++ * Parse the parent device's firmware node for a SFP bus, and locate
++ * the sfp_bus structure, incrementing its reference count.  This must
++ * be put via sfp_bus_put() when done.
+  *
+  * Returns: on success, a pointer to the sfp_bus structure,
+  *	    %NULL if no SFP is specified,
+@@ -537,9 +545,7 @@ static void sfp_upstream_clear(struct sf
+  * 	        %-ENOMEM if we failed to allocate the bus.
+  *		an error from the upstream's connect_phy() method.
+  */
+-struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
+-					   void *upstream,
+-					   const struct sfp_upstream_ops *ops)
++struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
+ {
+ 	struct fwnode_reference_args ref;
+ 	struct sfp_bus *bus;
+@@ -562,7 +568,39 @@ struct sfp_bus *sfp_register_upstream_no
+ 	if (!bus)
+ 		return ERR_PTR(-ENOMEM);
+ 
++	return bus;
++}
++EXPORT_SYMBOL_GPL(sfp_bus_find_fwnode);
++
++/**
++ * sfp_bus_add_upstream() - parse and register the neighbouring device
++ * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
++ * @upstream: the upstream private data
++ * @ops: the upstream's &struct sfp_upstream_ops
++ *
++ * Add upstream driver for the SFP bus, and if the bus is complete, register
++ * the SFP bus using sfp_register_upstream().  This takes a reference on the
++ * bus, so it is safe to put the bus after this call.
++ *
++ * Returns: on success, a pointer to the sfp_bus structure,
++ *	    %NULL if no SFP is specified,
++ * 	    on failure, an error pointer value:
++ * 		corresponding to the errors detailed for
++ * 		fwnode_property_get_reference_args().
++ * 	        %-ENOMEM if we failed to allocate the bus.
++ *		an error from the upstream's connect_phy() method.
++ */
++int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
++			 const struct sfp_upstream_ops *ops)
++{
++	int ret;
++
++	/* If no bus, return success */
++	if (!bus)
++		return 0;
++
+ 	rtnl_lock();
++	kref_get(&bus->kref);
+ 	bus->upstream_ops = ops;
+ 	bus->upstream = upstream;
+ 
+@@ -575,33 +613,33 @@ struct sfp_bus *sfp_register_upstream_no
+ 	}
+ 	rtnl_unlock();
+ 
+-	if (ret) {
++	if (ret)
+ 		sfp_bus_put(bus);
+-		bus = ERR_PTR(ret);
+-	}
+ 
+-	return bus;
++	return ret;
+ }
+-EXPORT_SYMBOL_GPL(sfp_register_upstream_node);
++EXPORT_SYMBOL_GPL(sfp_bus_add_upstream);
+ 
+ /**
+- * sfp_unregister_upstream() - Unregister sfp bus
++ * sfp_bus_del_upstream() - Delete a sfp bus
+  * @bus: a pointer to the &struct sfp_bus structure for the sfp module
+  *
+- * Unregister a previously registered upstream connection for the SFP
+- * module. @bus is returned from sfp_register_upstream().
++ * Delete a previously registered upstream connection for the SFP
++ * module. @bus should have been added by sfp_bus_add_upstream().
+  */
+-void sfp_unregister_upstream(struct sfp_bus *bus)
++void sfp_bus_del_upstream(struct sfp_bus *bus)
+ {
+-	rtnl_lock();
+-	if (bus->sfp)
+-		sfp_unregister_bus(bus);
+-	sfp_upstream_clear(bus);
+-	rtnl_unlock();
++	if (bus) {
++		rtnl_lock();
++		if (bus->sfp)
++			sfp_unregister_bus(bus);
++		sfp_upstream_clear(bus);
++		rtnl_unlock();
+ 
+-	sfp_bus_put(bus);
++		sfp_bus_put(bus);
++	}
+ }
+-EXPORT_SYMBOL_GPL(sfp_unregister_upstream);
++EXPORT_SYMBOL_GPL(sfp_bus_del_upstream);
+ 
+ /* Socket driver entry points */
+ int sfp_add_phy(struct sfp_bus *bus, struct phy_device *phydev)
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -508,10 +508,11 @@ int sfp_get_module_eeprom(struct sfp_bus
+ 			  u8 *data);
+ void sfp_upstream_start(struct sfp_bus *bus);
+ void sfp_upstream_stop(struct sfp_bus *bus);
+-struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
+-					   void *upstream,
+-					   const struct sfp_upstream_ops *ops);
+-void sfp_unregister_upstream(struct sfp_bus *bus);
++void sfp_bus_put(struct sfp_bus *bus);
++struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode);
++int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
++			 const struct sfp_upstream_ops *ops);
++void sfp_bus_del_upstream(struct sfp_bus *bus);
+ #else
+ static inline int sfp_parse_port(struct sfp_bus *bus,
+ 				 const struct sfp_eeprom_id *id,
+@@ -553,14 +554,22 @@ static inline void sfp_upstream_stop(str
+ {
+ }
+ 
+-static inline struct sfp_bus *sfp_register_upstream_node(
+-	struct fwnode_handle *fwnode, void *upstream,
+-	const struct sfp_upstream_ops *ops)
++static inline void sfp_bus_put(struct sfp_bus *bus)
++{
++}
++
++static inline struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
+ {
+ 	return NULL;
+ }
+ 
+-static inline void sfp_unregister_upstream(struct sfp_bus *bus)
++static int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
++				const struct sfp_upstream_ops *ops)
++{
++	return 0;
++}
++
++static inline void sfp_bus_del_upstream(struct sfp_bus *bus)
+ {
+ }
+ #endif