net: dsa: tag_sja1105: convert to tagger-owned data
authorVladimir Oltean <vladimir.oltean@nxp.com>
Thu, 9 Dec 2021 23:34:44 +0000 (01:34 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sun, 12 Dec 2021 12:51:33 +0000 (12:51 +0000)
Currently, struct sja1105_tagger_data is a part of struct
sja1105_private, and is used by the sja1105 driver to populate dp->priv.

With the movement towards tagger-owned storage, the sja1105 driver
should not be the owner of this memory.

This change implements the connection between the sja1105 switch driver
and its tagging protocol, which means that sja1105_tagger_data no longer
stays in dp->priv but in ds->tagger_data, and that the sja1105 driver
now only populates the sja1105_port_deferred_xmit callback pointer.
The kthread worker is now the responsibility of the tagger.

The sja1105 driver also alters the tagger's state some more, especially
with regard to the PTP RX timestamping state. This will be fixed up a
bit in further changes.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/sja1105/sja1105.h
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/dsa/sja1105/sja1105_ptp.c
include/linux/dsa/sja1105.h
net/dsa/tag_sja1105.c

index 850a7d3..9ba2ec2 100644 (file)
@@ -272,7 +272,6 @@ struct sja1105_private {
        struct mii_bus *mdio_base_tx;
        struct mii_bus *mdio_pcs;
        struct dw_xpcs *xpcs[SJA1105_MAX_NUM_PORTS];
-       struct sja1105_tagger_data tagger_data;
        struct sja1105_ptp_data ptp_data;
        struct sja1105_tas_data tas_data;
 };
index 880f28e..4f5ea5d 100644 (file)
@@ -2705,6 +2705,21 @@ static void sja1105_port_deferred_xmit(struct kthread_work *work)
        kfree(xmit_work);
 }
 
+static int sja1105_connect_tag_protocol(struct dsa_switch *ds,
+                                       enum dsa_tag_protocol proto)
+{
+       struct sja1105_tagger_data *tagger_data;
+
+       switch (proto) {
+       case DSA_TAG_PROTO_SJA1105:
+               tagger_data = sja1105_tagger_data(ds);
+               tagger_data->xmit_work_fn = sja1105_port_deferred_xmit;
+               return 0;
+       default:
+               return -EPROTONOSUPPORT;
+       }
+}
+
 /* The MAXAGE setting belongs to the L2 Forwarding Parameters table,
  * which cannot be reconfigured at runtime. So a switch reset is required.
  */
@@ -3005,38 +3020,6 @@ static int sja1105_port_bridge_flags(struct dsa_switch *ds, int port,
        return 0;
 }
 
-static void sja1105_teardown_ports(struct sja1105_private *priv)
-{
-       struct sja1105_tagger_data *tagger_data = &priv->tagger_data;
-
-       kthread_destroy_worker(tagger_data->xmit_worker);
-}
-
-static int sja1105_setup_ports(struct sja1105_private *priv)
-{
-       struct sja1105_tagger_data *tagger_data = &priv->tagger_data;
-       struct dsa_switch *ds = priv->ds;
-       struct kthread_worker *worker;
-       struct dsa_port *dp;
-
-       worker = kthread_create_worker(0, "dsa%d:%d_xmit", ds->dst->index,
-                                      ds->index);
-       if (IS_ERR(worker)) {
-               dev_err(ds->dev,
-                       "failed to create deferred xmit thread: %pe\n",
-                       worker);
-               return PTR_ERR(worker);
-       }
-
-       tagger_data->xmit_worker = worker;
-       tagger_data->xmit_work_fn = sja1105_port_deferred_xmit;
-
-       dsa_switch_for_each_user_port(dp, ds)
-               dp->priv = tagger_data;
-
-       return 0;
-}
-
 /* The programming model for the SJA1105 switch is "all-at-once" via static
  * configuration tables. Some of these can be dynamically modified at runtime,
  * but not the xMII mode parameters table.
@@ -3082,10 +3065,6 @@ static int sja1105_setup(struct dsa_switch *ds)
                }
        }
 
-       rc = sja1105_setup_ports(priv);
-       if (rc)
-               goto out_static_config_free;
-
        sja1105_tas_setup(ds);
        sja1105_flower_setup(ds);
 
@@ -3142,7 +3121,6 @@ out_ptp_clock_unregister:
 out_flower_teardown:
        sja1105_flower_teardown(ds);
        sja1105_tas_teardown(ds);
-       sja1105_teardown_ports(priv);
 out_static_config_free:
        sja1105_static_config_free(&priv->static_config);
 
@@ -3162,12 +3140,12 @@ static void sja1105_teardown(struct dsa_switch *ds)
        sja1105_ptp_clock_unregister(ds);
        sja1105_flower_teardown(ds);
        sja1105_tas_teardown(ds);
-       sja1105_teardown_ports(priv);
        sja1105_static_config_free(&priv->static_config);
 }
 
 static const struct dsa_switch_ops sja1105_switch_ops = {
        .get_tag_protocol       = sja1105_get_tag_protocol,
+       .connect_tag_protocol   = sja1105_connect_tag_protocol,
        .setup                  = sja1105_setup,
        .teardown               = sja1105_teardown,
        .set_ageing_time        = sja1105_set_ageing_time,
index 0904ab1..b34e467 100644 (file)
@@ -58,13 +58,13 @@ enum sja1105_ptp_clk_mode {
 #define ptp_data_to_sja1105(d) \
                container_of((d), struct sja1105_private, ptp_data)
 
-/* Must be called only with priv->tagger_data.state bit
+/* Must be called only with the tagger_data->state bit
  * SJA1105_HWTS_RX_EN cleared
  */
 static int sja1105_change_rxtstamping(struct sja1105_private *priv,
+                                     struct sja1105_tagger_data *tagger_data,
                                      bool on)
 {
-       struct sja1105_tagger_data *tagger_data = &priv->tagger_data;
        struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
        struct sja1105_general_params_entry *general_params;
        struct sja1105_table *table;
@@ -75,9 +75,9 @@ static int sja1105_change_rxtstamping(struct sja1105_private *priv,
        general_params->send_meta0 = on;
 
        /* Initialize the meta state machine to a known state */
-       if (priv->tagger_data.stampable_skb) {
-               kfree_skb(priv->tagger_data.stampable_skb);
-               priv->tagger_data.stampable_skb = NULL;
+       if (tagger_data->stampable_skb) {
+               kfree_skb(tagger_data->stampable_skb);
+               tagger_data->stampable_skb = NULL;
        }
        ptp_cancel_worker_sync(ptp_data->clock);
        skb_queue_purge(&tagger_data->skb_txtstamp_queue);
@@ -88,6 +88,7 @@ static int sja1105_change_rxtstamping(struct sja1105_private *priv,
 
 int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr)
 {
+       struct sja1105_tagger_data *tagger_data = sja1105_tagger_data(ds);
        struct sja1105_private *priv = ds->priv;
        struct hwtstamp_config config;
        bool rx_on;
@@ -116,17 +117,17 @@ int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr)
                break;
        }
 
-       if (rx_on != test_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state)) {
-               clear_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state);
+       if (rx_on != test_bit(SJA1105_HWTS_RX_EN, &tagger_data->state)) {
+               clear_bit(SJA1105_HWTS_RX_EN, &tagger_data->state);
 
-               rc = sja1105_change_rxtstamping(priv, rx_on);
+               rc = sja1105_change_rxtstamping(priv, tagger_data, rx_on);
                if (rc < 0) {
                        dev_err(ds->dev,
                                "Failed to change RX timestamping: %d\n", rc);
                        return rc;
                }
                if (rx_on)
-                       set_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state);
+                       set_bit(SJA1105_HWTS_RX_EN, &tagger_data->state);
        }
 
        if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
@@ -136,6 +137,7 @@ int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr)
 
 int sja1105_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr)
 {
+       struct sja1105_tagger_data *tagger_data = sja1105_tagger_data(ds);
        struct sja1105_private *priv = ds->priv;
        struct hwtstamp_config config;
 
@@ -144,7 +146,7 @@ int sja1105_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr)
                config.tx_type = HWTSTAMP_TX_ON;
        else
                config.tx_type = HWTSTAMP_TX_OFF;
-       if (test_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state))
+       if (test_bit(SJA1105_HWTS_RX_EN, &tagger_data->state))
                config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
        else
                config.rx_filter = HWTSTAMP_FILTER_NONE;
@@ -417,10 +419,11 @@ static long sja1105_rxtstamp_work(struct ptp_clock_info *ptp)
 
 bool sja1105_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
 {
+       struct sja1105_tagger_data *tagger_data = sja1105_tagger_data(ds);
        struct sja1105_private *priv = ds->priv;
        struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
 
-       if (!test_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state))
+       if (!test_bit(SJA1105_HWTS_RX_EN, &tagger_data->state))
                return false;
 
        /* We need to read the full PTP clock to reconstruct the Rx
@@ -459,13 +462,11 @@ bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port,
  */
 void sja1110_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
 {
+       struct sja1105_tagger_data *tagger_data = sja1105_tagger_data(ds);
        struct sk_buff *clone = SJA1105_SKB_CB(skb)->clone;
        struct sja1105_private *priv = ds->priv;
-       struct sja1105_tagger_data *tagger_data;
        u8 ts_id;
 
-       tagger_data = &priv->tagger_data;
-
        skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 
        spin_lock(&priv->ts_id_lock);
@@ -897,7 +898,6 @@ static struct ptp_pin_desc sja1105_ptp_pin = {
 int sja1105_ptp_clock_register(struct dsa_switch *ds)
 {
        struct sja1105_private *priv = ds->priv;
-       struct sja1105_tagger_data *tagger_data = &priv->tagger_data;
        struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
 
        ptp_data->caps = (struct ptp_clock_info) {
@@ -919,9 +919,6 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds)
 
        /* Only used on SJA1105 */
        skb_queue_head_init(&ptp_data->skb_rxtstamp_queue);
-       /* Only used on SJA1110 */
-       skb_queue_head_init(&tagger_data->skb_txtstamp_queue);
-       spin_lock_init(&tagger_data->meta_lock);
 
        ptp_data->clock = ptp_clock_register(&ptp_data->caps, ds->dev);
        if (IS_ERR_OR_NULL(ptp_data->clock))
@@ -937,8 +934,8 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds)
 
 void sja1105_ptp_clock_unregister(struct dsa_switch *ds)
 {
+       struct sja1105_tagger_data *tagger_data = sja1105_tagger_data(ds);
        struct sja1105_private *priv = ds->priv;
-       struct sja1105_tagger_data *tagger_data = &priv->tagger_data;
        struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
 
        if (IS_ERR_OR_NULL(ptp_data->clock))
index d8ee530..9f7d42c 100644 (file)
@@ -84,9 +84,12 @@ static inline s64 sja1105_ticks_to_ns(s64 ticks)
        return ticks * SJA1105_TICK_NS;
 }
 
-static inline bool dsa_port_is_sja1105(struct dsa_port *dp)
+static inline struct sja1105_tagger_data *
+sja1105_tagger_data(struct dsa_switch *ds)
 {
-       return true;
+       BUG_ON(ds->dst->tag_ops->proto != DSA_TAG_PROTO_SJA1105);
+
+       return ds->tagger_data;
 }
 
 #endif /* _NET_DSA_SJA1105_H */
index fc2af71..f3c1b31 100644 (file)
@@ -125,7 +125,7 @@ static inline bool sja1105_is_meta_frame(const struct sk_buff *skb)
 static struct sk_buff *sja1105_defer_xmit(struct dsa_port *dp,
                                          struct sk_buff *skb)
 {
-       struct sja1105_tagger_data *tagger_data = dp->priv;
+       struct sja1105_tagger_data *tagger_data = sja1105_tagger_data(dp->ds);
        void (*xmit_work_fn)(struct kthread_work *work);
        struct sja1105_deferred_xmit_work *xmit_work;
        struct kthread_worker *xmit_worker;
@@ -368,10 +368,10 @@ static struct sk_buff
         */
        if (is_link_local) {
                struct dsa_port *dp = dsa_slave_to_port(skb->dev);
-               struct sja1105_tagger_data *tagger_data = dp->priv;
+               struct sja1105_tagger_data *tagger_data;
+               struct dsa_switch *ds = dp->ds;
 
-               if (unlikely(!dsa_port_is_sja1105(dp)))
-                       return skb;
+               tagger_data = sja1105_tagger_data(ds);
 
                if (!test_bit(SJA1105_HWTS_RX_EN, &tagger_data->state))
                        /* Do normal processing. */
@@ -382,7 +382,7 @@ static struct sk_buff
                 * that we were expecting?
                 */
                if (tagger_data->stampable_skb) {
-                       dev_err_ratelimited(dp->ds->dev,
+                       dev_err_ratelimited(ds->dev,
                                            "Expected meta frame, is %12llx "
                                            "in the DSA master multicast filter?\n",
                                            SJA1105_META_DMAC);
@@ -406,11 +406,11 @@ static struct sk_buff
         */
        } else if (is_meta) {
                struct dsa_port *dp = dsa_slave_to_port(skb->dev);
-               struct sja1105_tagger_data *tagger_data = dp->priv;
+               struct sja1105_tagger_data *tagger_data;
+               struct dsa_switch *ds = dp->ds;
                struct sk_buff *stampable_skb;
 
-               if (unlikely(!dsa_port_is_sja1105(dp)))
-                       return skb;
+               tagger_data = sja1105_tagger_data(ds);
 
                /* Drop the meta frame if we're not in the right state
                 * to process it.
@@ -427,14 +427,14 @@ static struct sk_buff
                 * that we were expecting?
                 */
                if (!stampable_skb) {
-                       dev_err_ratelimited(dp->ds->dev,
+                       dev_err_ratelimited(ds->dev,
                                            "Unexpected meta frame\n");
                        spin_unlock(&tagger_data->meta_lock);
                        return NULL;
                }
 
                if (stampable_skb->dev != skb->dev) {
-                       dev_err_ratelimited(dp->ds->dev,
+                       dev_err_ratelimited(ds->dev,
                                            "Meta frame on wrong port\n");
                        spin_unlock(&tagger_data->meta_lock);
                        return NULL;
@@ -543,20 +543,14 @@ static void sja1110_process_meta_tstamp(struct dsa_switch *ds, int port,
                                        u8 ts_id, enum sja1110_meta_tstamp dir,
                                        u64 tstamp)
 {
+       struct sja1105_tagger_data *tagger_data = sja1105_tagger_data(ds);
        struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
-       struct dsa_port *dp = dsa_to_port(ds, port);
-       struct sja1105_tagger_data *tagger_data;
        struct skb_shared_hwtstamps shwt = {0};
 
-       if (!dsa_port_is_sja1105(dp))
-               return;
-
        /* We don't care about RX timestamps on the CPU port */
        if (dir == SJA1110_META_TSTAMP_RX)
                return;
 
-       tagger_data = dp->priv;
-
        spin_lock(&tagger_data->skb_txtstamp_queue.lock);
 
        skb_queue_walk_safe(&tagger_data->skb_txtstamp_queue, skb, skb_tmp) {
@@ -737,11 +731,71 @@ static void sja1110_flow_dissect(const struct sk_buff *skb, __be16 *proto,
        *proto = ((__be16 *)skb->data)[(VLAN_HLEN / 2) - 1];
 }
 
+static void sja1105_disconnect(struct dsa_switch_tree *dst)
+{
+       struct sja1105_tagger_data *tagger_data;
+       struct dsa_port *dp;
+
+       list_for_each_entry(dp, &dst->ports, list) {
+               tagger_data = dp->ds->tagger_data;
+
+               if (!tagger_data)
+                       continue;
+
+               if (tagger_data->xmit_worker)
+                       kthread_destroy_worker(tagger_data->xmit_worker);
+
+               kfree(tagger_data);
+               dp->ds->tagger_data = NULL;
+       }
+}
+
+static int sja1105_connect(struct dsa_switch_tree *dst)
+{
+       struct sja1105_tagger_data *tagger_data;
+       struct kthread_worker *xmit_worker;
+       struct dsa_port *dp;
+       int err;
+
+       list_for_each_entry(dp, &dst->ports, list) {
+               if (dp->ds->tagger_data)
+                       continue;
+
+               tagger_data = kzalloc(sizeof(*tagger_data), GFP_KERNEL);
+               if (!tagger_data) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               /* Only used on SJA1110 */
+               skb_queue_head_init(&tagger_data->skb_txtstamp_queue);
+               spin_lock_init(&tagger_data->meta_lock);
+
+               xmit_worker = kthread_create_worker(0, "dsa%d:%d_xmit",
+                                                   dst->index, dp->ds->index);
+               if (IS_ERR(xmit_worker)) {
+                       err = PTR_ERR(xmit_worker);
+                       goto out;
+               }
+
+               tagger_data->xmit_worker = xmit_worker;
+               dp->ds->tagger_data = tagger_data;
+       }
+
+       return 0;
+
+out:
+       sja1105_disconnect(dst);
+       return err;
+}
+
 static const struct dsa_device_ops sja1105_netdev_ops = {
        .name = "sja1105",
        .proto = DSA_TAG_PROTO_SJA1105,
        .xmit = sja1105_xmit,
        .rcv = sja1105_rcv,
+       .connect = sja1105_connect,
+       .disconnect = sja1105_disconnect,
        .needed_headroom = VLAN_HLEN,
        .flow_dissect = sja1105_flow_dissect,
        .promisc_on_master = true,
@@ -755,6 +809,8 @@ static const struct dsa_device_ops sja1110_netdev_ops = {
        .proto = DSA_TAG_PROTO_SJA1110,
        .xmit = sja1110_xmit,
        .rcv = sja1110_rcv,
+       .connect = sja1105_connect,
+       .disconnect = sja1105_disconnect,
        .flow_dissect = sja1110_flow_dissect,
        .needed_headroom = SJA1110_HEADER_LEN + VLAN_HLEN,
        .needed_tailroom = SJA1110_RX_TRAILER_LEN + SJA1110_MAX_PADDING_LEN,