| @@ -1,982 +0,0 @@ |
| 1 | | −// SPDX-License-Identifier: GPL-2.0 |
| 2 | | −/* |
| 3 | | − * Management Controller Transport Protocol (MCTP) |
| 4 | | − * |
| 5 | | − * Copyright (c) 2021 Code Construct |
| 6 | | − * Copyright (c) 2021 Google |
| 7 | | − */ |
| 8 | | − |
| 9 | | −#include <linux/module.h> |
| 10 | | −#include <linux/netdevice.h> |
| 11 | | −#include <linux/i2c.h> |
| 12 | | −#include <linux/i2c-mux.h> |
| 13 | | −#include <linux/if_arp.h> |
| 14 | | −#include <net/mctp.h> |
| 15 | | −#include <net/mctpdevice.h> |
| 16 | | − |
| 17 | | −/* SMBus 3.0 allows 255 data bytes (plus PEC), but the |
| 18 | | − * first byte is taken for source slave address. |
| 19 | | − */ |
| 20 | | −#define MCTP_I2C_MAXBLOCK 255 |
| 21 | | −#define MCTP_I2C_MAXMTU (MCTP_I2C_MAXBLOCK - 1) |
| 22 | | −#define MCTP_I2C_MINMTU (64 + 4) |
| 23 | | −/* Allow space for address, command, byte_count, databytes, PEC */ |
| 24 | | −#define MCTP_I2C_RXBUFSZ (3 + MCTP_I2C_MAXBLOCK + 1) |
| 25 | | −#define MCTP_I2C_MINLEN 8 |
| 26 | | −#define MCTP_I2C_COMMANDCODE 0x0f |
| 27 | | −#define MCTP_I2C_TX_WORK_LEN 100 |
| 28 | | −// sufficient for 64kB at min mtu |
| 29 | | −#define MCTP_I2C_TX_QUEUE_LEN 1100 |
| 30 | | − |
| 31 | | −#define MCTP_I2C_OF_PROP "mctp-controller" |
| 32 | | − |
| 33 | | −enum { |
| 34 | | − MCTP_I2C_FLOW_STATE_NEW = 0, |
| 35 | | − MCTP_I2C_FLOW_STATE_ACTIVE, |
| 36 | | −}; |
| 37 | | − |
| 38 | | −static struct { |
| 39 | | − /* lock protects clients and also prevents adding/removing adapters |
| 40 | | − * during mctp_i2c_client probe/remove. |
| 41 | | − */ |
| 42 | | − struct mutex lock; |
| 43 | | − // list of struct mctp_i2c_client |
| 44 | | − struct list_head clients; |
| 45 | | −} mi_driver_state; |
| 46 | | − |
| 47 | | −struct mctp_i2c_client; |
| 48 | | − |
| 49 | | −// The netdev structure. One of these per I2C adapter. |
| 50 | | −struct mctp_i2c_dev { |
| 51 | | − struct net_device *ndev; |
| 52 | | − struct i2c_adapter *adapter; |
| 53 | | − struct mctp_i2c_client *client; |
| 54 | | − struct list_head list; // for mctp_i2c_client.devs |
| 55 | | − |
| 56 | | − size_t pos; |
| 57 | | − u8 buffer[MCTP_I2C_RXBUFSZ]; |
| 58 | | − |
| 59 | | − struct task_struct *tx_thread; |
| 60 | | − wait_queue_head_t tx_wq; |
| 61 | | − struct sk_buff_head tx_queue; |
| 62 | | − |
| 63 | | − // a fake entry in our tx queue to perform an unlock operation |
| 64 | | − struct sk_buff unlock_marker; |
| 65 | | − |
| 66 | | − spinlock_t flow_lock; // protects i2c_lock_count and release_count |
| 67 | | − int i2c_lock_count; |
| 68 | | − int release_count; |
| 69 | | −}; |
| 70 | | − |
| 71 | | −/* The i2c client structure. One per hardware i2c bus at the top of the |
| 72 | | − * mux tree, shared by multiple netdevs |
| 73 | | − */ |
| 74 | | −struct mctp_i2c_client { |
| 75 | | − struct i2c_client *client; |
| 76 | | − u8 lladdr; |
| 77 | | − |
| 78 | | − struct mctp_i2c_dev *sel; |
| 79 | | − struct list_head devs; |
| 80 | | − spinlock_t curr_lock; // protects sel |
| 81 | | − |
| 82 | | − struct list_head list; // for mi_driver_state.clients |
| 83 | | −}; |
| 84 | | − |
| 85 | | −// Header on the wire |
| 86 | | −struct mctp_i2c_hdr { |
| 87 | | − u8 dest_slave; |
| 88 | | − u8 command; |
| 89 | | − u8 byte_count; |
| 90 | | − u8 source_slave; |
| 91 | | −}; |
| 92 | | − |
| 93 | | −static int mctp_i2c_recv(struct mctp_i2c_dev *midev); |
| 94 | | −static int mctp_i2c_slave_cb(struct i2c_client *client, |
| 95 | | − enum i2c_slave_event event, u8 *val); |
| 96 | | − |
| 97 | | −static struct i2c_adapter *mux_root_adapter(struct i2c_adapter *adap) |
| 98 | | −{ |
| 99 | | −#if IS_ENABLED(CONFIG_I2C_MUX) |
| 100 | | − return i2c_root_adapter(&adap->dev); |
| 101 | | −#else |
| 102 | | − /* In non-mux config all i2c adapters are root adapters */ |
| 103 | | − return adap; |
| 104 | | −#endif |
| 105 | | −} |
| 106 | | − |
| 107 | | −static ssize_t mctp_current_mux_show(struct device *dev, |
| 108 | | − struct device_attribute *attr, char *buf) |
| 109 | | −{ |
| 110 | | − struct mctp_i2c_client *mcli = i2c_get_clientdata(to_i2c_client(dev)); |
| 111 | | − struct net_device *ndev = NULL; |
| 112 | | − unsigned long flags; |
| 113 | | − ssize_t l; |
| 114 | | − |
| 115 | | − spin_lock_irqsave(&mcli->curr_lock, flags); |
| 116 | | − if (mcli->sel) { |
| 117 | | − ndev = mcli->sel->ndev; |
| 118 | | − dev_hold(ndev); |
| 119 | | − } |
| 120 | | − spin_unlock_irqrestore(&mcli->curr_lock, flags); |
| 121 | | − l = scnprintf(buf, PAGE_SIZE, "%s\n", ndev ? ndev->name : "(none)"); |
| 122 | | − if (ndev) |
| 123 | | − dev_put(ndev); |
| 124 | | − return l; |
| 125 | | −} |
| 126 | | −static DEVICE_ATTR_RO(mctp_current_mux); |
| 127 | | − |
| 128 | | −/* Creates a new i2c slave device attached to the root adapter. |
| 129 | | − * Sets up the slave callback. |
| 130 | | − * Must be called with a client on a root adapter. |
| 131 | | − */ |
| 132 | | −static struct mctp_i2c_client *mctp_i2c_new_client(struct i2c_client *client) |
| 133 | | −{ |
| 134 | | − struct mctp_i2c_client *mcli = NULL; |
| 135 | | − struct i2c_adapter *root = NULL; |
| 136 | | − int rc; |
| 137 | | − |
| 138 | | − if (client->flags & I2C_CLIENT_TEN) { |
| 139 | | − dev_err(&client->dev, "%s failed, MCTP requires a 7-bit I2C address, addr=0x%x", |
| 140 | | − __func__, client->addr); |
| 141 | | − rc = -EINVAL; |
| 142 | | − goto err; |
| 143 | | − } |
| 144 | | − |
| 145 | | − root = mux_root_adapter(client->adapter); |
| 146 | | − if (!root) { |
| 147 | | − dev_err(&client->dev, "%s failed to find root adapter\n", __func__); |
| 148 | | − rc = -ENOENT; |
| 149 | | − goto err; |
| 150 | | − } |
| 151 | | − if (root != client->adapter) { |
| 152 | | − dev_err(&client->dev, |
| 153 | | − "A mctp-i2c-controller client cannot be placed on an I2C mux adapter.\n" |
| 154 | | − " It should be placed on the mux tree root adapter\n" |
| 155 | | − " then set mctp-controller property on adapters to attach\n"); |
| 156 | | − rc = -EINVAL; |
| 157 | | − goto err; |
| 158 | | − } |
| 159 | | − |
| 160 | | − mcli = kzalloc(sizeof(*mcli), GFP_KERNEL); |
| 161 | | − if (!mcli) { |
| 162 | | − rc = -ENOMEM; |
| 163 | | − goto err; |
| 164 | | − } |
| 165 | | − spin_lock_init(&mcli->curr_lock); |
| 166 | | − INIT_LIST_HEAD(&mcli->devs); |
| 167 | | − INIT_LIST_HEAD(&mcli->list); |
| 168 | | − mcli->lladdr = client->addr & 0xff; |
| 169 | | − mcli->client = client; |
| 170 | | − i2c_set_clientdata(client, mcli); |
| 171 | | − |
| 172 | | − rc = i2c_slave_register(mcli->client, mctp_i2c_slave_cb); |
| 173 | | − if (rc) { |
| 174 | | − dev_err(&client->dev, "%s i2c register failed %d\n", __func__, rc); |
| 175 | | − mcli->client = NULL; |
| 176 | | − i2c_set_clientdata(client, NULL); |
| 177 | | − goto err; |
| 178 | | − } |
| 179 | | − |
| 180 | | − rc = device_create_file(&client->dev, &dev_attr_mctp_current_mux); |
| 181 | | − if (rc) { |
| 182 | | − dev_err(&client->dev, "%s adding sysfs \"%s\" failed %d\n", __func__, |
| 183 | | − dev_attr_mctp_current_mux.attr.name, rc); |
| 184 | | − // continue anyway |
| 185 | | − } |
| 186 | | − |
| 187 | | − return mcli; |
| 188 | | −err: |
| 189 | | − if (mcli) { |
| 190 | | − if (mcli->client) { |
| 191 | | − device_remove_file(&mcli->client->dev, &dev_attr_mctp_current_mux); |
| 192 | | − i2c_unregister_device(mcli->client); |
| 193 | | − } |
| 194 | | − kfree(mcli); |
| 195 | | − } |
| 196 | | − return ERR_PTR(rc); |
| 197 | | −} |
| 198 | | − |
| 199 | | −static void mctp_i2c_free_client(struct mctp_i2c_client *mcli) |
| 200 | | −{ |
| 201 | | − int rc; |
| 202 | | − |
| 203 | | − WARN_ON(!mutex_is_locked(&mi_driver_state.lock)); |
| 204 | | − WARN_ON(!list_empty(&mcli->devs)); |
| 205 | | − WARN_ON(mcli->sel); // sanity check, no locking |
| 206 | | − |
| 207 | | − device_remove_file(&mcli->client->dev, &dev_attr_mctp_current_mux); |
| 208 | | − rc = i2c_slave_unregister(mcli->client); |
| 209 | | − // leak if it fails, we can't propagate errors upwards |
| 210 | | − if (rc) |
| 211 | | − dev_err(&mcli->client->dev, "%s i2c unregister failed %d\n", __func__, rc); |
| 212 | | − else |
| 213 | | − kfree(mcli); |
| 214 | | −} |
| 215 | | − |
| 216 | | −/* Switch the mctp i2c device to receive responses. |
| 217 | | − * Call with curr_lock held |
| 218 | | − */ |
| 219 | | −static void __mctp_i2c_device_select(struct mctp_i2c_client *mcli, |
| 220 | | − struct mctp_i2c_dev *midev) |
| 221 | | −{ |
| 222 | | − assert_spin_locked(&mcli->curr_lock); |
| 223 | | − if (midev) |
| 224 | | − dev_hold(midev->ndev); |
| 225 | | − if (mcli->sel) |
| 226 | | − dev_put(mcli->sel->ndev); |
| 227 | | − mcli->sel = midev; |
| 228 | | −} |
| 229 | | − |
| 230 | | −// Switch the mctp i2c device to receive responses |
| 231 | | −static void mctp_i2c_device_select(struct mctp_i2c_client *mcli, |
| 232 | | − struct mctp_i2c_dev *midev) |
| 233 | | −{ |
| 234 | | − unsigned long flags; |
| 235 | | − |
| 236 | | − spin_lock_irqsave(&mcli->curr_lock, flags); |
| 237 | | − __mctp_i2c_device_select(mcli, midev); |
| 238 | | − spin_unlock_irqrestore(&mcli->curr_lock, flags); |
| 239 | | −} |
| 240 | | − |
| 241 | | −static int mctp_i2c_slave_cb(struct i2c_client *client, |
| 242 | | − enum i2c_slave_event event, u8 *val) |
| 243 | | −{ |
| 244 | | − struct mctp_i2c_client *mcli = i2c_get_clientdata(client); |
| 245 | | − struct mctp_i2c_dev *midev = NULL; |
| 246 | | − unsigned long flags; |
| 247 | | − int rc = 0; |
| 248 | | − |
| 249 | | − spin_lock_irqsave(&mcli->curr_lock, flags); |
| 250 | | − midev = mcli->sel; |
| 251 | | − if (midev) |
| 252 | | − dev_hold(midev->ndev); |
| 253 | | − spin_unlock_irqrestore(&mcli->curr_lock, flags); |
| 254 | | − |
| 255 | | − if (!midev) |
| 256 | | − return 0; |
| 257 | | − |
| 258 | | − switch (event) { |
| 259 | | − case I2C_SLAVE_WRITE_RECEIVED: |
| 260 | | − if (midev->pos < MCTP_I2C_RXBUFSZ) { |
| 261 | | − midev->buffer[midev->pos] = *val; |
| 262 | | − midev->pos++; |
| 263 | | − } else { |
| 264 | | − midev->ndev->stats.rx_over_errors++; |
| 265 | | − } |
| 266 | | − |
| 267 | | − break; |
| 268 | | − case I2C_SLAVE_WRITE_REQUESTED: |
| 269 | | − /* dest_slave as first byte */ |
| 270 | | − midev->buffer[0] = mcli->lladdr << 1; |
| 271 | | − midev->pos = 1; |
| 272 | | − break; |
| 273 | | − case I2C_SLAVE_STOP: |
| 274 | | − rc = mctp_i2c_recv(midev); |
| 275 | | − break; |
| 276 | | − default: |
| 277 | | − break; |
| 278 | | − } |
| 279 | | − |
| 280 | | − dev_put(midev->ndev); |
| 281 | | − return rc; |
| 282 | | −} |
| 283 | | − |
| 284 | | −// Processes incoming data that has been accumulated by the slave cb |
| 285 | | −static int mctp_i2c_recv(struct mctp_i2c_dev *midev) |
| 286 | | −{ |
| 287 | | − struct net_device *ndev = midev->ndev; |
| 288 | | − struct mctp_i2c_hdr *hdr; |
| 289 | | − struct mctp_skb_cb *cb; |
| 290 | | − struct sk_buff *skb; |
| 291 | | − u8 pec, calc_pec; |
| 292 | | − size_t recvlen; |
| 293 | | − |
| 294 | | − /* + 1 for the PEC */ |
| 295 | | − if (midev->pos < MCTP_I2C_MINLEN + 1) { |
| 296 | | − ndev->stats.rx_length_errors++; |
| 297 | | − return -EINVAL; |
| 298 | | − } |
| 299 | | − recvlen = midev->pos - 1; |
| 300 | | − |
| 301 | | − hdr = (void *)midev->buffer; |
| 302 | | − if (hdr->command != MCTP_I2C_COMMANDCODE) { |
| 303 | | − ndev->stats.rx_dropped++; |
| 304 | | − return -EINVAL; |
| 305 | | − } |
| 306 | | − |
| 307 | | − pec = midev->buffer[midev->pos - 1]; |
| 308 | | − calc_pec = i2c_smbus_pec(0, midev->buffer, recvlen); |
| 309 | | − if (pec != calc_pec) { |
| 310 | | − ndev->stats.rx_crc_errors++; |
| 311 | | − return -EINVAL; |
| 312 | | − } |
| 313 | | − |
| 314 | | − skb = netdev_alloc_skb(ndev, recvlen); |
| 315 | | − if (!skb) { |
| 316 | | − ndev->stats.rx_dropped++; |
| 317 | | − return -ENOMEM; |
| 318 | | − } |
| 319 | | − |
| 320 | | − skb->protocol = htons(ETH_P_MCTP); |
| 321 | | − skb_put_data(skb, midev->buffer, recvlen); |
| 322 | | − skb_reset_mac_header(skb); |
| 323 | | − skb_pull(skb, sizeof(struct mctp_i2c_hdr)); |
| 324 | | − skb_reset_network_header(skb); |
| 325 | | − |
| 326 | | − cb = __mctp_cb(skb); |
| 327 | | − cb->halen = 1; |
| 328 | | − cb->haddr[0] = hdr->source_slave; |
| 329 | | − |
| 330 | | − if (netif_rx(skb) == NET_RX_SUCCESS) { |
| 331 | | − ndev->stats.rx_packets++; |
| 332 | | − ndev->stats.rx_bytes += skb->len; |
| 333 | | − } else { |
| 334 | | − ndev->stats.rx_dropped++; |
| 335 | | − } |
| 336 | | − return 0; |
| 337 | | −} |
| 338 | | − |
| 339 | | −enum mctp_i2c_flow_state { |
| 340 | | − MCTP_I2C_TX_FLOW_INVALID, |
| 341 | | − MCTP_I2C_TX_FLOW_NONE, |
| 342 | | − MCTP_I2C_TX_FLOW_NEW, |
| 343 | | − MCTP_I2C_TX_FLOW_EXISTING, |
| 344 | | −}; |
| 345 | | − |
| 346 | | −static enum mctp_i2c_flow_state |
| 347 | | −mctp_i2c_get_tx_flow_state(struct mctp_i2c_dev *midev, struct sk_buff *skb) |
| 348 | | −{ |
| 349 | | − enum mctp_i2c_flow_state state; |
| 350 | | − struct mctp_sk_key *key; |
| 351 | | − struct mctp_flow *flow; |
| 352 | | − unsigned long flags; |
| 353 | | − |
| 354 | | − flow = skb_ext_find(skb, SKB_EXT_MCTP); |
| 355 | | − if (!flow) |
| 356 | | − return MCTP_I2C_TX_FLOW_NONE; |
| 357 | | − |
| 358 | | − key = flow->key; |
| 359 | | − if (!key) |
| 360 | | − return MCTP_I2C_TX_FLOW_NONE; |
| 361 | | − |
| 362 | | − spin_lock_irqsave(&key->lock, flags); |
| 363 | | − /* if the key is present but invalid, we're unlikely to be able |
| 364 | | − * to handle the flow at all; just drop now |
| 365 | | − */ |
| 366 | | − if (!key->valid) { |
| 367 | | − state = MCTP_I2C_TX_FLOW_INVALID; |
| 368 | | − |
| 369 | | − } else if (key->dev_flow_state == MCTP_I2C_FLOW_STATE_NEW) { |
| 370 | | − key->dev_flow_state = MCTP_I2C_FLOW_STATE_ACTIVE; |
| 371 | | − state = MCTP_I2C_TX_FLOW_NEW; |
| 372 | | − } else { |
| 373 | | − state = MCTP_I2C_TX_FLOW_EXISTING; |
| 374 | | − } |
| 375 | | − |
| 376 | | − spin_unlock_irqrestore(&key->lock, flags); |
| 377 | | − |
| 378 | | − return state; |
| 379 | | −} |
| 380 | | − |
| 381 | | −/* We're not contending with ourselves here; we only need to exclude other |
| 382 | | − * i2c clients from using the bus. refcounts are simply to prevent |
| 383 | | − * recursive locking. |
| 384 | | − */ |
| 385 | | −static void mctp_i2c_lock_nest(struct mctp_i2c_dev *midev) |
| 386 | | −{ |
| 387 | | − unsigned long flags; |
| 388 | | − bool lock; |
| 389 | | − |
| 390 | | − spin_lock_irqsave(&midev->flow_lock, flags); |
| 391 | | − lock = midev->i2c_lock_count == 0; |
| 392 | | − midev->i2c_lock_count++; |
| 393 | | − spin_unlock_irqrestore(&midev->flow_lock, flags); |
| 394 | | − |
| 395 | | − if (lock) |
| 396 | | − i2c_lock_bus(midev->adapter, I2C_LOCK_SEGMENT); |
| 397 | | −} |
| 398 | | − |
| 399 | | −static void mctp_i2c_unlock_nest(struct mctp_i2c_dev *midev) |
| 400 | | −{ |
| 401 | | − unsigned long flags; |
| 402 | | − bool unlock; |
| 403 | | − |
| 404 | | − spin_lock_irqsave(&midev->flow_lock, flags); |
| 405 | | − if (!WARN_ONCE(midev->i2c_lock_count == 0, "lock count underflow!")) |
| 406 | | − midev->i2c_lock_count--; |
| 407 | | − unlock = midev->i2c_lock_count == 0; |
| 408 | | − spin_unlock_irqrestore(&midev->flow_lock, flags); |
| 409 | | − |
| 410 | | − if (unlock) |
| 411 | | − i2c_unlock_bus(midev->adapter, I2C_LOCK_SEGMENT); |
| 412 | | −} |
| 413 | | − |
| 414 | | −static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) |
| 415 | | −{ |
| 416 | | − struct net_device_stats *stats = &midev->ndev->stats; |
| 417 | | − enum mctp_i2c_flow_state fs; |
| 418 | | − union i2c_smbus_data *data; |
| 419 | | − struct mctp_i2c_hdr *hdr; |
| 420 | | − unsigned int len; |
| 421 | | − u16 daddr; |
| 422 | | − int rc; |
| 423 | | − |
| 424 | | − fs = mctp_i2c_get_tx_flow_state(midev, skb); |
| 425 | | − |
| 426 | | − len = skb->len; |
| 427 | | − hdr = (void *)skb_mac_header(skb); |
| 428 | | − data = (void *)&hdr->byte_count; |
| 429 | | − daddr = hdr->dest_slave >> 1; |
| 430 | | − |
| 431 | | − switch (fs) { |
| 432 | | − case MCTP_I2C_TX_FLOW_NONE: |
| 433 | | − /* no flow: full lock & unlock */ |
| 434 | | − mctp_i2c_lock_nest(midev); |
| 435 | | − mctp_i2c_device_select(midev->client, midev); |
| 436 | | − rc = __i2c_smbus_xfer(midev->adapter, daddr, I2C_CLIENT_PEC, |
| 437 | | − I2C_SMBUS_WRITE, hdr->command, |
| 438 | | − I2C_SMBUS_BLOCK_DATA, data); |
| 439 | | − mctp_i2c_unlock_nest(midev); |
| 440 | | − break; |
| 441 | | − |
| 442 | | − case MCTP_I2C_TX_FLOW_NEW: |
| 443 | | − /* new flow: lock, tx, but don't unlock; that will happen |
| 444 | | − * on flow release |
| 445 | | − */ |
| 446 | | − mctp_i2c_lock_nest(midev); |
| 447 | | − mctp_i2c_device_select(midev->client, midev); |
| 448 | | − fallthrough; |
| 449 | | − |
| 450 | | − case MCTP_I2C_TX_FLOW_EXISTING: |
| 451 | | − /* existing flow: we already have the lock; just tx */ |
| 452 | | − rc = __i2c_smbus_xfer(midev->adapter, daddr, I2C_CLIENT_PEC, |
| 453 | | − I2C_SMBUS_WRITE, hdr->command, |
| 454 | | − I2C_SMBUS_BLOCK_DATA, data); |
| 455 | | − break; |
| 456 | | − |
| 457 | | − case MCTP_I2C_TX_FLOW_INVALID: |
| 458 | | − return; |
| 459 | | − } |
| 460 | | − |
| 461 | | − if (rc) { |
| 462 | | − dev_warn_ratelimited(&midev->adapter->dev, |
| 463 | | − "%s i2c_smbus_xfer failed %d", __func__, rc); |
| 464 | | − stats->tx_errors++; |
| 465 | | − } else { |
| 466 | | − stats->tx_bytes += len; |
| 467 | | − stats->tx_packets++; |
| 468 | | − } |
| 469 | | −} |
| 470 | | − |
| 471 | | −static void mctp_i2c_flow_release(struct mctp_i2c_dev *midev) |
| 472 | | −{ |
| 473 | | − unsigned long flags; |
| 474 | | − bool unlock; |
| 475 | | − |
| 476 | | − spin_lock_irqsave(&midev->flow_lock, flags); |
| 477 | | − if (midev->release_count > midev->i2c_lock_count) { |
| 478 | | − WARN_ONCE(1, "release count overflow"); |
| 479 | | − midev->release_count = midev->i2c_lock_count; |
| 480 | | − } |
| 481 | | − |
| 482 | | − midev->i2c_lock_count -= midev->release_count; |
| 483 | | − unlock = midev->i2c_lock_count == 0 && midev->release_count > 0; |
| 484 | | − midev->release_count = 0; |
| 485 | | − spin_unlock_irqrestore(&midev->flow_lock, flags); |
| 486 | | − |
| 487 | | − if (unlock) |
| 488 | | − i2c_unlock_bus(midev->adapter, I2C_LOCK_SEGMENT); |
| 489 | | −} |
| 490 | | − |
| 491 | | −static int mctp_i2c_header_create(struct sk_buff *skb, struct net_device *dev, |
| 492 | | − unsigned short type, const void *daddr, |
| 493 | | − const void *saddr, unsigned int len) |
| 494 | | −{ |
| 495 | | − struct mctp_i2c_hdr *hdr; |
| 496 | | − struct mctp_hdr *mhdr; |
| 497 | | − u8 lldst, llsrc; |
| 498 | | − |
| 499 | | − lldst = *((u8 *)daddr); |
| 500 | | − llsrc = *((u8 *)saddr); |
| 501 | | − |
| 502 | | − skb_push(skb, sizeof(struct mctp_i2c_hdr)); |
| 503 | | − skb_reset_mac_header(skb); |
| 504 | | − hdr = (void *)skb_mac_header(skb); |
| 505 | | − mhdr = mctp_hdr(skb); |
| 506 | | − hdr->dest_slave = (lldst << 1) & 0xff; |
| 507 | | − hdr->command = MCTP_I2C_COMMANDCODE; |
| 508 | | − hdr->byte_count = len + 1; |
| 509 | | − if (hdr->byte_count > MCTP_I2C_MAXBLOCK) |
| 510 | | − return -EMSGSIZE; |
| 511 | | − hdr->source_slave = ((llsrc << 1) & 0xff) | 0x01; |
| 512 | | − mhdr->ver = 0x01; |
| 513 | | − |
| 514 | | − return 0; |
| 515 | | −} |
| 516 | | − |
| 517 | | −static int mctp_i2c_tx_thread(void *data) |
| 518 | | −{ |
| 519 | | − struct mctp_i2c_dev *midev = data; |
| 520 | | − struct sk_buff *skb; |
| 521 | | − unsigned long flags; |
| 522 | | − |
| 523 | | − for (;;) { |
| 524 | | − if (kthread_should_stop()) |
| 525 | | − break; |
| 526 | | − |
| 527 | | − spin_lock_irqsave(&midev->tx_queue.lock, flags); |
| 528 | | − skb = __skb_dequeue(&midev->tx_queue); |
| 529 | | − if (netif_queue_stopped(midev->ndev)) |
| 530 | | − netif_wake_queue(midev->ndev); |
| 531 | | − spin_unlock_irqrestore(&midev->tx_queue.lock, flags); |
| 532 | | − |
| 533 | | − if (skb == &midev->unlock_marker) { |
| 534 | | − mctp_i2c_flow_release(midev); |
| 535 | | − |
| 536 | | − } else if (skb) { |
| 537 | | − mctp_i2c_xmit(midev, skb); |
| 538 | | − kfree_skb(skb); |
| 539 | | − |
| 540 | | − } else { |
| 541 | | − wait_event(midev->tx_wq, |
| 542 | | − !skb_queue_empty(&midev->tx_queue) || |
| 543 | | − kthread_should_stop()); |
| 544 | | − } |
| 545 | | − } |
| 546 | | − |
| 547 | | − return 0; |
| 548 | | −} |
| 549 | | − |
| 550 | | −static netdev_tx_t mctp_i2c_start_xmit(struct sk_buff *skb, |
| 551 | | − struct net_device *dev) |
| 552 | | −{ |
| 553 | | − struct mctp_i2c_dev *midev = netdev_priv(dev); |
| 554 | | − unsigned long flags; |
| 555 | | − |
| 556 | | − spin_lock_irqsave(&midev->tx_queue.lock, flags); |
| 557 | | − if (skb_queue_len(&midev->tx_queue) >= MCTP_I2C_TX_WORK_LEN) { |
| 558 | | − netif_stop_queue(dev); |
| 559 | | − spin_unlock_irqrestore(&midev->tx_queue.lock, flags); |
| 560 | | − netdev_err(dev, "BUG! Tx Ring full when queue awake!\n"); |
| 561 | | − return NETDEV_TX_BUSY; |
| 562 | | − } |
| 563 | | − |
| 564 | | − __skb_queue_tail(&midev->tx_queue, skb); |
| 565 | | − if (skb_queue_len(&midev->tx_queue) == MCTP_I2C_TX_WORK_LEN) |
| 566 | | − netif_stop_queue(dev); |
| 567 | | − spin_unlock_irqrestore(&midev->tx_queue.lock, flags); |
| 568 | | − |
| 569 | | − wake_up(&midev->tx_wq); |
| 570 | | − return NETDEV_TX_OK; |
| 571 | | −} |
| 572 | | − |
| 573 | | −static void mctp_i2c_release_flow(struct mctp_dev *mdev, |
| 574 | | − struct mctp_sk_key *key) |
| 575 | | − |
| 576 | | −{ |
| 577 | | − struct mctp_i2c_dev *midev = netdev_priv(mdev->dev); |
| 578 | | − unsigned long flags; |
| 579 | | − |
| 580 | | − spin_lock_irqsave(&midev->flow_lock, flags); |
| 581 | | − midev->release_count++; |
| 582 | | − spin_unlock_irqrestore(&midev->flow_lock, flags); |
| 583 | | − |
| 584 | | − /* Ensure we have a release operation queued, through the fake |
| 585 | | − * marker skb |
| 586 | | − */ |
| 587 | | − spin_lock(&midev->tx_queue.lock); |
| 588 | | − if (!midev->unlock_marker.next) |
| 589 | | − __skb_queue_tail(&midev->tx_queue, &midev->unlock_marker); |
| 590 | | − spin_unlock(&midev->tx_queue.lock); |
| 591 | | − |
| 592 | | − wake_up(&midev->tx_wq); |
| 593 | | −} |
| 594 | | − |
| 595 | | −static const struct net_device_ops mctp_i2c_ops = { |
| 596 | | − .ndo_start_xmit = mctp_i2c_start_xmit, |
| 597 | | −}; |
| 598 | | − |
| 599 | | −static const struct header_ops mctp_i2c_headops = { |
| 600 | | − .create = mctp_i2c_header_create, |
| 601 | | −}; |
| 602 | | − |
| 603 | | −static const struct mctp_netdev_ops mctp_i2c_mctp_ops = { |
| 604 | | − .release_flow = mctp_i2c_release_flow, |
| 605 | | −}; |
| 606 | | − |
| 607 | | −static void mctp_i2c_net_setup(struct net_device *dev) |
| 608 | | −{ |
| 609 | | − dev->type = ARPHRD_MCTP; |
| 610 | | − |
| 611 | | − dev->mtu = MCTP_I2C_MAXMTU; |
| 612 | | − dev->min_mtu = MCTP_I2C_MINMTU; |
| 613 | | − dev->max_mtu = MCTP_I2C_MAXMTU; |
| 614 | | − dev->tx_queue_len = MCTP_I2C_TX_QUEUE_LEN; |
| 615 | | − |
| 616 | | − dev->hard_header_len = sizeof(struct mctp_i2c_hdr); |
| 617 | | − dev->addr_len = 1; |
| 618 | | − |
| 619 | | − dev->netdev_ops = &mctp_i2c_ops; |
| 620 | | − dev->header_ops = &mctp_i2c_headops; |
| 621 | | − dev->needs_free_netdev = true; |
| 622 | | −} |
| 623 | | − |
| 624 | | −static int mctp_i2c_add_netdev(struct mctp_i2c_client *mcli, |
| 625 | | − struct i2c_adapter *adap) |
| 626 | | −{ |
| 627 | | − unsigned long flags; |
| 628 | | − struct mctp_i2c_dev *midev = NULL; |
| 629 | | − struct net_device *ndev = NULL; |
| 630 | | − struct i2c_adapter *root; |
| 631 | | − char namebuf[30]; |
| 632 | | − int rc; |
| 633 | | − |
| 634 | | − root = mux_root_adapter(adap); |
| 635 | | − if (root != mcli->client->adapter) { |
| 636 | | − dev_err(&mcli->client->dev, |
| 637 | | − "I2C adapter %s is not a child bus of %s", |
| 638 | | − mcli->client->adapter->name, root->name); |
| 639 | | − return -EINVAL; |
| 640 | | − } |
| 641 | | − |
| 642 | | − WARN_ON(!mutex_is_locked(&mi_driver_state.lock)); |
| 643 | | − snprintf(namebuf, sizeof(namebuf), "mctpi2c%d", adap->nr); |
| 644 | | − ndev = alloc_netdev(sizeof(*midev), namebuf, NET_NAME_ENUM, mctp_i2c_net_setup); |
| 645 | | − if (!ndev) { |
| 646 | | − dev_err(&mcli->client->dev, "%s alloc netdev failed\n", __func__); |
| 647 | | − rc = -ENOMEM; |
| 648 | | − goto err; |
| 649 | | − } |
| 650 | | − dev_net_set(ndev, current->nsproxy->net_ns); |
| 651 | | − SET_NETDEV_DEV(ndev, &adap->dev); |
| 652 | | − ndev->dev_addr = &mcli->lladdr; |
| 653 | | − |
| 654 | | − midev = netdev_priv(ndev); |
| 655 | | − skb_queue_head_init(&midev->tx_queue); |
| 656 | | − INIT_LIST_HEAD(&midev->list); |
| 657 | | − midev->adapter = adap; |
| 658 | | − midev->client = mcli; |
| 659 | | − spin_lock_init(&midev->flow_lock); |
| 660 | | − midev->i2c_lock_count = 0; |
| 661 | | − midev->release_count = 0; |
| 662 | | − /* Hold references */ |
| 663 | | − get_device(&midev->adapter->dev); |
| 664 | | − get_device(&midev->client->client->dev); |
| 665 | | − midev->ndev = ndev; |
| 666 | | − init_waitqueue_head(&midev->tx_wq); |
| 667 | | − midev->tx_thread = kthread_create(mctp_i2c_tx_thread, midev, |
| 668 | | − "%s/tx", namebuf); |
| 669 | | − if (IS_ERR_OR_NULL(midev->tx_thread)) { |
| 670 | | − rc = -ENOMEM; |
| 671 | | − goto err_free; |
| 672 | | − } |
| 673 | | − |
| 674 | | − rc = mctp_register_netdev(ndev, &mctp_i2c_mctp_ops); |
| 675 | | − if (rc) { |
| 676 | | − dev_err(&mcli->client->dev, |
| 677 | | − "%s register netdev \"%s\" failed %d\n", __func__, |
| 678 | | − ndev->name, rc); |
| 679 | | − goto err_stop_kthread; |
| 680 | | − } |
| 681 | | − spin_lock_irqsave(&mcli->curr_lock, flags); |
| 682 | | − list_add(&midev->list, &mcli->devs); |
| 683 | | − // Select a device by default |
| 684 | | − if (!mcli->sel) |
| 685 | | − __mctp_i2c_device_select(mcli, midev); |
| 686 | | − spin_unlock_irqrestore(&mcli->curr_lock, flags); |
| 687 | | − |
| 688 | | − wake_up_process(midev->tx_thread); |
| 689 | | − |
| 690 | | − return 0; |
| 691 | | − |
| 692 | | −err_stop_kthread: |
| 693 | | − kthread_stop(midev->tx_thread); |
| 694 | | − |
| 695 | | −err_free: |
| 696 | | − free_netdev(ndev); |
| 697 | | − |
| 698 | | −err: |
| 699 | | − return rc; |
| 700 | | −} |
| 701 | | − |
| 702 | | −// Removes and unregisters a mctp-i2c netdev |
| 703 | | −static void mctp_i2c_free_netdev(struct mctp_i2c_dev *midev) |
| 704 | | −{ |
| 705 | | − struct mctp_i2c_client *mcli = midev->client; |
| 706 | | − unsigned long flags; |
| 707 | | − |
| 708 | | − netif_stop_queue(midev->ndev); |
| 709 | | − kthread_stop(midev->tx_thread); |
| 710 | | − skb_queue_purge(&midev->tx_queue); |
| 711 | | − |
| 712 | | − /* Release references, used only for TX which has stopped */ |
| 713 | | − put_device(&midev->adapter->dev); |
| 714 | | − put_device(&mcli->client->dev); |
| 715 | | − |
| 716 | | − /* Remove it from the parent mcli */ |
| 717 | | − spin_lock_irqsave(&mcli->curr_lock, flags); |
| 718 | | − list_del(&midev->list); |
| 719 | | − if (mcli->sel == midev) { |
| 720 | | − struct mctp_i2c_dev *first; |
| 721 | | − |
| 722 | | − first = list_first_entry_or_null(&mcli->devs, struct mctp_i2c_dev, list); |
| 723 | | − __mctp_i2c_device_select(mcli, first); |
| 724 | | − } |
| 725 | | − spin_unlock_irqrestore(&mcli->curr_lock, flags); |
| 726 | | − |
| 727 | | − /* Remove netdev. mctp_i2c_slave_cb() takes a dev_hold() so removing |
| 728 | | − * it now is safe. unregister_netdev() frees ndev and midev. |
| 729 | | − */ |
| 730 | | − mctp_unregister_netdev(midev->ndev); |
| 731 | | −} |
| 732 | | − |
| 733 | | −// Removes any netdev for adap. mcli is the parent root i2c client |
| 734 | | −static void mctp_i2c_remove_netdev(struct mctp_i2c_client *mcli, |
| 735 | | − struct i2c_adapter *adap) |
| 736 | | −{ |
| 737 | | − unsigned long flags; |
| 738 | | − struct mctp_i2c_dev *midev = NULL, *m = NULL; |
| 739 | | − |
| 740 | | − WARN_ON(!mutex_is_locked(&mi_driver_state.lock)); |
| 741 | | − spin_lock_irqsave(&mcli->curr_lock, flags); |
| 742 | | − // list size is limited by number of MCTP netdevs on a single hardware bus |
| 743 | | − list_for_each_entry(m, &mcli->devs, list) |
| 744 | | − if (m->adapter == adap) { |
| 745 | | − midev = m; |
| 746 | | − break; |
| 747 | | − } |
| 748 | | − spin_unlock_irqrestore(&mcli->curr_lock, flags); |
| 749 | | − |
| 750 | | − if (midev) |
| 751 | | − mctp_i2c_free_netdev(midev); |
| 752 | | −} |
| 753 | | − |
| 754 | | −/* Determines whether a device is an i2c adapter. |
| 755 | | − * Optionally returns the root i2c_adapter |
| 756 | | − */ |
| 757 | | −static struct i2c_adapter *mctp_i2c_get_adapter(struct device *dev, |
| 758 | | − struct i2c_adapter **ret_root) |
| 759 | | −{ |
| 760 | | − struct i2c_adapter *root, *adap; |
| 761 | | − |
| 762 | | − if (dev->type != &i2c_adapter_type) |
| 763 | | − return NULL; |
| 764 | | − adap = to_i2c_adapter(dev); |
| 765 | | − root = mux_root_adapter(adap); |
| 766 | | − WARN_ONCE(!root, "%s failed to find root adapter for %s\n", |
| 767 | | − __func__, dev_name(dev)); |
| 768 | | − if (!root) |
| 769 | | − return NULL; |
| 770 | | − if (ret_root) |
| 771 | | − *ret_root = root; |
| 772 | | − return adap; |
| 773 | | −} |
| 774 | | − |
| 775 | | −/* Determines whether a device is an i2c adapter with the "mctp-controller" |
| 776 | | − * devicetree property set. If adap is not an OF node, returns match_no_of |
| 777 | | − */ |
| 778 | | −static bool mctp_i2c_adapter_match(struct i2c_adapter *adap, bool match_no_of) |
| 779 | | −{ |
| 780 | | − if (!adap->dev.of_node) |
| 781 | | − return match_no_of; |
| 782 | | − return of_property_read_bool(adap->dev.of_node, MCTP_I2C_OF_PROP); |
| 783 | | −} |
| 784 | | − |
| 785 | | −/* Called for each existing i2c device (adapter or client) when a |
| 786 | | − * new mctp-i2c client is probed. |
| 787 | | − */ |
| 788 | | −static int mctp_i2c_client_try_attach(struct device *dev, void *data) |
| 789 | | −{ |
| 790 | | − struct i2c_adapter *adap = NULL, *root = NULL; |
| 791 | | − struct mctp_i2c_client *mcli = data; |
| 792 | | − |
| 793 | | − adap = mctp_i2c_get_adapter(dev, &root); |
| 794 | | − if (!adap) |
| 795 | | − return 0; |
| 796 | | − if (mcli->client->adapter != root) |
| 797 | | − return 0; |
| 798 | | − // Must either have mctp-controller property on the adapter, or |
| 799 | | − // be a root adapter if it's non-devicetree |
| 800 | | − if (!mctp_i2c_adapter_match(adap, adap == root)) |
| 801 | | − return 0; |
| 802 | | − |
| 803 | | − return mctp_i2c_add_netdev(mcli, adap); |
| 804 | | −} |
| 805 | | − |
| 806 | | −static void mctp_i2c_notify_add(struct device *dev) |
| 807 | | −{ |
| 808 | | − struct mctp_i2c_client *mcli = NULL, *m = NULL; |
| 809 | | − struct i2c_adapter *root = NULL, *adap = NULL; |
| 810 | | − int rc; |
| 811 | | − |
| 812 | | − adap = mctp_i2c_get_adapter(dev, &root); |
| 813 | | − if (!adap) |
| 814 | | − return; |
| 815 | | − // Check for mctp-controller property on the adapter |
| 816 | | − if (!mctp_i2c_adapter_match(adap, false)) |
| 817 | | − return; |
| 818 | | − |
| 819 | | − /* Find an existing mcli for adap's root */ |
| 820 | | − mutex_lock(&mi_driver_state.lock); |
| 821 | | − list_for_each_entry(m, &mi_driver_state.clients, list) { |
| 822 | | − if (m->client->adapter == root) { |
| 823 | | − mcli = m; |
| 824 | | − break; |
| 825 | | − } |
| 826 | | − } |
| 827 | | − |
| 828 | | − if (mcli) { |
| 829 | | − rc = mctp_i2c_add_netdev(mcli, adap); |
| 830 | | − if (rc) |
| 831 | | − dev_warn(dev, "%s Failed adding mctp-i2c device", |
| 832 | | − __func__); |
| 833 | | − } |
| 834 | | − mutex_unlock(&mi_driver_state.lock); |
| 835 | | −} |
| 836 | | − |
| 837 | | −static void mctp_i2c_notify_del(struct device *dev) |
| 838 | | −{ |
| 839 | | − struct i2c_adapter *root = NULL, *adap = NULL; |
| 840 | | − struct mctp_i2c_client *mcli = NULL; |
| 841 | | − |
| 842 | | − adap = mctp_i2c_get_adapter(dev, &root); |
| 843 | | − if (!adap) |
| 844 | | − return; |
| 845 | | − |
| 846 | | − mutex_lock(&mi_driver_state.lock); |
| 847 | | − list_for_each_entry(mcli, &mi_driver_state.clients, list) { |
| 848 | | − if (mcli->client->adapter == root) { |
| 849 | | − mctp_i2c_remove_netdev(mcli, adap); |
| 850 | | − break; |
| 851 | | − } |
| 852 | | − } |
| 853 | | − mutex_unlock(&mi_driver_state.lock); |
| 854 | | −} |
| 855 | | − |
| 856 | | −static int mctp_i2c_probe(struct i2c_client *client) |
| 857 | | −{ |
| 858 | | − struct mctp_i2c_client *mcli = NULL; |
| 859 | | − int rc; |
| 860 | | − |
| 861 | | − /* Check for >32 byte block support required for MCTP */ |
| 862 | | − if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_V3_BLOCK)) { |
| 863 | | − dev_err(&client->dev, |
| 864 | | − "%s failed, I2C bus driver does not support 255 byte block transfer\n", |
| 865 | | − __func__); |
| 866 | | − return -EOPNOTSUPP; |
| 867 | | − } |
| 868 | | − |
| 869 | | − mutex_lock(&mi_driver_state.lock); |
| 870 | | − mcli = mctp_i2c_new_client(client); |
| 871 | | − if (IS_ERR(mcli)) { |
| 872 | | − rc = PTR_ERR(mcli); |
| 873 | | − mcli = NULL; |
| 874 | | − goto out; |
| 875 | | − } else { |
| 876 | | − list_add(&mcli->list, &mi_driver_state.clients); |
| 877 | | − } |
| 878 | | − |
| 879 | | − // Add a netdev for adapters that have a 'mctp-controller' property |
| 880 | | − i2c_for_each_dev(mcli, mctp_i2c_client_try_attach); |
| 881 | | − rc = 0; |
| 882 | | −out: |
| 883 | | − mutex_unlock(&mi_driver_state.lock); |
| 884 | | − return rc; |
| 885 | | −} |
| 886 | | − |
| 887 | | −static int mctp_i2c_remove(struct i2c_client *client) |
| 888 | | −{ |
| 889 | | − struct mctp_i2c_client *mcli = i2c_get_clientdata(client); |
| 890 | | − struct mctp_i2c_dev *midev = NULL, *tmp = NULL; |
| 891 | | − |
| 892 | | − mutex_lock(&mi_driver_state.lock); |
| 893 | | − list_del(&mcli->list); |
| 894 | | − // Remove all child adapter netdevs |
| 895 | | − list_for_each_entry_safe(midev, tmp, &mcli->devs, list) |
| 896 | | − mctp_i2c_free_netdev(midev); |
| 897 | | − |
| 898 | | − mctp_i2c_free_client(mcli); |
| 899 | | − mutex_unlock(&mi_driver_state.lock); |
| 900 | | − // Callers ignore return code |
| 901 | | − return 0; |
| 902 | | −} |
| 903 | | − |
| 904 | | −/* We look for a 'mctp-controller' property on I2C busses as they are |
| 905 | | − * added/deleted, creating/removing netdevs as required. |
| 906 | | − */ |
| 907 | | −static int mctp_i2c_notifier_call(struct notifier_block *nb, |
| 908 | | − unsigned long action, void *data) |
| 909 | | −{ |
| 910 | | − struct device *dev = data; |
| 911 | | − |
| 912 | | − switch (action) { |
| 913 | | − case BUS_NOTIFY_ADD_DEVICE: |
| 914 | | − mctp_i2c_notify_add(dev); |
| 915 | | − break; |
| 916 | | − case BUS_NOTIFY_DEL_DEVICE: |
| 917 | | − mctp_i2c_notify_del(dev); |
| 918 | | − break; |
| 919 | | − } |
| 920 | | − return NOTIFY_DONE; |
| 921 | | −} |
| 922 | | − |
| 923 | | −static struct notifier_block mctp_i2c_notifier = { |
| 924 | | − .notifier_call = mctp_i2c_notifier_call, |
| 925 | | −}; |
| 926 | | − |
| 927 | | −static const struct i2c_device_id mctp_i2c_id[] = { |
| 928 | | − { "mctp-i2c", 0 }, |
| 929 | | − {}, |
| 930 | | −}; |
| 931 | | −MODULE_DEVICE_TABLE(i2c, mctp_i2c_id); |
| 932 | | − |
| 933 | | −static const struct of_device_id mctp_i2c_of_match[] = { |
| 934 | | − { .compatible = "mctp-i2c-controller" }, |
| 935 | | − {}, |
| 936 | | −}; |
| 937 | | −MODULE_DEVICE_TABLE(of, mctp_i2c_of_match); |
| 938 | | − |
| 939 | | −static struct i2c_driver mctp_i2c_driver = { |
| 940 | | − .driver = { |
| 941 | | − .name = "mctp-i2c", |
| 942 | | − .of_match_table = mctp_i2c_of_match, |
| 943 | | − }, |
| 944 | | − .probe_new = mctp_i2c_probe, |
| 945 | | − .remove = mctp_i2c_remove, |
| 946 | | − .id_table = mctp_i2c_id, |
| 947 | | −}; |
| 948 | | − |
| 949 | | −static __init int mctp_i2c_init(void) |
| 950 | | −{ |
| 951 | | − int rc; |
| 952 | | − |
| 953 | | − INIT_LIST_HEAD(&mi_driver_state.clients); |
| 954 | | − mutex_init(&mi_driver_state.lock); |
| 955 | | − pr_info("MCTP SMBus/I2C transport driver\n"); |
| 956 | | − rc = i2c_add_driver(&mctp_i2c_driver); |
| 957 | | − if (rc) |
| 958 | | − return rc; |
| 959 | | − rc = bus_register_notifier(&i2c_bus_type, &mctp_i2c_notifier); |
| 960 | | − if (rc) { |
| 961 | | − i2c_del_driver(&mctp_i2c_driver); |
| 962 | | − return rc; |
| 963 | | − } |
| 964 | | − return 0; |
| 965 | | −} |
| 966 | | − |
| 967 | | −static __exit void mctp_i2c_exit(void) |
| 968 | | −{ |
| 969 | | − int rc; |
| 970 | | − |
| 971 | | − rc = bus_unregister_notifier(&i2c_bus_type, &mctp_i2c_notifier); |
| 972 | | − if (rc) |
| 973 | | − pr_warn("%s Could not unregister notifier, %d", __func__, rc); |
| 974 | | − i2c_del_driver(&mctp_i2c_driver); |
| 975 | | −} |
| 976 | | − |
| 977 | | −module_init(mctp_i2c_init); |
| 978 | | −module_exit(mctp_i2c_exit); |
| 979 | | − |
| 980 | | −MODULE_DESCRIPTION("MCTP SMBus/I2C device"); |
| 981 | | −MODULE_LICENSE("GPL v2"); |
| 982 | | −MODULE_AUTHOR("Matt Johnston <matt@codeconstruct.com.au>"); |