// 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,
};
/* 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(sizeof(*mcli), GFP_KERNEL);
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) {
if (mcli->client)
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