| @@ -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>"); | | |