root/drivers/net/mctp/mctp-i2c.c
// SPDX-License-Identifier: GPL-2.0
/*
 * Management Controller Transport Protocol (MCTP)
 * Implements DMTF specification
 * "DSP0237 Management Component Transport Protocol (MCTP) SMBus/I2C
 * Transport Binding"
 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0237_1.2.0.pdf
 *
 * A netdev is created for each I2C bus that handles MCTP. In the case of an I2C
 * mux topology a single I2C client is attached to the root of the mux topology,
 * shared between all mux I2C busses underneath. For non-mux cases an I2C client
 * is attached per netdev.
 *
 * mctp-i2c-controller.yml devicetree binding has further details.
 *
 * Copyright (c) 2022 Code Construct
 * Copyright (c) 2022 Google
 */

#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/if_arp.h>
#include <net/mctp.h>
#include <net/mctpdevice.h>

/* byte_count is limited to u8 */
#define MCTP_I2C_MAXBLOCK 255
/* One byte is taken by source_slave */
#define MCTP_I2C_MAXMTU (MCTP_I2C_MAXBLOCK - 1)
#define MCTP_I2C_MINMTU (64 + 4)
/* Allow space for dest_address, command, byte_count, data, PEC */
#define MCTP_I2C_BUFSZ (3 + MCTP_I2C_MAXBLOCK + 1)
#define MCTP_I2C_MINLEN 8
#define MCTP_I2C_COMMANDCODE 0x0f
#define MCTP_I2C_TX_WORK_LEN 100
/* Sufficient for 64kB at min mtu */
#define MCTP_I2C_TX_QUEUE_LEN 1100

#define MCTP_I2C_OF_PROP "mctp-controller"

enum {
        MCTP_I2C_FLOW_STATE_NEW = 0,
        MCTP_I2C_FLOW_STATE_ACTIVE,
        MCTP_I2C_FLOW_STATE_INVALID,
};

/* List of all struct mctp_i2c_client
 * Lock protects driver_clients and also prevents adding/removing adapters
 * during mctp_i2c_client probe/remove.
 */
static DEFINE_MUTEX(driver_clients_lock);
static LIST_HEAD(driver_clients);

struct mctp_i2c_client;

/* The netdev structure. One of these per I2C adapter. */
struct mctp_i2c_dev {
        struct net_device *ndev;
        struct i2c_adapter *adapter;
        struct mctp_i2c_client *client;
        struct list_head list; /* For mctp_i2c_client.devs */

        size_t rx_pos;
        u8 rx_buffer[MCTP_I2C_BUFSZ];
        struct completion rx_done;

        struct task_struct *tx_thread;
        wait_queue_head_t tx_wq;
        struct sk_buff_head tx_queue;
        u8 tx_scratch[MCTP_I2C_BUFSZ];

        /* A fake entry in our tx queue to perform an unlock operation */
        struct sk_buff unlock_marker;

        /* Spinlock protects i2c_lock_count, release_count, allow_rx */
        spinlock_t lock;
        int i2c_lock_count;
        int release_count;
        /* Indicates that the netif is ready to receive incoming packets */
        bool allow_rx;

};

/* The i2c client structure. One per hardware i2c bus at the top of the
 * mux tree, shared by multiple netdevs
 */
struct mctp_i2c_client {
        struct i2c_client *client;
        u8 lladdr;

        struct mctp_i2c_dev *sel;
        struct list_head devs;
        spinlock_t sel_lock; /* Protects sel and devs */

        struct list_head list; /* For driver_clients */
};

/* Header on the wire. */
struct mctp_i2c_hdr {
        u8 dest_slave;
        u8 command;
        /* Count of bytes following byte_count, excluding PEC */
        u8 byte_count;
        u8 source_slave;
};

static int mctp_i2c_recv(struct mctp_i2c_dev *midev);
static int mctp_i2c_slave_cb(struct i2c_client *client,
                             enum i2c_slave_event event, u8 *val);
static void mctp_i2c_ndo_uninit(struct net_device *dev);
static int mctp_i2c_ndo_open(struct net_device *dev);

static struct i2c_adapter *mux_root_adapter(struct i2c_adapter *adap)
{
#if IS_ENABLED(CONFIG_I2C_MUX)
        return i2c_root_adapter(&adap->dev);
#else
        /* In non-mux config all i2c adapters are root adapters */
        return adap;
#endif
}

/* Creates a new i2c slave device attached to the root adapter.
 * Sets up the slave callback.
 * Must be called with a client on a root adapter.
 */
static struct mctp_i2c_client *mctp_i2c_new_client(struct i2c_client *client)
{
        struct mctp_i2c_client *mcli = NULL;
        struct i2c_adapter *root = NULL;
        int rc;

        if (client->flags & I2C_CLIENT_TEN) {
                dev_err(&client->dev, "failed, MCTP requires a 7-bit I2C address, addr=0x%x\n",
                        client->addr);
                rc = -EINVAL;
                goto err;
        }

        root = mux_root_adapter(client->adapter);
        if (!root) {
                dev_err(&client->dev, "failed to find root adapter\n");
                rc = -ENOENT;
                goto err;
        }
        if (root != client->adapter) {
                dev_err(&client->dev,
                        "A mctp-i2c-controller client cannot be placed on an I2C mux adapter.\n"
                        " It should be placed on the mux tree root adapter\n"
                        " then set mctp-controller property on adapters to attach\n");
                rc = -EINVAL;
                goto err;
        }

        mcli = kzalloc_obj(*mcli);
        if (!mcli) {
                rc = -ENOMEM;
                goto err;
        }
        spin_lock_init(&mcli->sel_lock);
        INIT_LIST_HEAD(&mcli->devs);
        INIT_LIST_HEAD(&mcli->list);
        mcli->lladdr = client->addr & 0xff;
        mcli->client = client;
        i2c_set_clientdata(client, mcli);

        rc = i2c_slave_register(mcli->client, mctp_i2c_slave_cb);
        if (rc < 0) {
                dev_err(&client->dev, "i2c register failed %d\n", rc);
                mcli->client = NULL;
                i2c_set_clientdata(client, NULL);
                goto err;
        }

        return mcli;
err:
        if (mcli) {
                i2c_unregister_device(mcli->client);
                kfree(mcli);
        }
        return ERR_PTR(rc);
}

static void mctp_i2c_free_client(struct mctp_i2c_client *mcli)
{
        int rc;

        WARN_ON(!mutex_is_locked(&driver_clients_lock));
        WARN_ON(!list_empty(&mcli->devs));
        WARN_ON(mcli->sel); /* sanity check, no locking */

        rc = i2c_slave_unregister(mcli->client);
        /* Leak if it fails, we can't propagate errors upwards */
        if (rc < 0)
                dev_err(&mcli->client->dev, "i2c unregister failed %d\n", rc);
        else
                kfree(mcli);
}

/* Switch the mctp i2c device to receive responses.
 * Call with sel_lock held
 */
static void __mctp_i2c_device_select(struct mctp_i2c_client *mcli,
                                     struct mctp_i2c_dev *midev)
{
        assert_spin_locked(&mcli->sel_lock);
        if (midev)
                dev_hold(midev->ndev);
        if (mcli->sel)
                dev_put(mcli->sel->ndev);
        mcli->sel = midev;
}

/* Switch the mctp i2c device to receive responses */
static void mctp_i2c_device_select(struct mctp_i2c_client *mcli,
                                   struct mctp_i2c_dev *midev)
{
        unsigned long flags;

        spin_lock_irqsave(&mcli->sel_lock, flags);
        __mctp_i2c_device_select(mcli, midev);
        spin_unlock_irqrestore(&mcli->sel_lock, flags);
}

static int mctp_i2c_slave_cb(struct i2c_client *client,
                             enum i2c_slave_event event, u8 *val)
{
        struct mctp_i2c_client *mcli = i2c_get_clientdata(client);
        struct mctp_i2c_dev *midev = NULL;
        unsigned long flags;
        int rc = 0;

        spin_lock_irqsave(&mcli->sel_lock, flags);
        midev = mcli->sel;
        if (midev)
                dev_hold(midev->ndev);
        spin_unlock_irqrestore(&mcli->sel_lock, flags);

        if (!midev)
                return 0;

        switch (event) {
        case I2C_SLAVE_READ_REQUESTED:
        case I2C_SLAVE_READ_PROCESSED:
                /* MCTP I2C transport only uses writes */
                midev->rx_pos = 0;
                *val = 0xff;
                break;
        case I2C_SLAVE_WRITE_RECEIVED:
                if (midev->rx_pos < MCTP_I2C_BUFSZ) {
                        midev->rx_buffer[midev->rx_pos] = *val;
                        midev->rx_pos++;
                } else {
                        midev->ndev->stats.rx_over_errors++;
                }

                break;
        case I2C_SLAVE_WRITE_REQUESTED:
                /* dest_slave as first byte */
                midev->rx_buffer[0] = mcli->lladdr << 1;
                midev->rx_pos = 1;
                break;
        case I2C_SLAVE_STOP:
                rc = mctp_i2c_recv(midev);
                break;
        default:
                break;
        }

        dev_put(midev->ndev);
        return rc;
}

/* Processes incoming data that has been accumulated by the slave cb */
static int mctp_i2c_recv(struct mctp_i2c_dev *midev)
{
        struct net_device *ndev = midev->ndev;
        struct mctp_i2c_hdr *hdr;
        struct mctp_skb_cb *cb;
        struct sk_buff *skb;
        unsigned long flags;
        u8 pec, calc_pec;
        size_t recvlen;
        int status;

        if (midev->rx_pos == 0)
                return 0;

        /* + 1 for the PEC */
        if (midev->rx_pos < MCTP_I2C_MINLEN + 1) {
                ndev->stats.rx_length_errors++;
                return -EINVAL;
        }
        /* recvlen excludes PEC */
        recvlen = midev->rx_pos - 1;

        hdr = (void *)midev->rx_buffer;
        if (hdr->command != MCTP_I2C_COMMANDCODE) {
                ndev->stats.rx_dropped++;
                return -EINVAL;
        }

        if (hdr->byte_count + offsetof(struct mctp_i2c_hdr, source_slave) != recvlen) {
                ndev->stats.rx_length_errors++;
                return -EINVAL;
        }

        pec = midev->rx_buffer[midev->rx_pos - 1];
        calc_pec = i2c_smbus_pec(0, midev->rx_buffer, recvlen);
        if (pec != calc_pec) {
                ndev->stats.rx_crc_errors++;
                return -EINVAL;
        }

        skb = netdev_alloc_skb(ndev, recvlen);
        if (!skb) {
                ndev->stats.rx_dropped++;
                return -ENOMEM;
        }

        skb->protocol = htons(ETH_P_MCTP);
        skb_put_data(skb, midev->rx_buffer, recvlen);
        skb_reset_mac_header(skb);
        skb_pull(skb, sizeof(struct mctp_i2c_hdr));
        skb_reset_network_header(skb);

        cb = __mctp_cb(skb);
        cb->halen = 1;
        cb->haddr[0] = hdr->source_slave >> 1;

        /* We need to ensure that the netif is not used once netdev
         * unregister occurs
         */
        spin_lock_irqsave(&midev->lock, flags);
        if (midev->allow_rx) {
                reinit_completion(&midev->rx_done);
                spin_unlock_irqrestore(&midev->lock, flags);

                status = netif_rx(skb);
                complete(&midev->rx_done);
        } else {
                status = NET_RX_DROP;
                spin_unlock_irqrestore(&midev->lock, flags);
                kfree_skb(skb);
        }

        if (status == NET_RX_SUCCESS) {
                ndev->stats.rx_packets++;
                ndev->stats.rx_bytes += recvlen;
        } else {
                ndev->stats.rx_dropped++;
        }
        return 0;
}

enum mctp_i2c_flow_state {
        MCTP_I2C_TX_FLOW_INVALID,
        MCTP_I2C_TX_FLOW_NONE,
        MCTP_I2C_TX_FLOW_NEW,
        MCTP_I2C_TX_FLOW_EXISTING,
};

static enum mctp_i2c_flow_state
mctp_i2c_get_tx_flow_state(struct mctp_i2c_dev *midev, struct sk_buff *skb)
{
        enum mctp_i2c_flow_state state;
        struct mctp_sk_key *key;
        struct mctp_flow *flow;
        unsigned long flags;

        flow = skb_ext_find(skb, SKB_EXT_MCTP);
        if (!flow)
                return MCTP_I2C_TX_FLOW_NONE;

        key = flow->key;
        if (!key)
                return MCTP_I2C_TX_FLOW_NONE;

        spin_lock_irqsave(&key->lock, flags);
        /* If the key is present but invalid, we're unlikely to be able
         * to handle the flow at all; just drop now
         */
        if (!key->valid) {
                state = MCTP_I2C_TX_FLOW_INVALID;
        } else {
                switch (key->dev_flow_state) {
                case MCTP_I2C_FLOW_STATE_NEW:
                        key->dev_flow_state = MCTP_I2C_FLOW_STATE_ACTIVE;
                        state = MCTP_I2C_TX_FLOW_NEW;
                        break;
                case MCTP_I2C_FLOW_STATE_ACTIVE:
                        state = MCTP_I2C_TX_FLOW_EXISTING;
                        break;
                default:
                        state = MCTP_I2C_TX_FLOW_INVALID;
                }
        }

        spin_unlock_irqrestore(&key->lock, flags);

        return state;
}

/* We're not contending with ourselves here; we only need to exclude other
 * i2c clients from using the bus. refcounts are simply to prevent
 * recursive locking.
 */
static void mctp_i2c_lock_nest(struct mctp_i2c_dev *midev)
{
        unsigned long flags;
        bool lock;

        spin_lock_irqsave(&midev->lock, flags);
        lock = midev->i2c_lock_count == 0;
        midev->i2c_lock_count++;
        spin_unlock_irqrestore(&midev->lock, flags);

        if (lock)
                i2c_lock_bus(midev->adapter, I2C_LOCK_SEGMENT);
}

static void mctp_i2c_unlock_nest(struct mctp_i2c_dev *midev)
{
        unsigned long flags;
        bool unlock;

        spin_lock_irqsave(&midev->lock, flags);
        if (!WARN_ONCE(midev->i2c_lock_count == 0, "lock count underflow!"))
                midev->i2c_lock_count--;
        unlock = midev->i2c_lock_count == 0;
        spin_unlock_irqrestore(&midev->lock, flags);

        if (unlock)
                i2c_unlock_bus(midev->adapter, I2C_LOCK_SEGMENT);
}

/* Unlocks the bus if was previously locked, used for cleanup */
static void mctp_i2c_unlock_reset(struct mctp_i2c_dev *midev)
{
        unsigned long flags;
        bool unlock;

        spin_lock_irqsave(&midev->lock, flags);
        unlock = midev->i2c_lock_count > 0;
        midev->i2c_lock_count = 0;
        spin_unlock_irqrestore(&midev->lock, flags);

        if (unlock)
                i2c_unlock_bus(midev->adapter, I2C_LOCK_SEGMENT);
}

static void mctp_i2c_invalidate_tx_flow(struct mctp_i2c_dev *midev,
                                        struct sk_buff *skb)
{
        struct mctp_sk_key *key;
        struct mctp_flow *flow;
        unsigned long flags;
        bool release;

        flow = skb_ext_find(skb, SKB_EXT_MCTP);
        if (!flow)
                return;

        key = flow->key;
        if (!key)
                return;

        spin_lock_irqsave(&key->lock, flags);
        if (key->manual_alloc) {
                /* we don't have control over lifetimes for manually-allocated
                 * keys, so cannot assume we can invalidate all future flows
                 * that would use this key.
                 */
                release = false;
        } else {
                release = key->dev_flow_state == MCTP_I2C_FLOW_STATE_ACTIVE;
                key->dev_flow_state = MCTP_I2C_FLOW_STATE_INVALID;
        }
        spin_unlock_irqrestore(&key->lock, flags);

        /* if we have changed state from active, the flow held a reference on
         * the lock; release that now.
         */
        if (release)
                mctp_i2c_unlock_nest(midev);
}

static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
{
        struct net_device_stats *stats = &midev->ndev->stats;
        enum mctp_i2c_flow_state fs;
        struct mctp_i2c_hdr *hdr;
        struct i2c_msg msg = {0};
        u8 *pecp;
        int rc;

        fs = mctp_i2c_get_tx_flow_state(midev, skb);

        hdr = (void *)skb_mac_header(skb);
        /* Sanity check that packet contents matches skb length,
         * and can't exceed MCTP_I2C_BUFSZ
         */
        if (skb->len != hdr->byte_count + 3) {
                dev_warn_ratelimited(&midev->adapter->dev,
                                     "Bad tx length %d vs skb %u\n",
                                     hdr->byte_count + 3, skb->len);
                return;
        }

        if (skb_tailroom(skb) >= 1) {
                /* Linear case with space, we can just append the PEC */
                skb_put(skb, 1);
        } else {
                /* Otherwise need to copy the buffer */
                skb_copy_bits(skb, 0, midev->tx_scratch, skb->len);
                hdr = (void *)midev->tx_scratch;
        }

        pecp = (void *)&hdr->source_slave + hdr->byte_count;
        *pecp = i2c_smbus_pec(0, (u8 *)hdr, hdr->byte_count + 3);
        msg.buf = (void *)&hdr->command;
        /* command, bytecount, data, pec */
        msg.len = 2 + hdr->byte_count + 1;
        msg.addr = hdr->dest_slave >> 1;

        switch (fs) {
        case MCTP_I2C_TX_FLOW_NONE:
                /* no flow: full lock & unlock */
                mctp_i2c_lock_nest(midev);
                mctp_i2c_device_select(midev->client, midev);
                rc = __i2c_transfer(midev->adapter, &msg, 1);
                mctp_i2c_unlock_nest(midev);
                break;

        case MCTP_I2C_TX_FLOW_NEW:
                /* new flow: lock, tx, but don't unlock; that will happen
                 * on flow release
                 */
                mctp_i2c_lock_nest(midev);
                mctp_i2c_device_select(midev->client, midev);
                fallthrough;

        case MCTP_I2C_TX_FLOW_EXISTING:
                /* existing flow: we already have the lock; just tx */
                rc = __i2c_transfer(midev->adapter, &msg, 1);

                /* on tx errors, the flow can no longer be considered valid */
                if (rc < 0)
                        mctp_i2c_invalidate_tx_flow(midev, skb);

                break;

        case MCTP_I2C_TX_FLOW_INVALID:
                return;
        }

        if (rc < 0) {
                dev_warn_ratelimited(&midev->adapter->dev,
                                     "__i2c_transfer failed %d\n", rc);
                stats->tx_errors++;
        } else {
                stats->tx_bytes += skb->len;
                stats->tx_packets++;
        }
}

static void mctp_i2c_flow_release(struct mctp_i2c_dev *midev)
{
        unsigned long flags;
        bool unlock;

        spin_lock_irqsave(&midev->lock, flags);
        if (midev->release_count > midev->i2c_lock_count) {
                WARN_ONCE(1, "release count overflow");
                midev->release_count = midev->i2c_lock_count;
        }

        midev->i2c_lock_count -= midev->release_count;
        unlock = midev->i2c_lock_count == 0 && midev->release_count > 0;
        midev->release_count = 0;
        spin_unlock_irqrestore(&midev->lock, flags);

        if (unlock)
                i2c_unlock_bus(midev->adapter, I2C_LOCK_SEGMENT);
}

static int mctp_i2c_header_create(struct sk_buff *skb, struct net_device *dev,
                                  unsigned short type, const void *daddr,
           const void *saddr, unsigned int len)
{
        struct mctp_i2c_hdr *hdr;
        struct mctp_hdr *mhdr;
        u8 lldst, llsrc;
        int rc;

        if (len > MCTP_I2C_MAXMTU)
                return -EMSGSIZE;

        if (!daddr || !saddr)
                return -EINVAL;

        lldst = *((u8 *)daddr);
        llsrc = *((u8 *)saddr);

        rc = skb_cow_head(skb, sizeof(struct mctp_i2c_hdr));
        if (rc)
                return rc;

        skb_push(skb, sizeof(struct mctp_i2c_hdr));
        skb_reset_mac_header(skb);
        hdr = (void *)skb_mac_header(skb);
        mhdr = mctp_hdr(skb);
        hdr->dest_slave = (lldst << 1) & 0xff;
        hdr->command = MCTP_I2C_COMMANDCODE;
        hdr->byte_count = len + 1;
        hdr->source_slave = ((llsrc << 1) & 0xff) | 0x01;
        mhdr->ver = 0x01;

        return sizeof(struct mctp_i2c_hdr);
}

static int mctp_i2c_tx_thread(void *data)
{
        struct mctp_i2c_dev *midev = data;
        struct sk_buff *skb;
        unsigned long flags;

        for (;;) {
                if (kthread_should_stop())
                        break;

                spin_lock_irqsave(&midev->tx_queue.lock, flags);
                skb = __skb_dequeue(&midev->tx_queue);
                if (netif_queue_stopped(midev->ndev))
                        netif_wake_queue(midev->ndev);
                spin_unlock_irqrestore(&midev->tx_queue.lock, flags);

                if (skb == &midev->unlock_marker) {
                        mctp_i2c_flow_release(midev);

                } else if (skb) {
                        mctp_i2c_xmit(midev, skb);
                        kfree_skb(skb);

                } else {
                        wait_event_idle(midev->tx_wq,
                                        !skb_queue_empty(&midev->tx_queue) ||
                                   kthread_should_stop());
                }
        }

        return 0;
}

static netdev_tx_t mctp_i2c_start_xmit(struct sk_buff *skb,
                                       struct net_device *dev)
{
        struct mctp_i2c_dev *midev = netdev_priv(dev);
        unsigned long flags;

        spin_lock_irqsave(&midev->tx_queue.lock, flags);
        if (skb_queue_len(&midev->tx_queue) >= MCTP_I2C_TX_WORK_LEN) {
                netif_stop_queue(dev);
                spin_unlock_irqrestore(&midev->tx_queue.lock, flags);
                netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
                return NETDEV_TX_BUSY;
        }

        __skb_queue_tail(&midev->tx_queue, skb);
        if (skb_queue_len(&midev->tx_queue) == MCTP_I2C_TX_WORK_LEN)
                netif_stop_queue(dev);
        spin_unlock_irqrestore(&midev->tx_queue.lock, flags);

        wake_up(&midev->tx_wq);
        return NETDEV_TX_OK;
}

static void mctp_i2c_release_flow(struct mctp_dev *mdev,
                                  struct mctp_sk_key *key)

{
        struct mctp_i2c_dev *midev = netdev_priv(mdev->dev);
        bool queue_release = false;
        unsigned long flags;

        spin_lock_irqsave(&midev->lock, flags);
        /* if we have seen the flow/key previously, we need to pair the
         * original lock with a release
         */
        if (key->dev_flow_state == MCTP_I2C_FLOW_STATE_ACTIVE) {
                midev->release_count++;
                queue_release = true;
        }
        key->dev_flow_state = MCTP_I2C_FLOW_STATE_INVALID;
        spin_unlock_irqrestore(&midev->lock, flags);

        if (queue_release) {
                /* Ensure we have a release operation queued, through the fake
                 * marker skb
                 */
                spin_lock(&midev->tx_queue.lock);
                if (!midev->unlock_marker.next)
                        __skb_queue_tail(&midev->tx_queue,
                                         &midev->unlock_marker);
                spin_unlock(&midev->tx_queue.lock);
                wake_up(&midev->tx_wq);
        }
}

static const struct net_device_ops mctp_i2c_ops = {
        .ndo_start_xmit = mctp_i2c_start_xmit,
        .ndo_uninit = mctp_i2c_ndo_uninit,
        .ndo_open = mctp_i2c_ndo_open,
};

static const struct header_ops mctp_i2c_headops = {
        .create = mctp_i2c_header_create,
};

static const struct mctp_netdev_ops mctp_i2c_mctp_ops = {
        .release_flow = mctp_i2c_release_flow,
};

static void mctp_i2c_net_setup(struct net_device *dev)
{
        dev->type = ARPHRD_MCTP;

        dev->mtu = MCTP_I2C_MAXMTU;
        dev->min_mtu = MCTP_I2C_MINMTU;
        dev->max_mtu = MCTP_I2C_MAXMTU;
        dev->tx_queue_len = MCTP_I2C_TX_QUEUE_LEN;

        dev->hard_header_len = sizeof(struct mctp_i2c_hdr);
        dev->addr_len = 1;

        dev->netdev_ops         = &mctp_i2c_ops;
        dev->header_ops         = &mctp_i2c_headops;
}

/* Populates the mctp_i2c_dev priv struct for a netdev.
 * Returns an error pointer on failure.
 */
static struct mctp_i2c_dev *mctp_i2c_midev_init(struct net_device *dev,
                                                struct mctp_i2c_client *mcli,
                                                struct i2c_adapter *adap)
{
        struct mctp_i2c_dev *midev = netdev_priv(dev);
        unsigned long flags;

        midev->tx_thread = kthread_create(mctp_i2c_tx_thread, midev,
                                          "%s/tx", dev->name);
        if (IS_ERR(midev->tx_thread))
                return ERR_CAST(midev->tx_thread);

        midev->ndev = dev;
        get_device(&adap->dev);
        midev->adapter = adap;
        get_device(&mcli->client->dev);
        midev->client = mcli;
        INIT_LIST_HEAD(&midev->list);
        spin_lock_init(&midev->lock);
        midev->i2c_lock_count = 0;
        midev->release_count = 0;
        init_completion(&midev->rx_done);
        complete(&midev->rx_done);
        init_waitqueue_head(&midev->tx_wq);
        skb_queue_head_init(&midev->tx_queue);

        /* Add to the parent mcli */
        spin_lock_irqsave(&mcli->sel_lock, flags);
        list_add(&midev->list, &mcli->devs);
        /* Select a device by default */
        if (!mcli->sel)
                __mctp_i2c_device_select(mcli, midev);
        spin_unlock_irqrestore(&mcli->sel_lock, flags);

        /* Start the worker thread */
        wake_up_process(midev->tx_thread);

        return midev;
}

/* Counterpart of mctp_i2c_midev_init */
static void mctp_i2c_midev_free(struct mctp_i2c_dev *midev)
{
        struct mctp_i2c_client *mcli = midev->client;
        unsigned long flags;

        if (midev->tx_thread) {
                kthread_stop(midev->tx_thread);
                midev->tx_thread = NULL;
        }

        /* Unconditionally unlock on close */
        mctp_i2c_unlock_reset(midev);

        /* Remove the netdev from the parent i2c client. */
        spin_lock_irqsave(&mcli->sel_lock, flags);
        list_del(&midev->list);
        if (mcli->sel == midev) {
                struct mctp_i2c_dev *first;

                first = list_first_entry_or_null(&mcli->devs, struct mctp_i2c_dev, list);
                __mctp_i2c_device_select(mcli, first);
        }
        spin_unlock_irqrestore(&mcli->sel_lock, flags);

        skb_queue_purge(&midev->tx_queue);
        put_device(&midev->adapter->dev);
        put_device(&mcli->client->dev);
}

/* Stops, unregisters, and frees midev */
static void mctp_i2c_unregister(struct mctp_i2c_dev *midev)
{
        unsigned long flags;

        /* Stop tx thread prior to unregister, it uses netif_() functions */
        kthread_stop(midev->tx_thread);
        midev->tx_thread = NULL;

        /* Prevent any new rx in mctp_i2c_recv(), let any pending work finish */
        spin_lock_irqsave(&midev->lock, flags);
        midev->allow_rx = false;
        spin_unlock_irqrestore(&midev->lock, flags);
        wait_for_completion(&midev->rx_done);

        mctp_unregister_netdev(midev->ndev);
        /* midev has been freed now by mctp_i2c_ndo_uninit callback */

        free_netdev(midev->ndev);
}

static void mctp_i2c_ndo_uninit(struct net_device *dev)
{
        struct mctp_i2c_dev *midev = netdev_priv(dev);

        /* Perform cleanup here to ensure that mcli->sel isn't holding
         * a reference that would prevent unregister_netdevice()
         * from completing.
         */
        mctp_i2c_midev_free(midev);
}

static int mctp_i2c_ndo_open(struct net_device *dev)
{
        struct mctp_i2c_dev *midev = netdev_priv(dev);
        unsigned long flags;

        /* i2c rx handler can only pass packets once the netdev is registered */
        spin_lock_irqsave(&midev->lock, flags);
        midev->allow_rx = true;
        spin_unlock_irqrestore(&midev->lock, flags);

        return 0;
}

static int mctp_i2c_add_netdev(struct mctp_i2c_client *mcli,
                               struct i2c_adapter *adap)
{
        struct mctp_i2c_dev *midev = NULL;
        struct net_device *ndev = NULL;
        struct i2c_adapter *root;
        unsigned long flags;
        char namebuf[30];
        int rc;

        root = mux_root_adapter(adap);
        if (root != mcli->client->adapter) {
                dev_err(&mcli->client->dev,
                        "I2C adapter %s is not a child bus of %s\n",
                        mcli->client->adapter->name, root->name);
                return -EINVAL;
        }

        WARN_ON(!mutex_is_locked(&driver_clients_lock));
        snprintf(namebuf, sizeof(namebuf), "mctpi2c%d", adap->nr);
        ndev = alloc_netdev(sizeof(*midev), namebuf, NET_NAME_ENUM, mctp_i2c_net_setup);
        if (!ndev) {
                dev_err(&mcli->client->dev, "alloc netdev failed\n");
                rc = -ENOMEM;
                goto err;
        }
        dev_net_set(ndev, current->nsproxy->net_ns);
        SET_NETDEV_DEV(ndev, &adap->dev);
        dev_addr_set(ndev, &mcli->lladdr);

        midev = mctp_i2c_midev_init(ndev, mcli, adap);
        if (IS_ERR(midev)) {
                rc = PTR_ERR(midev);
                midev = NULL;
                goto err;
        }

        rc = mctp_register_netdev(ndev, &mctp_i2c_mctp_ops,
                                  MCTP_PHYS_BINDING_SMBUS);
        if (rc < 0) {
                dev_err(&mcli->client->dev,
                        "register netdev \"%s\" failed %d\n",
                        ndev->name, rc);
                goto err;
        }

        spin_lock_irqsave(&midev->lock, flags);
        midev->allow_rx = false;
        spin_unlock_irqrestore(&midev->lock, flags);

        return 0;
err:
        if (midev)
                mctp_i2c_midev_free(midev);
        if (ndev)
                free_netdev(ndev);
        return rc;
}

/* Removes any netdev for adap. mcli is the parent root i2c client */
static void mctp_i2c_remove_netdev(struct mctp_i2c_client *mcli,
                                   struct i2c_adapter *adap)
{
        struct mctp_i2c_dev *midev = NULL, *m = NULL;
        unsigned long flags;

        WARN_ON(!mutex_is_locked(&driver_clients_lock));
        spin_lock_irqsave(&mcli->sel_lock, flags);
        /* List size is limited by number of MCTP netdevs on a single hardware bus */
        list_for_each_entry(m, &mcli->devs, list)
                if (m->adapter == adap) {
                        midev = m;
                        break;
                }
        spin_unlock_irqrestore(&mcli->sel_lock, flags);

        if (midev)
                mctp_i2c_unregister(midev);
}

/* Determines whether a device is an i2c adapter.
 * Optionally returns the root i2c_adapter
 */
static struct i2c_adapter *mctp_i2c_get_adapter(struct device *dev,
                                                struct i2c_adapter **ret_root)
{
        struct i2c_adapter *root, *adap;

        if (dev->type != &i2c_adapter_type)
                return NULL;
        adap = to_i2c_adapter(dev);
        root = mux_root_adapter(adap);
        WARN_ONCE(!root, "MCTP I2C failed to find root adapter for %s\n",
                  dev_name(dev));
        if (!root)
                return NULL;
        if (ret_root)
                *ret_root = root;
        return adap;
}

/* Determines whether a device is an i2c adapter with the "mctp-controller"
 * devicetree property set. If adap is not an OF node, returns match_no_of
 */
static bool mctp_i2c_adapter_match(struct i2c_adapter *adap, bool match_no_of)
{
        if (!adap->dev.of_node)
                return match_no_of;
        return of_property_read_bool(adap->dev.of_node, MCTP_I2C_OF_PROP);
}

/* Called for each existing i2c device (adapter or client) when a
 * new mctp-i2c client is probed.
 */
static int mctp_i2c_client_try_attach(struct device *dev, void *data)
{
        struct i2c_adapter *adap = NULL, *root = NULL;
        struct mctp_i2c_client *mcli = data;

        adap = mctp_i2c_get_adapter(dev, &root);
        if (!adap)
                return 0;
        if (mcli->client->adapter != root)
                return 0;
        /* Must either have mctp-controller property on the adapter, or
         * be a root adapter if it's non-devicetree
         */
        if (!mctp_i2c_adapter_match(adap, adap == root))
                return 0;

        return mctp_i2c_add_netdev(mcli, adap);
}

static void mctp_i2c_notify_add(struct device *dev)
{
        struct mctp_i2c_client *mcli = NULL, *m = NULL;
        struct i2c_adapter *root = NULL, *adap = NULL;
        int rc;

        adap = mctp_i2c_get_adapter(dev, &root);
        if (!adap)
                return;
        /* Check for mctp-controller property on the adapter */
        if (!mctp_i2c_adapter_match(adap, false))
                return;

        /* Find an existing mcli for adap's root */
        mutex_lock(&driver_clients_lock);
        list_for_each_entry(m, &driver_clients, list) {
                if (m->client->adapter == root) {
                        mcli = m;
                        break;
                }
        }

        if (mcli) {
                rc = mctp_i2c_add_netdev(mcli, adap);
                if (rc < 0)
                        dev_warn(dev, "Failed adding mctp-i2c net device\n");
        }
        mutex_unlock(&driver_clients_lock);
}

static void mctp_i2c_notify_del(struct device *dev)
{
        struct i2c_adapter *root = NULL, *adap = NULL;
        struct mctp_i2c_client *mcli = NULL;

        adap = mctp_i2c_get_adapter(dev, &root);
        if (!adap)
                return;

        mutex_lock(&driver_clients_lock);
        list_for_each_entry(mcli, &driver_clients, list) {
                if (mcli->client->adapter == root) {
                        mctp_i2c_remove_netdev(mcli, adap);
                        break;
                }
        }
        mutex_unlock(&driver_clients_lock);
}

static int mctp_i2c_probe(struct i2c_client *client)
{
        struct mctp_i2c_client *mcli = NULL;
        int rc;

        mutex_lock(&driver_clients_lock);
        mcli = mctp_i2c_new_client(client);
        if (IS_ERR(mcli)) {
                rc = PTR_ERR(mcli);
                mcli = NULL;
                goto out;
        } else {
                list_add(&mcli->list, &driver_clients);
        }

        /* Add a netdev for adapters that have a 'mctp-controller' property */
        i2c_for_each_dev(mcli, mctp_i2c_client_try_attach);
        rc = 0;
out:
        mutex_unlock(&driver_clients_lock);
        return rc;
}

static void mctp_i2c_remove(struct i2c_client *client)
{
        struct mctp_i2c_client *mcli = i2c_get_clientdata(client);
        struct mctp_i2c_dev *midev = NULL, *tmp = NULL;

        mutex_lock(&driver_clients_lock);
        list_del(&mcli->list);
        /* Remove all child adapter netdevs */
        list_for_each_entry_safe(midev, tmp, &mcli->devs, list)
                mctp_i2c_unregister(midev);

        mctp_i2c_free_client(mcli);
        mutex_unlock(&driver_clients_lock);
}

/* We look for a 'mctp-controller' property on I2C busses as they are
 * added/deleted, creating/removing netdevs as required.
 */
static int mctp_i2c_notifier_call(struct notifier_block *nb,
                                  unsigned long action, void *data)
{
        struct device *dev = data;

        switch (action) {
        case BUS_NOTIFY_ADD_DEVICE:
                mctp_i2c_notify_add(dev);
                break;
        case BUS_NOTIFY_DEL_DEVICE:
                mctp_i2c_notify_del(dev);
                break;
        }
        return NOTIFY_DONE;
}

static struct notifier_block mctp_i2c_notifier = {
        .notifier_call = mctp_i2c_notifier_call,
};

static const struct i2c_device_id mctp_i2c_id[] = {
        { "mctp-i2c-interface" },
        {}
};
MODULE_DEVICE_TABLE(i2c, mctp_i2c_id);

static const struct of_device_id mctp_i2c_of_match[] = {
        { .compatible = "mctp-i2c-controller" },
        {},
};
MODULE_DEVICE_TABLE(of, mctp_i2c_of_match);

static struct i2c_driver mctp_i2c_driver = {
        .driver = {
                .name = "mctp-i2c-interface",
                .of_match_table = mctp_i2c_of_match,
        },
        .probe = mctp_i2c_probe,
        .remove = mctp_i2c_remove,
        .id_table = mctp_i2c_id,
};

static __init int mctp_i2c_mod_init(void)
{
        int rc;

        pr_info("MCTP I2C interface driver\n");
        rc = i2c_add_driver(&mctp_i2c_driver);
        if (rc < 0)
                return rc;
        rc = bus_register_notifier(&i2c_bus_type, &mctp_i2c_notifier);
        if (rc < 0) {
                i2c_del_driver(&mctp_i2c_driver);
                return rc;
        }
        return 0;
}

static __exit void mctp_i2c_mod_exit(void)
{
        int rc;

        rc = bus_unregister_notifier(&i2c_bus_type, &mctp_i2c_notifier);
        if (rc < 0)
                pr_warn("MCTP I2C could not unregister notifier, %d\n", rc);
        i2c_del_driver(&mctp_i2c_driver);
}

module_init(mctp_i2c_mod_init);
module_exit(mctp_i2c_mod_exit);

MODULE_DESCRIPTION("MCTP I2C device");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Matt Johnston <matt@codeconstruct.com.au>");