162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Management Controller Transport Protocol (MCTP) 462306a36Sopenharmony_ci * Implements DMTF specification 562306a36Sopenharmony_ci * "DSP0237 Management Component Transport Protocol (MCTP) SMBus/I2C 662306a36Sopenharmony_ci * Transport Binding" 762306a36Sopenharmony_ci * https://www.dmtf.org/sites/default/files/standards/documents/DSP0237_1.2.0.pdf 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * A netdev is created for each I2C bus that handles MCTP. In the case of an I2C 1062306a36Sopenharmony_ci * mux topology a single I2C client is attached to the root of the mux topology, 1162306a36Sopenharmony_ci * shared between all mux I2C busses underneath. For non-mux cases an I2C client 1262306a36Sopenharmony_ci * is attached per netdev. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * mctp-i2c-controller.yml devicetree binding has further details. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Copyright (c) 2022 Code Construct 1762306a36Sopenharmony_ci * Copyright (c) 2022 Google 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/netdevice.h> 2262306a36Sopenharmony_ci#include <linux/i2c.h> 2362306a36Sopenharmony_ci#include <linux/i2c-mux.h> 2462306a36Sopenharmony_ci#include <linux/if_arp.h> 2562306a36Sopenharmony_ci#include <net/mctp.h> 2662306a36Sopenharmony_ci#include <net/mctpdevice.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* byte_count is limited to u8 */ 2962306a36Sopenharmony_ci#define MCTP_I2C_MAXBLOCK 255 3062306a36Sopenharmony_ci/* One byte is taken by source_slave */ 3162306a36Sopenharmony_ci#define MCTP_I2C_MAXMTU (MCTP_I2C_MAXBLOCK - 1) 3262306a36Sopenharmony_ci#define MCTP_I2C_MINMTU (64 + 4) 3362306a36Sopenharmony_ci/* Allow space for dest_address, command, byte_count, data, PEC */ 3462306a36Sopenharmony_ci#define MCTP_I2C_BUFSZ (3 + MCTP_I2C_MAXBLOCK + 1) 3562306a36Sopenharmony_ci#define MCTP_I2C_MINLEN 8 3662306a36Sopenharmony_ci#define MCTP_I2C_COMMANDCODE 0x0f 3762306a36Sopenharmony_ci#define MCTP_I2C_TX_WORK_LEN 100 3862306a36Sopenharmony_ci/* Sufficient for 64kB at min mtu */ 3962306a36Sopenharmony_ci#define MCTP_I2C_TX_QUEUE_LEN 1100 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define MCTP_I2C_OF_PROP "mctp-controller" 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cienum { 4462306a36Sopenharmony_ci MCTP_I2C_FLOW_STATE_NEW = 0, 4562306a36Sopenharmony_ci MCTP_I2C_FLOW_STATE_ACTIVE, 4662306a36Sopenharmony_ci MCTP_I2C_FLOW_STATE_INVALID, 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* List of all struct mctp_i2c_client 5062306a36Sopenharmony_ci * Lock protects driver_clients and also prevents adding/removing adapters 5162306a36Sopenharmony_ci * during mctp_i2c_client probe/remove. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_cistatic DEFINE_MUTEX(driver_clients_lock); 5462306a36Sopenharmony_cistatic LIST_HEAD(driver_clients); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistruct mctp_i2c_client; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* The netdev structure. One of these per I2C adapter. */ 5962306a36Sopenharmony_cistruct mctp_i2c_dev { 6062306a36Sopenharmony_ci struct net_device *ndev; 6162306a36Sopenharmony_ci struct i2c_adapter *adapter; 6262306a36Sopenharmony_ci struct mctp_i2c_client *client; 6362306a36Sopenharmony_ci struct list_head list; /* For mctp_i2c_client.devs */ 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci size_t rx_pos; 6662306a36Sopenharmony_ci u8 rx_buffer[MCTP_I2C_BUFSZ]; 6762306a36Sopenharmony_ci struct completion rx_done; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci struct task_struct *tx_thread; 7062306a36Sopenharmony_ci wait_queue_head_t tx_wq; 7162306a36Sopenharmony_ci struct sk_buff_head tx_queue; 7262306a36Sopenharmony_ci u8 tx_scratch[MCTP_I2C_BUFSZ]; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* A fake entry in our tx queue to perform an unlock operation */ 7562306a36Sopenharmony_ci struct sk_buff unlock_marker; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Spinlock protects i2c_lock_count, release_count, allow_rx */ 7862306a36Sopenharmony_ci spinlock_t lock; 7962306a36Sopenharmony_ci int i2c_lock_count; 8062306a36Sopenharmony_ci int release_count; 8162306a36Sopenharmony_ci /* Indicates that the netif is ready to receive incoming packets */ 8262306a36Sopenharmony_ci bool allow_rx; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* The i2c client structure. One per hardware i2c bus at the top of the 8762306a36Sopenharmony_ci * mux tree, shared by multiple netdevs 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_cistruct mctp_i2c_client { 9062306a36Sopenharmony_ci struct i2c_client *client; 9162306a36Sopenharmony_ci u8 lladdr; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci struct mctp_i2c_dev *sel; 9462306a36Sopenharmony_ci struct list_head devs; 9562306a36Sopenharmony_ci spinlock_t sel_lock; /* Protects sel and devs */ 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci struct list_head list; /* For driver_clients */ 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* Header on the wire. */ 10162306a36Sopenharmony_cistruct mctp_i2c_hdr { 10262306a36Sopenharmony_ci u8 dest_slave; 10362306a36Sopenharmony_ci u8 command; 10462306a36Sopenharmony_ci /* Count of bytes following byte_count, excluding PEC */ 10562306a36Sopenharmony_ci u8 byte_count; 10662306a36Sopenharmony_ci u8 source_slave; 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int mctp_i2c_recv(struct mctp_i2c_dev *midev); 11062306a36Sopenharmony_cistatic int mctp_i2c_slave_cb(struct i2c_client *client, 11162306a36Sopenharmony_ci enum i2c_slave_event event, u8 *val); 11262306a36Sopenharmony_cistatic void mctp_i2c_ndo_uninit(struct net_device *dev); 11362306a36Sopenharmony_cistatic int mctp_i2c_ndo_open(struct net_device *dev); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic struct i2c_adapter *mux_root_adapter(struct i2c_adapter *adap) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_MUX) 11862306a36Sopenharmony_ci return i2c_root_adapter(&adap->dev); 11962306a36Sopenharmony_ci#else 12062306a36Sopenharmony_ci /* In non-mux config all i2c adapters are root adapters */ 12162306a36Sopenharmony_ci return adap; 12262306a36Sopenharmony_ci#endif 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* Creates a new i2c slave device attached to the root adapter. 12662306a36Sopenharmony_ci * Sets up the slave callback. 12762306a36Sopenharmony_ci * Must be called with a client on a root adapter. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_cistatic struct mctp_i2c_client *mctp_i2c_new_client(struct i2c_client *client) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct mctp_i2c_client *mcli = NULL; 13262306a36Sopenharmony_ci struct i2c_adapter *root = NULL; 13362306a36Sopenharmony_ci int rc; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (client->flags & I2C_CLIENT_TEN) { 13662306a36Sopenharmony_ci dev_err(&client->dev, "failed, MCTP requires a 7-bit I2C address, addr=0x%x\n", 13762306a36Sopenharmony_ci client->addr); 13862306a36Sopenharmony_ci rc = -EINVAL; 13962306a36Sopenharmony_ci goto err; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci root = mux_root_adapter(client->adapter); 14362306a36Sopenharmony_ci if (!root) { 14462306a36Sopenharmony_ci dev_err(&client->dev, "failed to find root adapter\n"); 14562306a36Sopenharmony_ci rc = -ENOENT; 14662306a36Sopenharmony_ci goto err; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci if (root != client->adapter) { 14962306a36Sopenharmony_ci dev_err(&client->dev, 15062306a36Sopenharmony_ci "A mctp-i2c-controller client cannot be placed on an I2C mux adapter.\n" 15162306a36Sopenharmony_ci " It should be placed on the mux tree root adapter\n" 15262306a36Sopenharmony_ci " then set mctp-controller property on adapters to attach\n"); 15362306a36Sopenharmony_ci rc = -EINVAL; 15462306a36Sopenharmony_ci goto err; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci mcli = kzalloc(sizeof(*mcli), GFP_KERNEL); 15862306a36Sopenharmony_ci if (!mcli) { 15962306a36Sopenharmony_ci rc = -ENOMEM; 16062306a36Sopenharmony_ci goto err; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci spin_lock_init(&mcli->sel_lock); 16362306a36Sopenharmony_ci INIT_LIST_HEAD(&mcli->devs); 16462306a36Sopenharmony_ci INIT_LIST_HEAD(&mcli->list); 16562306a36Sopenharmony_ci mcli->lladdr = client->addr & 0xff; 16662306a36Sopenharmony_ci mcli->client = client; 16762306a36Sopenharmony_ci i2c_set_clientdata(client, mcli); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci rc = i2c_slave_register(mcli->client, mctp_i2c_slave_cb); 17062306a36Sopenharmony_ci if (rc < 0) { 17162306a36Sopenharmony_ci dev_err(&client->dev, "i2c register failed %d\n", rc); 17262306a36Sopenharmony_ci mcli->client = NULL; 17362306a36Sopenharmony_ci i2c_set_clientdata(client, NULL); 17462306a36Sopenharmony_ci goto err; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return mcli; 17862306a36Sopenharmony_cierr: 17962306a36Sopenharmony_ci if (mcli) { 18062306a36Sopenharmony_ci if (mcli->client) 18162306a36Sopenharmony_ci i2c_unregister_device(mcli->client); 18262306a36Sopenharmony_ci kfree(mcli); 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci return ERR_PTR(rc); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic void mctp_i2c_free_client(struct mctp_i2c_client *mcli) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci int rc; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci WARN_ON(!mutex_is_locked(&driver_clients_lock)); 19262306a36Sopenharmony_ci WARN_ON(!list_empty(&mcli->devs)); 19362306a36Sopenharmony_ci WARN_ON(mcli->sel); /* sanity check, no locking */ 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci rc = i2c_slave_unregister(mcli->client); 19662306a36Sopenharmony_ci /* Leak if it fails, we can't propagate errors upwards */ 19762306a36Sopenharmony_ci if (rc < 0) 19862306a36Sopenharmony_ci dev_err(&mcli->client->dev, "i2c unregister failed %d\n", rc); 19962306a36Sopenharmony_ci else 20062306a36Sopenharmony_ci kfree(mcli); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/* Switch the mctp i2c device to receive responses. 20462306a36Sopenharmony_ci * Call with sel_lock held 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_cistatic void __mctp_i2c_device_select(struct mctp_i2c_client *mcli, 20762306a36Sopenharmony_ci struct mctp_i2c_dev *midev) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci assert_spin_locked(&mcli->sel_lock); 21062306a36Sopenharmony_ci if (midev) 21162306a36Sopenharmony_ci dev_hold(midev->ndev); 21262306a36Sopenharmony_ci if (mcli->sel) 21362306a36Sopenharmony_ci dev_put(mcli->sel->ndev); 21462306a36Sopenharmony_ci mcli->sel = midev; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/* Switch the mctp i2c device to receive responses */ 21862306a36Sopenharmony_cistatic void mctp_i2c_device_select(struct mctp_i2c_client *mcli, 21962306a36Sopenharmony_ci struct mctp_i2c_dev *midev) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci unsigned long flags; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci spin_lock_irqsave(&mcli->sel_lock, flags); 22462306a36Sopenharmony_ci __mctp_i2c_device_select(mcli, midev); 22562306a36Sopenharmony_ci spin_unlock_irqrestore(&mcli->sel_lock, flags); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic int mctp_i2c_slave_cb(struct i2c_client *client, 22962306a36Sopenharmony_ci enum i2c_slave_event event, u8 *val) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci struct mctp_i2c_client *mcli = i2c_get_clientdata(client); 23262306a36Sopenharmony_ci struct mctp_i2c_dev *midev = NULL; 23362306a36Sopenharmony_ci unsigned long flags; 23462306a36Sopenharmony_ci int rc = 0; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci spin_lock_irqsave(&mcli->sel_lock, flags); 23762306a36Sopenharmony_ci midev = mcli->sel; 23862306a36Sopenharmony_ci if (midev) 23962306a36Sopenharmony_ci dev_hold(midev->ndev); 24062306a36Sopenharmony_ci spin_unlock_irqrestore(&mcli->sel_lock, flags); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (!midev) 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci switch (event) { 24662306a36Sopenharmony_ci case I2C_SLAVE_WRITE_RECEIVED: 24762306a36Sopenharmony_ci if (midev->rx_pos < MCTP_I2C_BUFSZ) { 24862306a36Sopenharmony_ci midev->rx_buffer[midev->rx_pos] = *val; 24962306a36Sopenharmony_ci midev->rx_pos++; 25062306a36Sopenharmony_ci } else { 25162306a36Sopenharmony_ci midev->ndev->stats.rx_over_errors++; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci case I2C_SLAVE_WRITE_REQUESTED: 25662306a36Sopenharmony_ci /* dest_slave as first byte */ 25762306a36Sopenharmony_ci midev->rx_buffer[0] = mcli->lladdr << 1; 25862306a36Sopenharmony_ci midev->rx_pos = 1; 25962306a36Sopenharmony_ci break; 26062306a36Sopenharmony_ci case I2C_SLAVE_STOP: 26162306a36Sopenharmony_ci rc = mctp_i2c_recv(midev); 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci default: 26462306a36Sopenharmony_ci break; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci dev_put(midev->ndev); 26862306a36Sopenharmony_ci return rc; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/* Processes incoming data that has been accumulated by the slave cb */ 27262306a36Sopenharmony_cistatic int mctp_i2c_recv(struct mctp_i2c_dev *midev) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct net_device *ndev = midev->ndev; 27562306a36Sopenharmony_ci struct mctp_i2c_hdr *hdr; 27662306a36Sopenharmony_ci struct mctp_skb_cb *cb; 27762306a36Sopenharmony_ci struct sk_buff *skb; 27862306a36Sopenharmony_ci unsigned long flags; 27962306a36Sopenharmony_ci u8 pec, calc_pec; 28062306a36Sopenharmony_ci size_t recvlen; 28162306a36Sopenharmony_ci int status; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* + 1 for the PEC */ 28462306a36Sopenharmony_ci if (midev->rx_pos < MCTP_I2C_MINLEN + 1) { 28562306a36Sopenharmony_ci ndev->stats.rx_length_errors++; 28662306a36Sopenharmony_ci return -EINVAL; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci /* recvlen excludes PEC */ 28962306a36Sopenharmony_ci recvlen = midev->rx_pos - 1; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci hdr = (void *)midev->rx_buffer; 29262306a36Sopenharmony_ci if (hdr->command != MCTP_I2C_COMMANDCODE) { 29362306a36Sopenharmony_ci ndev->stats.rx_dropped++; 29462306a36Sopenharmony_ci return -EINVAL; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (hdr->byte_count + offsetof(struct mctp_i2c_hdr, source_slave) != recvlen) { 29862306a36Sopenharmony_ci ndev->stats.rx_length_errors++; 29962306a36Sopenharmony_ci return -EINVAL; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci pec = midev->rx_buffer[midev->rx_pos - 1]; 30362306a36Sopenharmony_ci calc_pec = i2c_smbus_pec(0, midev->rx_buffer, recvlen); 30462306a36Sopenharmony_ci if (pec != calc_pec) { 30562306a36Sopenharmony_ci ndev->stats.rx_crc_errors++; 30662306a36Sopenharmony_ci return -EINVAL; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci skb = netdev_alloc_skb(ndev, recvlen); 31062306a36Sopenharmony_ci if (!skb) { 31162306a36Sopenharmony_ci ndev->stats.rx_dropped++; 31262306a36Sopenharmony_ci return -ENOMEM; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci skb->protocol = htons(ETH_P_MCTP); 31662306a36Sopenharmony_ci skb_put_data(skb, midev->rx_buffer, recvlen); 31762306a36Sopenharmony_ci skb_reset_mac_header(skb); 31862306a36Sopenharmony_ci skb_pull(skb, sizeof(struct mctp_i2c_hdr)); 31962306a36Sopenharmony_ci skb_reset_network_header(skb); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci cb = __mctp_cb(skb); 32262306a36Sopenharmony_ci cb->halen = 1; 32362306a36Sopenharmony_ci cb->haddr[0] = hdr->source_slave >> 1; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* We need to ensure that the netif is not used once netdev 32662306a36Sopenharmony_ci * unregister occurs 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_ci spin_lock_irqsave(&midev->lock, flags); 32962306a36Sopenharmony_ci if (midev->allow_rx) { 33062306a36Sopenharmony_ci reinit_completion(&midev->rx_done); 33162306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->lock, flags); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci status = netif_rx(skb); 33462306a36Sopenharmony_ci complete(&midev->rx_done); 33562306a36Sopenharmony_ci } else { 33662306a36Sopenharmony_ci status = NET_RX_DROP; 33762306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->lock, flags); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (status == NET_RX_SUCCESS) { 34162306a36Sopenharmony_ci ndev->stats.rx_packets++; 34262306a36Sopenharmony_ci ndev->stats.rx_bytes += recvlen; 34362306a36Sopenharmony_ci } else { 34462306a36Sopenharmony_ci ndev->stats.rx_dropped++; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci return 0; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cienum mctp_i2c_flow_state { 35062306a36Sopenharmony_ci MCTP_I2C_TX_FLOW_INVALID, 35162306a36Sopenharmony_ci MCTP_I2C_TX_FLOW_NONE, 35262306a36Sopenharmony_ci MCTP_I2C_TX_FLOW_NEW, 35362306a36Sopenharmony_ci MCTP_I2C_TX_FLOW_EXISTING, 35462306a36Sopenharmony_ci}; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic enum mctp_i2c_flow_state 35762306a36Sopenharmony_cimctp_i2c_get_tx_flow_state(struct mctp_i2c_dev *midev, struct sk_buff *skb) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci enum mctp_i2c_flow_state state; 36062306a36Sopenharmony_ci struct mctp_sk_key *key; 36162306a36Sopenharmony_ci struct mctp_flow *flow; 36262306a36Sopenharmony_ci unsigned long flags; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci flow = skb_ext_find(skb, SKB_EXT_MCTP); 36562306a36Sopenharmony_ci if (!flow) 36662306a36Sopenharmony_ci return MCTP_I2C_TX_FLOW_NONE; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci key = flow->key; 36962306a36Sopenharmony_ci if (!key) 37062306a36Sopenharmony_ci return MCTP_I2C_TX_FLOW_NONE; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci spin_lock_irqsave(&key->lock, flags); 37362306a36Sopenharmony_ci /* If the key is present but invalid, we're unlikely to be able 37462306a36Sopenharmony_ci * to handle the flow at all; just drop now 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_ci if (!key->valid) { 37762306a36Sopenharmony_ci state = MCTP_I2C_TX_FLOW_INVALID; 37862306a36Sopenharmony_ci } else { 37962306a36Sopenharmony_ci switch (key->dev_flow_state) { 38062306a36Sopenharmony_ci case MCTP_I2C_FLOW_STATE_NEW: 38162306a36Sopenharmony_ci key->dev_flow_state = MCTP_I2C_FLOW_STATE_ACTIVE; 38262306a36Sopenharmony_ci state = MCTP_I2C_TX_FLOW_NEW; 38362306a36Sopenharmony_ci break; 38462306a36Sopenharmony_ci case MCTP_I2C_FLOW_STATE_ACTIVE: 38562306a36Sopenharmony_ci state = MCTP_I2C_TX_FLOW_EXISTING; 38662306a36Sopenharmony_ci break; 38762306a36Sopenharmony_ci default: 38862306a36Sopenharmony_ci state = MCTP_I2C_TX_FLOW_INVALID; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci spin_unlock_irqrestore(&key->lock, flags); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return state; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci/* We're not contending with ourselves here; we only need to exclude other 39862306a36Sopenharmony_ci * i2c clients from using the bus. refcounts are simply to prevent 39962306a36Sopenharmony_ci * recursive locking. 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_cistatic void mctp_i2c_lock_nest(struct mctp_i2c_dev *midev) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci unsigned long flags; 40462306a36Sopenharmony_ci bool lock; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci spin_lock_irqsave(&midev->lock, flags); 40762306a36Sopenharmony_ci lock = midev->i2c_lock_count == 0; 40862306a36Sopenharmony_ci midev->i2c_lock_count++; 40962306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->lock, flags); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (lock) 41262306a36Sopenharmony_ci i2c_lock_bus(midev->adapter, I2C_LOCK_SEGMENT); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic void mctp_i2c_unlock_nest(struct mctp_i2c_dev *midev) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci unsigned long flags; 41862306a36Sopenharmony_ci bool unlock; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci spin_lock_irqsave(&midev->lock, flags); 42162306a36Sopenharmony_ci if (!WARN_ONCE(midev->i2c_lock_count == 0, "lock count underflow!")) 42262306a36Sopenharmony_ci midev->i2c_lock_count--; 42362306a36Sopenharmony_ci unlock = midev->i2c_lock_count == 0; 42462306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->lock, flags); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (unlock) 42762306a36Sopenharmony_ci i2c_unlock_bus(midev->adapter, I2C_LOCK_SEGMENT); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci/* Unlocks the bus if was previously locked, used for cleanup */ 43162306a36Sopenharmony_cistatic void mctp_i2c_unlock_reset(struct mctp_i2c_dev *midev) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci unsigned long flags; 43462306a36Sopenharmony_ci bool unlock; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci spin_lock_irqsave(&midev->lock, flags); 43762306a36Sopenharmony_ci unlock = midev->i2c_lock_count > 0; 43862306a36Sopenharmony_ci midev->i2c_lock_count = 0; 43962306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->lock, flags); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (unlock) 44262306a36Sopenharmony_ci i2c_unlock_bus(midev->adapter, I2C_LOCK_SEGMENT); 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct net_device_stats *stats = &midev->ndev->stats; 44862306a36Sopenharmony_ci enum mctp_i2c_flow_state fs; 44962306a36Sopenharmony_ci struct mctp_i2c_hdr *hdr; 45062306a36Sopenharmony_ci struct i2c_msg msg = {0}; 45162306a36Sopenharmony_ci u8 *pecp; 45262306a36Sopenharmony_ci int rc; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci fs = mctp_i2c_get_tx_flow_state(midev, skb); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci hdr = (void *)skb_mac_header(skb); 45762306a36Sopenharmony_ci /* Sanity check that packet contents matches skb length, 45862306a36Sopenharmony_ci * and can't exceed MCTP_I2C_BUFSZ 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci if (skb->len != hdr->byte_count + 3) { 46162306a36Sopenharmony_ci dev_warn_ratelimited(&midev->adapter->dev, 46262306a36Sopenharmony_ci "Bad tx length %d vs skb %u\n", 46362306a36Sopenharmony_ci hdr->byte_count + 3, skb->len); 46462306a36Sopenharmony_ci return; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (skb_tailroom(skb) >= 1) { 46862306a36Sopenharmony_ci /* Linear case with space, we can just append the PEC */ 46962306a36Sopenharmony_ci skb_put(skb, 1); 47062306a36Sopenharmony_ci } else { 47162306a36Sopenharmony_ci /* Otherwise need to copy the buffer */ 47262306a36Sopenharmony_ci skb_copy_bits(skb, 0, midev->tx_scratch, skb->len); 47362306a36Sopenharmony_ci hdr = (void *)midev->tx_scratch; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci pecp = (void *)&hdr->source_slave + hdr->byte_count; 47762306a36Sopenharmony_ci *pecp = i2c_smbus_pec(0, (u8 *)hdr, hdr->byte_count + 3); 47862306a36Sopenharmony_ci msg.buf = (void *)&hdr->command; 47962306a36Sopenharmony_ci /* command, bytecount, data, pec */ 48062306a36Sopenharmony_ci msg.len = 2 + hdr->byte_count + 1; 48162306a36Sopenharmony_ci msg.addr = hdr->dest_slave >> 1; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci switch (fs) { 48462306a36Sopenharmony_ci case MCTP_I2C_TX_FLOW_NONE: 48562306a36Sopenharmony_ci /* no flow: full lock & unlock */ 48662306a36Sopenharmony_ci mctp_i2c_lock_nest(midev); 48762306a36Sopenharmony_ci mctp_i2c_device_select(midev->client, midev); 48862306a36Sopenharmony_ci rc = __i2c_transfer(midev->adapter, &msg, 1); 48962306a36Sopenharmony_ci mctp_i2c_unlock_nest(midev); 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci case MCTP_I2C_TX_FLOW_NEW: 49362306a36Sopenharmony_ci /* new flow: lock, tx, but don't unlock; that will happen 49462306a36Sopenharmony_ci * on flow release 49562306a36Sopenharmony_ci */ 49662306a36Sopenharmony_ci mctp_i2c_lock_nest(midev); 49762306a36Sopenharmony_ci mctp_i2c_device_select(midev->client, midev); 49862306a36Sopenharmony_ci fallthrough; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci case MCTP_I2C_TX_FLOW_EXISTING: 50162306a36Sopenharmony_ci /* existing flow: we already have the lock; just tx */ 50262306a36Sopenharmony_ci rc = __i2c_transfer(midev->adapter, &msg, 1); 50362306a36Sopenharmony_ci break; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci case MCTP_I2C_TX_FLOW_INVALID: 50662306a36Sopenharmony_ci return; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (rc < 0) { 51062306a36Sopenharmony_ci dev_warn_ratelimited(&midev->adapter->dev, 51162306a36Sopenharmony_ci "__i2c_transfer failed %d\n", rc); 51262306a36Sopenharmony_ci stats->tx_errors++; 51362306a36Sopenharmony_ci } else { 51462306a36Sopenharmony_ci stats->tx_bytes += skb->len; 51562306a36Sopenharmony_ci stats->tx_packets++; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic void mctp_i2c_flow_release(struct mctp_i2c_dev *midev) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci unsigned long flags; 52262306a36Sopenharmony_ci bool unlock; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci spin_lock_irqsave(&midev->lock, flags); 52562306a36Sopenharmony_ci if (midev->release_count > midev->i2c_lock_count) { 52662306a36Sopenharmony_ci WARN_ONCE(1, "release count overflow"); 52762306a36Sopenharmony_ci midev->release_count = midev->i2c_lock_count; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci midev->i2c_lock_count -= midev->release_count; 53162306a36Sopenharmony_ci unlock = midev->i2c_lock_count == 0 && midev->release_count > 0; 53262306a36Sopenharmony_ci midev->release_count = 0; 53362306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->lock, flags); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (unlock) 53662306a36Sopenharmony_ci i2c_unlock_bus(midev->adapter, I2C_LOCK_SEGMENT); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int mctp_i2c_header_create(struct sk_buff *skb, struct net_device *dev, 54062306a36Sopenharmony_ci unsigned short type, const void *daddr, 54162306a36Sopenharmony_ci const void *saddr, unsigned int len) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct mctp_i2c_hdr *hdr; 54462306a36Sopenharmony_ci struct mctp_hdr *mhdr; 54562306a36Sopenharmony_ci u8 lldst, llsrc; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (len > MCTP_I2C_MAXMTU) 54862306a36Sopenharmony_ci return -EMSGSIZE; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci lldst = *((u8 *)daddr); 55162306a36Sopenharmony_ci llsrc = *((u8 *)saddr); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci skb_push(skb, sizeof(struct mctp_i2c_hdr)); 55462306a36Sopenharmony_ci skb_reset_mac_header(skb); 55562306a36Sopenharmony_ci hdr = (void *)skb_mac_header(skb); 55662306a36Sopenharmony_ci mhdr = mctp_hdr(skb); 55762306a36Sopenharmony_ci hdr->dest_slave = (lldst << 1) & 0xff; 55862306a36Sopenharmony_ci hdr->command = MCTP_I2C_COMMANDCODE; 55962306a36Sopenharmony_ci hdr->byte_count = len + 1; 56062306a36Sopenharmony_ci hdr->source_slave = ((llsrc << 1) & 0xff) | 0x01; 56162306a36Sopenharmony_ci mhdr->ver = 0x01; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci return sizeof(struct mctp_i2c_hdr); 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic int mctp_i2c_tx_thread(void *data) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct mctp_i2c_dev *midev = data; 56962306a36Sopenharmony_ci struct sk_buff *skb; 57062306a36Sopenharmony_ci unsigned long flags; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci for (;;) { 57362306a36Sopenharmony_ci if (kthread_should_stop()) 57462306a36Sopenharmony_ci break; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci spin_lock_irqsave(&midev->tx_queue.lock, flags); 57762306a36Sopenharmony_ci skb = __skb_dequeue(&midev->tx_queue); 57862306a36Sopenharmony_ci if (netif_queue_stopped(midev->ndev)) 57962306a36Sopenharmony_ci netif_wake_queue(midev->ndev); 58062306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->tx_queue.lock, flags); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (skb == &midev->unlock_marker) { 58362306a36Sopenharmony_ci mctp_i2c_flow_release(midev); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci } else if (skb) { 58662306a36Sopenharmony_ci mctp_i2c_xmit(midev, skb); 58762306a36Sopenharmony_ci kfree_skb(skb); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci } else { 59062306a36Sopenharmony_ci wait_event_idle(midev->tx_wq, 59162306a36Sopenharmony_ci !skb_queue_empty(&midev->tx_queue) || 59262306a36Sopenharmony_ci kthread_should_stop()); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci return 0; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic netdev_tx_t mctp_i2c_start_xmit(struct sk_buff *skb, 60062306a36Sopenharmony_ci struct net_device *dev) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct mctp_i2c_dev *midev = netdev_priv(dev); 60362306a36Sopenharmony_ci unsigned long flags; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci spin_lock_irqsave(&midev->tx_queue.lock, flags); 60662306a36Sopenharmony_ci if (skb_queue_len(&midev->tx_queue) >= MCTP_I2C_TX_WORK_LEN) { 60762306a36Sopenharmony_ci netif_stop_queue(dev); 60862306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->tx_queue.lock, flags); 60962306a36Sopenharmony_ci netdev_err(dev, "BUG! Tx Ring full when queue awake!\n"); 61062306a36Sopenharmony_ci return NETDEV_TX_BUSY; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci __skb_queue_tail(&midev->tx_queue, skb); 61462306a36Sopenharmony_ci if (skb_queue_len(&midev->tx_queue) == MCTP_I2C_TX_WORK_LEN) 61562306a36Sopenharmony_ci netif_stop_queue(dev); 61662306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->tx_queue.lock, flags); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci wake_up(&midev->tx_wq); 61962306a36Sopenharmony_ci return NETDEV_TX_OK; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic void mctp_i2c_release_flow(struct mctp_dev *mdev, 62362306a36Sopenharmony_ci struct mctp_sk_key *key) 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci struct mctp_i2c_dev *midev = netdev_priv(mdev->dev); 62762306a36Sopenharmony_ci bool queue_release = false; 62862306a36Sopenharmony_ci unsigned long flags; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci spin_lock_irqsave(&midev->lock, flags); 63162306a36Sopenharmony_ci /* if we have seen the flow/key previously, we need to pair the 63262306a36Sopenharmony_ci * original lock with a release 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_ci if (key->dev_flow_state == MCTP_I2C_FLOW_STATE_ACTIVE) { 63562306a36Sopenharmony_ci midev->release_count++; 63662306a36Sopenharmony_ci queue_release = true; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci key->dev_flow_state = MCTP_I2C_FLOW_STATE_INVALID; 63962306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->lock, flags); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (queue_release) { 64262306a36Sopenharmony_ci /* Ensure we have a release operation queued, through the fake 64362306a36Sopenharmony_ci * marker skb 64462306a36Sopenharmony_ci */ 64562306a36Sopenharmony_ci spin_lock(&midev->tx_queue.lock); 64662306a36Sopenharmony_ci if (!midev->unlock_marker.next) 64762306a36Sopenharmony_ci __skb_queue_tail(&midev->tx_queue, 64862306a36Sopenharmony_ci &midev->unlock_marker); 64962306a36Sopenharmony_ci spin_unlock(&midev->tx_queue.lock); 65062306a36Sopenharmony_ci wake_up(&midev->tx_wq); 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic const struct net_device_ops mctp_i2c_ops = { 65562306a36Sopenharmony_ci .ndo_start_xmit = mctp_i2c_start_xmit, 65662306a36Sopenharmony_ci .ndo_uninit = mctp_i2c_ndo_uninit, 65762306a36Sopenharmony_ci .ndo_open = mctp_i2c_ndo_open, 65862306a36Sopenharmony_ci}; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic const struct header_ops mctp_i2c_headops = { 66162306a36Sopenharmony_ci .create = mctp_i2c_header_create, 66262306a36Sopenharmony_ci}; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic const struct mctp_netdev_ops mctp_i2c_mctp_ops = { 66562306a36Sopenharmony_ci .release_flow = mctp_i2c_release_flow, 66662306a36Sopenharmony_ci}; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic void mctp_i2c_net_setup(struct net_device *dev) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci dev->type = ARPHRD_MCTP; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci dev->mtu = MCTP_I2C_MAXMTU; 67362306a36Sopenharmony_ci dev->min_mtu = MCTP_I2C_MINMTU; 67462306a36Sopenharmony_ci dev->max_mtu = MCTP_I2C_MAXMTU; 67562306a36Sopenharmony_ci dev->tx_queue_len = MCTP_I2C_TX_QUEUE_LEN; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci dev->hard_header_len = sizeof(struct mctp_i2c_hdr); 67862306a36Sopenharmony_ci dev->addr_len = 1; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci dev->netdev_ops = &mctp_i2c_ops; 68162306a36Sopenharmony_ci dev->header_ops = &mctp_i2c_headops; 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci/* Populates the mctp_i2c_dev priv struct for a netdev. 68562306a36Sopenharmony_ci * Returns an error pointer on failure. 68662306a36Sopenharmony_ci */ 68762306a36Sopenharmony_cistatic struct mctp_i2c_dev *mctp_i2c_midev_init(struct net_device *dev, 68862306a36Sopenharmony_ci struct mctp_i2c_client *mcli, 68962306a36Sopenharmony_ci struct i2c_adapter *adap) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci struct mctp_i2c_dev *midev = netdev_priv(dev); 69262306a36Sopenharmony_ci unsigned long flags; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci midev->tx_thread = kthread_create(mctp_i2c_tx_thread, midev, 69562306a36Sopenharmony_ci "%s/tx", dev->name); 69662306a36Sopenharmony_ci if (IS_ERR(midev->tx_thread)) 69762306a36Sopenharmony_ci return ERR_CAST(midev->tx_thread); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci midev->ndev = dev; 70062306a36Sopenharmony_ci get_device(&adap->dev); 70162306a36Sopenharmony_ci midev->adapter = adap; 70262306a36Sopenharmony_ci get_device(&mcli->client->dev); 70362306a36Sopenharmony_ci midev->client = mcli; 70462306a36Sopenharmony_ci INIT_LIST_HEAD(&midev->list); 70562306a36Sopenharmony_ci spin_lock_init(&midev->lock); 70662306a36Sopenharmony_ci midev->i2c_lock_count = 0; 70762306a36Sopenharmony_ci midev->release_count = 0; 70862306a36Sopenharmony_ci init_completion(&midev->rx_done); 70962306a36Sopenharmony_ci complete(&midev->rx_done); 71062306a36Sopenharmony_ci init_waitqueue_head(&midev->tx_wq); 71162306a36Sopenharmony_ci skb_queue_head_init(&midev->tx_queue); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* Add to the parent mcli */ 71462306a36Sopenharmony_ci spin_lock_irqsave(&mcli->sel_lock, flags); 71562306a36Sopenharmony_ci list_add(&midev->list, &mcli->devs); 71662306a36Sopenharmony_ci /* Select a device by default */ 71762306a36Sopenharmony_ci if (!mcli->sel) 71862306a36Sopenharmony_ci __mctp_i2c_device_select(mcli, midev); 71962306a36Sopenharmony_ci spin_unlock_irqrestore(&mcli->sel_lock, flags); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci /* Start the worker thread */ 72262306a36Sopenharmony_ci wake_up_process(midev->tx_thread); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci return midev; 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci/* Counterpart of mctp_i2c_midev_init */ 72862306a36Sopenharmony_cistatic void mctp_i2c_midev_free(struct mctp_i2c_dev *midev) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct mctp_i2c_client *mcli = midev->client; 73162306a36Sopenharmony_ci unsigned long flags; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (midev->tx_thread) { 73462306a36Sopenharmony_ci kthread_stop(midev->tx_thread); 73562306a36Sopenharmony_ci midev->tx_thread = NULL; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci /* Unconditionally unlock on close */ 73962306a36Sopenharmony_ci mctp_i2c_unlock_reset(midev); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* Remove the netdev from the parent i2c client. */ 74262306a36Sopenharmony_ci spin_lock_irqsave(&mcli->sel_lock, flags); 74362306a36Sopenharmony_ci list_del(&midev->list); 74462306a36Sopenharmony_ci if (mcli->sel == midev) { 74562306a36Sopenharmony_ci struct mctp_i2c_dev *first; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci first = list_first_entry_or_null(&mcli->devs, struct mctp_i2c_dev, list); 74862306a36Sopenharmony_ci __mctp_i2c_device_select(mcli, first); 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci spin_unlock_irqrestore(&mcli->sel_lock, flags); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci skb_queue_purge(&midev->tx_queue); 75362306a36Sopenharmony_ci put_device(&midev->adapter->dev); 75462306a36Sopenharmony_ci put_device(&mcli->client->dev); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci/* Stops, unregisters, and frees midev */ 75862306a36Sopenharmony_cistatic void mctp_i2c_unregister(struct mctp_i2c_dev *midev) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci unsigned long flags; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci /* Stop tx thread prior to unregister, it uses netif_() functions */ 76362306a36Sopenharmony_ci kthread_stop(midev->tx_thread); 76462306a36Sopenharmony_ci midev->tx_thread = NULL; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* Prevent any new rx in mctp_i2c_recv(), let any pending work finish */ 76762306a36Sopenharmony_ci spin_lock_irqsave(&midev->lock, flags); 76862306a36Sopenharmony_ci midev->allow_rx = false; 76962306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->lock, flags); 77062306a36Sopenharmony_ci wait_for_completion(&midev->rx_done); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci mctp_unregister_netdev(midev->ndev); 77362306a36Sopenharmony_ci /* midev has been freed now by mctp_i2c_ndo_uninit callback */ 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci free_netdev(midev->ndev); 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic void mctp_i2c_ndo_uninit(struct net_device *dev) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct mctp_i2c_dev *midev = netdev_priv(dev); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* Perform cleanup here to ensure that mcli->sel isn't holding 78362306a36Sopenharmony_ci * a reference that would prevent unregister_netdevice() 78462306a36Sopenharmony_ci * from completing. 78562306a36Sopenharmony_ci */ 78662306a36Sopenharmony_ci mctp_i2c_midev_free(midev); 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic int mctp_i2c_ndo_open(struct net_device *dev) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct mctp_i2c_dev *midev = netdev_priv(dev); 79262306a36Sopenharmony_ci unsigned long flags; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* i2c rx handler can only pass packets once the netdev is registered */ 79562306a36Sopenharmony_ci spin_lock_irqsave(&midev->lock, flags); 79662306a36Sopenharmony_ci midev->allow_rx = true; 79762306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->lock, flags); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci return 0; 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic int mctp_i2c_add_netdev(struct mctp_i2c_client *mcli, 80362306a36Sopenharmony_ci struct i2c_adapter *adap) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci struct mctp_i2c_dev *midev = NULL; 80662306a36Sopenharmony_ci struct net_device *ndev = NULL; 80762306a36Sopenharmony_ci struct i2c_adapter *root; 80862306a36Sopenharmony_ci unsigned long flags; 80962306a36Sopenharmony_ci char namebuf[30]; 81062306a36Sopenharmony_ci int rc; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci root = mux_root_adapter(adap); 81362306a36Sopenharmony_ci if (root != mcli->client->adapter) { 81462306a36Sopenharmony_ci dev_err(&mcli->client->dev, 81562306a36Sopenharmony_ci "I2C adapter %s is not a child bus of %s\n", 81662306a36Sopenharmony_ci mcli->client->adapter->name, root->name); 81762306a36Sopenharmony_ci return -EINVAL; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci WARN_ON(!mutex_is_locked(&driver_clients_lock)); 82162306a36Sopenharmony_ci snprintf(namebuf, sizeof(namebuf), "mctpi2c%d", adap->nr); 82262306a36Sopenharmony_ci ndev = alloc_netdev(sizeof(*midev), namebuf, NET_NAME_ENUM, mctp_i2c_net_setup); 82362306a36Sopenharmony_ci if (!ndev) { 82462306a36Sopenharmony_ci dev_err(&mcli->client->dev, "alloc netdev failed\n"); 82562306a36Sopenharmony_ci rc = -ENOMEM; 82662306a36Sopenharmony_ci goto err; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci dev_net_set(ndev, current->nsproxy->net_ns); 82962306a36Sopenharmony_ci SET_NETDEV_DEV(ndev, &adap->dev); 83062306a36Sopenharmony_ci dev_addr_set(ndev, &mcli->lladdr); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci midev = mctp_i2c_midev_init(ndev, mcli, adap); 83362306a36Sopenharmony_ci if (IS_ERR(midev)) { 83462306a36Sopenharmony_ci rc = PTR_ERR(midev); 83562306a36Sopenharmony_ci midev = NULL; 83662306a36Sopenharmony_ci goto err; 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci rc = mctp_register_netdev(ndev, &mctp_i2c_mctp_ops); 84062306a36Sopenharmony_ci if (rc < 0) { 84162306a36Sopenharmony_ci dev_err(&mcli->client->dev, 84262306a36Sopenharmony_ci "register netdev \"%s\" failed %d\n", 84362306a36Sopenharmony_ci ndev->name, rc); 84462306a36Sopenharmony_ci goto err; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci spin_lock_irqsave(&midev->lock, flags); 84862306a36Sopenharmony_ci midev->allow_rx = false; 84962306a36Sopenharmony_ci spin_unlock_irqrestore(&midev->lock, flags); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci return 0; 85262306a36Sopenharmony_cierr: 85362306a36Sopenharmony_ci if (midev) 85462306a36Sopenharmony_ci mctp_i2c_midev_free(midev); 85562306a36Sopenharmony_ci if (ndev) 85662306a36Sopenharmony_ci free_netdev(ndev); 85762306a36Sopenharmony_ci return rc; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci/* Removes any netdev for adap. mcli is the parent root i2c client */ 86162306a36Sopenharmony_cistatic void mctp_i2c_remove_netdev(struct mctp_i2c_client *mcli, 86262306a36Sopenharmony_ci struct i2c_adapter *adap) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct mctp_i2c_dev *midev = NULL, *m = NULL; 86562306a36Sopenharmony_ci unsigned long flags; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci WARN_ON(!mutex_is_locked(&driver_clients_lock)); 86862306a36Sopenharmony_ci spin_lock_irqsave(&mcli->sel_lock, flags); 86962306a36Sopenharmony_ci /* List size is limited by number of MCTP netdevs on a single hardware bus */ 87062306a36Sopenharmony_ci list_for_each_entry(m, &mcli->devs, list) 87162306a36Sopenharmony_ci if (m->adapter == adap) { 87262306a36Sopenharmony_ci midev = m; 87362306a36Sopenharmony_ci break; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci spin_unlock_irqrestore(&mcli->sel_lock, flags); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (midev) 87862306a36Sopenharmony_ci mctp_i2c_unregister(midev); 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci/* Determines whether a device is an i2c adapter. 88262306a36Sopenharmony_ci * Optionally returns the root i2c_adapter 88362306a36Sopenharmony_ci */ 88462306a36Sopenharmony_cistatic struct i2c_adapter *mctp_i2c_get_adapter(struct device *dev, 88562306a36Sopenharmony_ci struct i2c_adapter **ret_root) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci struct i2c_adapter *root, *adap; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (dev->type != &i2c_adapter_type) 89062306a36Sopenharmony_ci return NULL; 89162306a36Sopenharmony_ci adap = to_i2c_adapter(dev); 89262306a36Sopenharmony_ci root = mux_root_adapter(adap); 89362306a36Sopenharmony_ci WARN_ONCE(!root, "MCTP I2C failed to find root adapter for %s\n", 89462306a36Sopenharmony_ci dev_name(dev)); 89562306a36Sopenharmony_ci if (!root) 89662306a36Sopenharmony_ci return NULL; 89762306a36Sopenharmony_ci if (ret_root) 89862306a36Sopenharmony_ci *ret_root = root; 89962306a36Sopenharmony_ci return adap; 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci/* Determines whether a device is an i2c adapter with the "mctp-controller" 90362306a36Sopenharmony_ci * devicetree property set. If adap is not an OF node, returns match_no_of 90462306a36Sopenharmony_ci */ 90562306a36Sopenharmony_cistatic bool mctp_i2c_adapter_match(struct i2c_adapter *adap, bool match_no_of) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci if (!adap->dev.of_node) 90862306a36Sopenharmony_ci return match_no_of; 90962306a36Sopenharmony_ci return of_property_read_bool(adap->dev.of_node, MCTP_I2C_OF_PROP); 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci/* Called for each existing i2c device (adapter or client) when a 91362306a36Sopenharmony_ci * new mctp-i2c client is probed. 91462306a36Sopenharmony_ci */ 91562306a36Sopenharmony_cistatic int mctp_i2c_client_try_attach(struct device *dev, void *data) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci struct i2c_adapter *adap = NULL, *root = NULL; 91862306a36Sopenharmony_ci struct mctp_i2c_client *mcli = data; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci adap = mctp_i2c_get_adapter(dev, &root); 92162306a36Sopenharmony_ci if (!adap) 92262306a36Sopenharmony_ci return 0; 92362306a36Sopenharmony_ci if (mcli->client->adapter != root) 92462306a36Sopenharmony_ci return 0; 92562306a36Sopenharmony_ci /* Must either have mctp-controller property on the adapter, or 92662306a36Sopenharmony_ci * be a root adapter if it's non-devicetree 92762306a36Sopenharmony_ci */ 92862306a36Sopenharmony_ci if (!mctp_i2c_adapter_match(adap, adap == root)) 92962306a36Sopenharmony_ci return 0; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci return mctp_i2c_add_netdev(mcli, adap); 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_cistatic void mctp_i2c_notify_add(struct device *dev) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci struct mctp_i2c_client *mcli = NULL, *m = NULL; 93762306a36Sopenharmony_ci struct i2c_adapter *root = NULL, *adap = NULL; 93862306a36Sopenharmony_ci int rc; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci adap = mctp_i2c_get_adapter(dev, &root); 94162306a36Sopenharmony_ci if (!adap) 94262306a36Sopenharmony_ci return; 94362306a36Sopenharmony_ci /* Check for mctp-controller property on the adapter */ 94462306a36Sopenharmony_ci if (!mctp_i2c_adapter_match(adap, false)) 94562306a36Sopenharmony_ci return; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* Find an existing mcli for adap's root */ 94862306a36Sopenharmony_ci mutex_lock(&driver_clients_lock); 94962306a36Sopenharmony_ci list_for_each_entry(m, &driver_clients, list) { 95062306a36Sopenharmony_ci if (m->client->adapter == root) { 95162306a36Sopenharmony_ci mcli = m; 95262306a36Sopenharmony_ci break; 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (mcli) { 95762306a36Sopenharmony_ci rc = mctp_i2c_add_netdev(mcli, adap); 95862306a36Sopenharmony_ci if (rc < 0) 95962306a36Sopenharmony_ci dev_warn(dev, "Failed adding mctp-i2c net device\n"); 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci mutex_unlock(&driver_clients_lock); 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_cistatic void mctp_i2c_notify_del(struct device *dev) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci struct i2c_adapter *root = NULL, *adap = NULL; 96762306a36Sopenharmony_ci struct mctp_i2c_client *mcli = NULL; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci adap = mctp_i2c_get_adapter(dev, &root); 97062306a36Sopenharmony_ci if (!adap) 97162306a36Sopenharmony_ci return; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci mutex_lock(&driver_clients_lock); 97462306a36Sopenharmony_ci list_for_each_entry(mcli, &driver_clients, list) { 97562306a36Sopenharmony_ci if (mcli->client->adapter == root) { 97662306a36Sopenharmony_ci mctp_i2c_remove_netdev(mcli, adap); 97762306a36Sopenharmony_ci break; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci mutex_unlock(&driver_clients_lock); 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cistatic int mctp_i2c_probe(struct i2c_client *client) 98462306a36Sopenharmony_ci{ 98562306a36Sopenharmony_ci struct mctp_i2c_client *mcli = NULL; 98662306a36Sopenharmony_ci int rc; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci mutex_lock(&driver_clients_lock); 98962306a36Sopenharmony_ci mcli = mctp_i2c_new_client(client); 99062306a36Sopenharmony_ci if (IS_ERR(mcli)) { 99162306a36Sopenharmony_ci rc = PTR_ERR(mcli); 99262306a36Sopenharmony_ci mcli = NULL; 99362306a36Sopenharmony_ci goto out; 99462306a36Sopenharmony_ci } else { 99562306a36Sopenharmony_ci list_add(&mcli->list, &driver_clients); 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci /* Add a netdev for adapters that have a 'mctp-controller' property */ 99962306a36Sopenharmony_ci i2c_for_each_dev(mcli, mctp_i2c_client_try_attach); 100062306a36Sopenharmony_ci rc = 0; 100162306a36Sopenharmony_ciout: 100262306a36Sopenharmony_ci mutex_unlock(&driver_clients_lock); 100362306a36Sopenharmony_ci return rc; 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic void mctp_i2c_remove(struct i2c_client *client) 100762306a36Sopenharmony_ci{ 100862306a36Sopenharmony_ci struct mctp_i2c_client *mcli = i2c_get_clientdata(client); 100962306a36Sopenharmony_ci struct mctp_i2c_dev *midev = NULL, *tmp = NULL; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci mutex_lock(&driver_clients_lock); 101262306a36Sopenharmony_ci list_del(&mcli->list); 101362306a36Sopenharmony_ci /* Remove all child adapter netdevs */ 101462306a36Sopenharmony_ci list_for_each_entry_safe(midev, tmp, &mcli->devs, list) 101562306a36Sopenharmony_ci mctp_i2c_unregister(midev); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci mctp_i2c_free_client(mcli); 101862306a36Sopenharmony_ci mutex_unlock(&driver_clients_lock); 101962306a36Sopenharmony_ci} 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci/* We look for a 'mctp-controller' property on I2C busses as they are 102262306a36Sopenharmony_ci * added/deleted, creating/removing netdevs as required. 102362306a36Sopenharmony_ci */ 102462306a36Sopenharmony_cistatic int mctp_i2c_notifier_call(struct notifier_block *nb, 102562306a36Sopenharmony_ci unsigned long action, void *data) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci struct device *dev = data; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci switch (action) { 103062306a36Sopenharmony_ci case BUS_NOTIFY_ADD_DEVICE: 103162306a36Sopenharmony_ci mctp_i2c_notify_add(dev); 103262306a36Sopenharmony_ci break; 103362306a36Sopenharmony_ci case BUS_NOTIFY_DEL_DEVICE: 103462306a36Sopenharmony_ci mctp_i2c_notify_del(dev); 103562306a36Sopenharmony_ci break; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci return NOTIFY_DONE; 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic struct notifier_block mctp_i2c_notifier = { 104162306a36Sopenharmony_ci .notifier_call = mctp_i2c_notifier_call, 104262306a36Sopenharmony_ci}; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_cistatic const struct i2c_device_id mctp_i2c_id[] = { 104562306a36Sopenharmony_ci { "mctp-i2c-interface", 0 }, 104662306a36Sopenharmony_ci {}, 104762306a36Sopenharmony_ci}; 104862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, mctp_i2c_id); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_cistatic const struct of_device_id mctp_i2c_of_match[] = { 105162306a36Sopenharmony_ci { .compatible = "mctp-i2c-controller" }, 105262306a36Sopenharmony_ci {}, 105362306a36Sopenharmony_ci}; 105462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mctp_i2c_of_match); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic struct i2c_driver mctp_i2c_driver = { 105762306a36Sopenharmony_ci .driver = { 105862306a36Sopenharmony_ci .name = "mctp-i2c-interface", 105962306a36Sopenharmony_ci .of_match_table = mctp_i2c_of_match, 106062306a36Sopenharmony_ci }, 106162306a36Sopenharmony_ci .probe = mctp_i2c_probe, 106262306a36Sopenharmony_ci .remove = mctp_i2c_remove, 106362306a36Sopenharmony_ci .id_table = mctp_i2c_id, 106462306a36Sopenharmony_ci}; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic __init int mctp_i2c_mod_init(void) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci int rc; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci pr_info("MCTP I2C interface driver\n"); 107162306a36Sopenharmony_ci rc = i2c_add_driver(&mctp_i2c_driver); 107262306a36Sopenharmony_ci if (rc < 0) 107362306a36Sopenharmony_ci return rc; 107462306a36Sopenharmony_ci rc = bus_register_notifier(&i2c_bus_type, &mctp_i2c_notifier); 107562306a36Sopenharmony_ci if (rc < 0) { 107662306a36Sopenharmony_ci i2c_del_driver(&mctp_i2c_driver); 107762306a36Sopenharmony_ci return rc; 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ci return 0; 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_cistatic __exit void mctp_i2c_mod_exit(void) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci int rc; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci rc = bus_unregister_notifier(&i2c_bus_type, &mctp_i2c_notifier); 108762306a36Sopenharmony_ci if (rc < 0) 108862306a36Sopenharmony_ci pr_warn("MCTP I2C could not unregister notifier, %d\n", rc); 108962306a36Sopenharmony_ci i2c_del_driver(&mctp_i2c_driver); 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cimodule_init(mctp_i2c_mod_init); 109362306a36Sopenharmony_cimodule_exit(mctp_i2c_mod_exit); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ciMODULE_DESCRIPTION("MCTP I2C device"); 109662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 109762306a36Sopenharmony_ciMODULE_AUTHOR("Matt Johnston <matt@codeconstruct.com.au>"); 1098