b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | From 863b5b6941f9f43b924393b6ba2b36647e7dee42 Mon Sep 17 00:00:00 2001 |
| 2 | From: Russell King <rmk+kernel@armlinux.org.uk> |
| 3 | Date: Thu, 7 Nov 2019 17:06:08 +0000 |
| 4 | Subject: [PATCH 615/660] net: sfp: rework upstream interface |
| 5 | |
| 6 | The current upstream interface is an all-or-nothing, which is |
| 7 | sub-optimal for future changes, as it doesn't allow the upstream driver |
| 8 | to prepare for the SFP module becoming available, as it is at boot. |
| 9 | |
| 10 | Switch to a find-sfp-bus, add-upstream, del-upstream, put-sfp-bus |
| 11 | interface structure instead, which allows the upstream driver to |
| 12 | prepare for a module being available as soon as add-upstream is called. |
| 13 | |
| 14 | Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> |
| 15 | --- |
| 16 | drivers/net/phy/phylink.c | 10 +++-- |
| 17 | drivers/net/phy/sfp-bus.c | 92 +++++++++++++++++++++++++++------------ |
| 18 | include/linux/sfp.h | 25 +++++++---- |
| 19 | 3 files changed, 88 insertions(+), 39 deletions(-) |
| 20 | |
| 21 | --- a/drivers/net/phy/phylink.c |
| 22 | +++ b/drivers/net/phy/phylink.c |
| 23 | @@ -568,7 +568,7 @@ static int phylink_register_sfp(struct p |
| 24 | struct sfp_bus *bus; |
| 25 | int ret; |
| 26 | |
| 27 | - bus = sfp_register_upstream_node(fwnode, pl, &sfp_phylink_ops); |
| 28 | + bus = sfp_bus_find_fwnode(fwnode); |
| 29 | if (IS_ERR(bus)) { |
| 30 | ret = PTR_ERR(bus); |
| 31 | phylink_err(pl, "unable to attach SFP bus: %d\n", ret); |
| 32 | @@ -577,7 +577,10 @@ static int phylink_register_sfp(struct p |
| 33 | |
| 34 | pl->sfp_bus = bus; |
| 35 | |
| 36 | - return 0; |
| 37 | + ret = sfp_bus_add_upstream(bus, pl, &sfp_phylink_ops); |
| 38 | + sfp_bus_put(bus); |
| 39 | + |
| 40 | + return ret; |
| 41 | } |
| 42 | |
| 43 | /** |
| 44 | @@ -675,8 +678,7 @@ EXPORT_SYMBOL_GPL(phylink_create); |
| 45 | */ |
| 46 | void phylink_destroy(struct phylink *pl) |
| 47 | { |
| 48 | - if (pl->sfp_bus) |
| 49 | - sfp_unregister_upstream(pl->sfp_bus); |
| 50 | + sfp_bus_del_upstream(pl->sfp_bus); |
| 51 | if (pl->link_gpio) |
| 52 | gpiod_put(pl->link_gpio); |
| 53 | |
| 54 | --- a/drivers/net/phy/sfp-bus.c |
| 55 | +++ b/drivers/net/phy/sfp-bus.c |
| 56 | @@ -404,10 +404,19 @@ static void sfp_bus_release(struct kref |
| 57 | kfree(bus); |
| 58 | } |
| 59 | |
| 60 | -static void sfp_bus_put(struct sfp_bus *bus) |
| 61 | +/** |
| 62 | + * sfp_bus_put() - put a reference on the &struct sfp_bus |
| 63 | + * bus: the &struct sfp_bus found via sfp_bus_find_fwnode() |
| 64 | + * |
| 65 | + * Put a reference on the &struct sfp_bus and free the underlying structure |
| 66 | + * if this was the last reference. |
| 67 | + */ |
| 68 | +void sfp_bus_put(struct sfp_bus *bus) |
| 69 | { |
| 70 | - kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex); |
| 71 | + if (bus) |
| 72 | + kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex); |
| 73 | } |
| 74 | +EXPORT_SYMBOL_GPL(sfp_bus_put); |
| 75 | |
| 76 | static int sfp_register_bus(struct sfp_bus *bus) |
| 77 | { |
| 78 | @@ -423,11 +432,11 @@ static int sfp_register_bus(struct sfp_b |
| 79 | return ret; |
| 80 | } |
| 81 | } |
| 82 | + bus->registered = true; |
| 83 | bus->socket_ops->attach(bus->sfp); |
| 84 | if (bus->started) |
| 85 | bus->socket_ops->start(bus->sfp); |
| 86 | bus->upstream_ops->attach(bus->upstream, bus); |
| 87 | - bus->registered = true; |
| 88 | return 0; |
| 89 | } |
| 90 | |
| 91 | @@ -521,13 +530,12 @@ static void sfp_upstream_clear(struct sf |
| 92 | } |
| 93 | |
| 94 | /** |
| 95 | - * sfp_register_upstream_node() - parse and register the neighbouring device |
| 96 | + * sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode |
| 97 | * @fwnode: firmware node for the parent device (MAC or PHY) |
| 98 | - * @upstream: the upstream private data |
| 99 | - * @ops: the upstream's &struct sfp_upstream_ops |
| 100 | * |
| 101 | - * Parse the parent device's firmware node for a SFP bus, and register the |
| 102 | - * SFP bus using sfp_register_upstream(). |
| 103 | + * Parse the parent device's firmware node for a SFP bus, and locate |
| 104 | + * the sfp_bus structure, incrementing its reference count. This must |
| 105 | + * be put via sfp_bus_put() when done. |
| 106 | * |
| 107 | * Returns: on success, a pointer to the sfp_bus structure, |
| 108 | * %NULL if no SFP is specified, |
| 109 | @@ -537,9 +545,7 @@ static void sfp_upstream_clear(struct sf |
| 110 | * %-ENOMEM if we failed to allocate the bus. |
| 111 | * an error from the upstream's connect_phy() method. |
| 112 | */ |
| 113 | -struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode, |
| 114 | - void *upstream, |
| 115 | - const struct sfp_upstream_ops *ops) |
| 116 | +struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode) |
| 117 | { |
| 118 | struct fwnode_reference_args ref; |
| 119 | struct sfp_bus *bus; |
| 120 | @@ -562,7 +568,39 @@ struct sfp_bus *sfp_register_upstream_no |
| 121 | if (!bus) |
| 122 | return ERR_PTR(-ENOMEM); |
| 123 | |
| 124 | + return bus; |
| 125 | +} |
| 126 | +EXPORT_SYMBOL_GPL(sfp_bus_find_fwnode); |
| 127 | + |
| 128 | +/** |
| 129 | + * sfp_bus_add_upstream() - parse and register the neighbouring device |
| 130 | + * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode() |
| 131 | + * @upstream: the upstream private data |
| 132 | + * @ops: the upstream's &struct sfp_upstream_ops |
| 133 | + * |
| 134 | + * Add upstream driver for the SFP bus, and if the bus is complete, register |
| 135 | + * the SFP bus using sfp_register_upstream(). This takes a reference on the |
| 136 | + * bus, so it is safe to put the bus after this call. |
| 137 | + * |
| 138 | + * Returns: on success, a pointer to the sfp_bus structure, |
| 139 | + * %NULL if no SFP is specified, |
| 140 | + * on failure, an error pointer value: |
| 141 | + * corresponding to the errors detailed for |
| 142 | + * fwnode_property_get_reference_args(). |
| 143 | + * %-ENOMEM if we failed to allocate the bus. |
| 144 | + * an error from the upstream's connect_phy() method. |
| 145 | + */ |
| 146 | +int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream, |
| 147 | + const struct sfp_upstream_ops *ops) |
| 148 | +{ |
| 149 | + int ret; |
| 150 | + |
| 151 | + /* If no bus, return success */ |
| 152 | + if (!bus) |
| 153 | + return 0; |
| 154 | + |
| 155 | rtnl_lock(); |
| 156 | + kref_get(&bus->kref); |
| 157 | bus->upstream_ops = ops; |
| 158 | bus->upstream = upstream; |
| 159 | |
| 160 | @@ -575,33 +613,33 @@ struct sfp_bus *sfp_register_upstream_no |
| 161 | } |
| 162 | rtnl_unlock(); |
| 163 | |
| 164 | - if (ret) { |
| 165 | + if (ret) |
| 166 | sfp_bus_put(bus); |
| 167 | - bus = ERR_PTR(ret); |
| 168 | - } |
| 169 | |
| 170 | - return bus; |
| 171 | + return ret; |
| 172 | } |
| 173 | -EXPORT_SYMBOL_GPL(sfp_register_upstream_node); |
| 174 | +EXPORT_SYMBOL_GPL(sfp_bus_add_upstream); |
| 175 | |
| 176 | /** |
| 177 | - * sfp_unregister_upstream() - Unregister sfp bus |
| 178 | + * sfp_bus_del_upstream() - Delete a sfp bus |
| 179 | * @bus: a pointer to the &struct sfp_bus structure for the sfp module |
| 180 | * |
| 181 | - * Unregister a previously registered upstream connection for the SFP |
| 182 | - * module. @bus is returned from sfp_register_upstream(). |
| 183 | + * Delete a previously registered upstream connection for the SFP |
| 184 | + * module. @bus should have been added by sfp_bus_add_upstream(). |
| 185 | */ |
| 186 | -void sfp_unregister_upstream(struct sfp_bus *bus) |
| 187 | +void sfp_bus_del_upstream(struct sfp_bus *bus) |
| 188 | { |
| 189 | - rtnl_lock(); |
| 190 | - if (bus->sfp) |
| 191 | - sfp_unregister_bus(bus); |
| 192 | - sfp_upstream_clear(bus); |
| 193 | - rtnl_unlock(); |
| 194 | + if (bus) { |
| 195 | + rtnl_lock(); |
| 196 | + if (bus->sfp) |
| 197 | + sfp_unregister_bus(bus); |
| 198 | + sfp_upstream_clear(bus); |
| 199 | + rtnl_unlock(); |
| 200 | |
| 201 | - sfp_bus_put(bus); |
| 202 | + sfp_bus_put(bus); |
| 203 | + } |
| 204 | } |
| 205 | -EXPORT_SYMBOL_GPL(sfp_unregister_upstream); |
| 206 | +EXPORT_SYMBOL_GPL(sfp_bus_del_upstream); |
| 207 | |
| 208 | /* Socket driver entry points */ |
| 209 | int sfp_add_phy(struct sfp_bus *bus, struct phy_device *phydev) |
| 210 | --- a/include/linux/sfp.h |
| 211 | +++ b/include/linux/sfp.h |
| 212 | @@ -508,10 +508,11 @@ int sfp_get_module_eeprom(struct sfp_bus |
| 213 | u8 *data); |
| 214 | void sfp_upstream_start(struct sfp_bus *bus); |
| 215 | void sfp_upstream_stop(struct sfp_bus *bus); |
| 216 | -struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode, |
| 217 | - void *upstream, |
| 218 | - const struct sfp_upstream_ops *ops); |
| 219 | -void sfp_unregister_upstream(struct sfp_bus *bus); |
| 220 | +void sfp_bus_put(struct sfp_bus *bus); |
| 221 | +struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode); |
| 222 | +int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream, |
| 223 | + const struct sfp_upstream_ops *ops); |
| 224 | +void sfp_bus_del_upstream(struct sfp_bus *bus); |
| 225 | #else |
| 226 | static inline int sfp_parse_port(struct sfp_bus *bus, |
| 227 | const struct sfp_eeprom_id *id, |
| 228 | @@ -553,14 +554,22 @@ static inline void sfp_upstream_stop(str |
| 229 | { |
| 230 | } |
| 231 | |
| 232 | -static inline struct sfp_bus *sfp_register_upstream_node( |
| 233 | - struct fwnode_handle *fwnode, void *upstream, |
| 234 | - const struct sfp_upstream_ops *ops) |
| 235 | +static inline void sfp_bus_put(struct sfp_bus *bus) |
| 236 | +{ |
| 237 | +} |
| 238 | + |
| 239 | +static inline struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode) |
| 240 | { |
| 241 | return NULL; |
| 242 | } |
| 243 | |
| 244 | -static inline void sfp_unregister_upstream(struct sfp_bus *bus) |
| 245 | +static int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream, |
| 246 | + const struct sfp_upstream_ops *ops) |
| 247 | +{ |
| 248 | + return 0; |
| 249 | +} |
| 250 | + |
| 251 | +static inline void sfp_bus_del_upstream(struct sfp_bus *bus) |
| 252 | { |
| 253 | } |
| 254 | #endif |