Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Intel On Demand (Software Defined Silicon) driver
4 *
5 * Copyright (c) 2022, Intel Corporation.
6 * All Rights Reserved.
7 *
8 * Author: "David E. Box" <david.e.box@linux.intel.com>
9 */
10
11#include <linux/auxiliary_bus.h>
12#include <linux/bits.h>
13#include <linux/bitfield.h>
14#include <linux/device.h>
15#include <linux/iopoll.h>
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/overflow.h>
19#include <linux/pci.h>
20#include <linux/slab.h>
21#include <linux/sysfs.h>
22#include <linux/types.h>
23#include <linux/uaccess.h>
24
25#include "vsec.h"
26
27#define ACCESS_TYPE_BARID 2
28#define ACCESS_TYPE_LOCAL 3
29
30#define SDSI_MIN_SIZE_DWORDS 276
31#define SDSI_SIZE_MAILBOX 1024
32#define SDSI_SIZE_REGS 80
33#define SDSI_SIZE_CMD sizeof(u64)
34
35/*
36 * Write messages are currently up to the size of the mailbox
37 * while read messages are up to 4 times the size of the
38 * mailbox, sent in packets
39 */
40#define SDSI_SIZE_WRITE_MSG SDSI_SIZE_MAILBOX
41#define SDSI_SIZE_READ_MSG (SDSI_SIZE_MAILBOX * 4)
42
43#define SDSI_ENABLED_FEATURES_OFFSET 16
44#define SDSI_FEATURE_SDSI BIT(3)
45#define SDSI_FEATURE_METERING BIT(26)
46
47#define SDSI_SOCKET_ID_OFFSET 64
48#define SDSI_SOCKET_ID GENMASK(3, 0)
49
50#define SDSI_MBOX_CMD_SUCCESS 0x40
51#define SDSI_MBOX_CMD_TIMEOUT 0x80
52
53#define MBOX_TIMEOUT_US 500000
54#define MBOX_TIMEOUT_ACQUIRE_US 1000
55#define MBOX_POLLING_PERIOD_US 100
56#define MBOX_ACQUIRE_NUM_RETRIES 5
57#define MBOX_ACQUIRE_RETRY_DELAY_MS 500
58#define MBOX_MAX_PACKETS 4
59
60#define MBOX_OWNER_NONE 0x00
61#define MBOX_OWNER_INBAND 0x01
62
63#define CTRL_RUN_BUSY BIT(0)
64#define CTRL_READ_WRITE BIT(1)
65#define CTRL_SOM BIT(2)
66#define CTRL_EOM BIT(3)
67#define CTRL_OWNER GENMASK(5, 4)
68#define CTRL_COMPLETE BIT(6)
69#define CTRL_READY BIT(7)
70#define CTRL_INBAND_LOCK BIT(32)
71#define CTRL_METER_ENABLE_DRAM BIT(33)
72#define CTRL_STATUS GENMASK(15, 8)
73#define CTRL_PACKET_SIZE GENMASK(31, 16)
74#define CTRL_MSG_SIZE GENMASK(63, 48)
75
76#define DISC_TABLE_SIZE 12
77#define DT_ACCESS_TYPE GENMASK(3, 0)
78#define DT_SIZE GENMASK(27, 12)
79#define DT_TBIR GENMASK(2, 0)
80#define DT_OFFSET(v) ((v) & GENMASK(31, 3))
81
82#define SDSI_GUID_V1 0x006DD191
83#define GUID_V1_CNTRL_SIZE 8
84#define GUID_V1_REGS_SIZE 72
85#define SDSI_GUID_V2 0xF210D9EF
86#define GUID_V2_CNTRL_SIZE 16
87#define GUID_V2_REGS_SIZE 80
88
89enum sdsi_command {
90 SDSI_CMD_PROVISION_AKC = 0x0004,
91 SDSI_CMD_PROVISION_CAP = 0x0008,
92 SDSI_CMD_READ_STATE = 0x0010,
93 SDSI_CMD_READ_METER = 0x0014,
94};
95
96struct sdsi_mbox_info {
97 u64 *payload;
98 void *buffer;
99 u64 control_flags;
100 int size;
101};
102
103struct disc_table {
104 u32 access_info;
105 u32 guid;
106 u32 offset;
107};
108
109struct sdsi_priv {
110 struct mutex mb_lock; /* Mailbox access lock */
111 struct device *dev;
112 void __iomem *control_addr;
113 void __iomem *mbox_addr;
114 void __iomem *regs_addr;
115 int control_size;
116 int maibox_size;
117 int registers_size;
118 u32 guid;
119 u32 features;
120};
121
122/* SDSi mailbox operations must be performed using 64bit mov instructions */
123static __always_inline void
124sdsi_memcpy64_toio(u64 __iomem *to, const u64 *from, size_t count_bytes)
125{
126 size_t count = count_bytes / sizeof(*to);
127 int i;
128
129 for (i = 0; i < count; i++)
130 writeq(from[i], &to[i]);
131}
132
133static __always_inline void
134sdsi_memcpy64_fromio(u64 *to, const u64 __iomem *from, size_t count_bytes)
135{
136 size_t count = count_bytes / sizeof(*to);
137 int i;
138
139 for (i = 0; i < count; i++)
140 to[i] = readq(&from[i]);
141}
142
143static inline void sdsi_complete_transaction(struct sdsi_priv *priv)
144{
145 u64 control = FIELD_PREP(CTRL_COMPLETE, 1);
146
147 lockdep_assert_held(&priv->mb_lock);
148 writeq(control, priv->control_addr);
149}
150
151static int sdsi_status_to_errno(u32 status)
152{
153 switch (status) {
154 case SDSI_MBOX_CMD_SUCCESS:
155 return 0;
156 case SDSI_MBOX_CMD_TIMEOUT:
157 return -ETIMEDOUT;
158 default:
159 return -EIO;
160 }
161}
162
163static int sdsi_mbox_poll(struct sdsi_priv *priv, struct sdsi_mbox_info *info,
164 size_t *data_size)
165{
166 struct device *dev = priv->dev;
167 u32 total, loop, eom, status, message_size;
168 u64 control;
169 int ret;
170
171 lockdep_assert_held(&priv->mb_lock);
172
173 /* For reads, data sizes that are larger than the mailbox size are read in packets. */
174 total = 0;
175 loop = 0;
176 do {
177 u32 packet_size;
178
179 /* Poll on ready bit */
180 ret = readq_poll_timeout(priv->control_addr, control, control & CTRL_READY,
181 MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_US);
182 if (ret)
183 break;
184
185 eom = FIELD_GET(CTRL_EOM, control);
186 status = FIELD_GET(CTRL_STATUS, control);
187 packet_size = FIELD_GET(CTRL_PACKET_SIZE, control);
188 message_size = FIELD_GET(CTRL_MSG_SIZE, control);
189
190 ret = sdsi_status_to_errno(status);
191 if (ret)
192 break;
193
194 if (!packet_size) {
195 sdsi_complete_transaction(priv);
196 break;
197 }
198
199 /* Only the last packet can be less than the mailbox size. */
200 if (!eom && packet_size != SDSI_SIZE_MAILBOX) {
201 dev_err(dev, "Invalid packet size\n");
202 ret = -EPROTO;
203 break;
204 }
205
206 if (packet_size > SDSI_SIZE_MAILBOX) {
207 dev_err(dev, "Packet size too large\n");
208 ret = -EPROTO;
209 break;
210 }
211
212 if (info->buffer) {
213 void *buf = info->buffer + array_size(SDSI_SIZE_MAILBOX, loop);
214
215 sdsi_memcpy64_fromio(buf, priv->mbox_addr,
216 round_up(packet_size, SDSI_SIZE_CMD));
217 total += packet_size;
218 }
219
220 sdsi_complete_transaction(priv);
221 } while (!eom && ++loop < MBOX_MAX_PACKETS);
222
223 if (ret) {
224 sdsi_complete_transaction(priv);
225 return ret;
226 }
227
228 if (!eom) {
229 dev_err(dev, "Exceeded read attempts\n");
230 return -EPROTO;
231 }
232
233 /* Message size check is only valid for multi-packet transfers */
234 if (loop && total != message_size)
235 dev_warn(dev, "Read count %u differs from expected count %u\n",
236 total, message_size);
237
238 if (data_size)
239 *data_size = total;
240
241 return 0;
242}
243
244static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info,
245 size_t *data_size)
246{
247 u64 control;
248
249 lockdep_assert_held(&priv->mb_lock);
250
251 /* Format and send the read command */
252 control = FIELD_PREP(CTRL_EOM, 1) |
253 FIELD_PREP(CTRL_SOM, 1) |
254 FIELD_PREP(CTRL_RUN_BUSY, 1) |
255 FIELD_PREP(CTRL_PACKET_SIZE, info->size) |
256 info->control_flags;
257 writeq(control, priv->control_addr);
258
259 return sdsi_mbox_poll(priv, info, data_size);
260}
261
262static int sdsi_mbox_cmd_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info,
263 size_t *data_size)
264{
265 u64 control;
266
267 lockdep_assert_held(&priv->mb_lock);
268
269 /* Write rest of the payload */
270 sdsi_memcpy64_toio(priv->mbox_addr + SDSI_SIZE_CMD, info->payload + 1,
271 info->size - SDSI_SIZE_CMD);
272
273 /* Format and send the write command */
274 control = FIELD_PREP(CTRL_EOM, 1) |
275 FIELD_PREP(CTRL_SOM, 1) |
276 FIELD_PREP(CTRL_RUN_BUSY, 1) |
277 FIELD_PREP(CTRL_READ_WRITE, 1) |
278 FIELD_PREP(CTRL_MSG_SIZE, info->size) |
279 FIELD_PREP(CTRL_PACKET_SIZE, info->size);
280 writeq(control, priv->control_addr);
281
282 return sdsi_mbox_poll(priv, info, data_size);
283}
284
285static int sdsi_mbox_acquire(struct sdsi_priv *priv, struct sdsi_mbox_info *info)
286{
287 u64 control;
288 u32 owner;
289 int ret, retries = 0;
290
291 lockdep_assert_held(&priv->mb_lock);
292
293 /* Check mailbox is available */
294 control = readq(priv->control_addr);
295 owner = FIELD_GET(CTRL_OWNER, control);
296 if (owner != MBOX_OWNER_NONE)
297 return -EBUSY;
298
299 /*
300 * If there has been no recent transaction and no one owns the mailbox,
301 * we should acquire it in under 1ms. However, if we've accessed it
302 * recently it may take up to 2.1 seconds to acquire it again.
303 */
304 do {
305 /* Write first qword of payload */
306 writeq(info->payload[0], priv->mbox_addr);
307
308 /* Check for ownership */
309 ret = readq_poll_timeout(priv->control_addr, control,
310 FIELD_GET(CTRL_OWNER, control) == MBOX_OWNER_INBAND,
311 MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_ACQUIRE_US);
312
313 if (FIELD_GET(CTRL_OWNER, control) == MBOX_OWNER_NONE &&
314 retries++ < MBOX_ACQUIRE_NUM_RETRIES) {
315 msleep(MBOX_ACQUIRE_RETRY_DELAY_MS);
316 continue;
317 }
318
319 /* Either we got it or someone else did. */
320 break;
321 } while (true);
322
323 return ret;
324}
325
326static int sdsi_mbox_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info,
327 size_t *data_size)
328{
329 int ret;
330
331 lockdep_assert_held(&priv->mb_lock);
332
333 ret = sdsi_mbox_acquire(priv, info);
334 if (ret)
335 return ret;
336
337 return sdsi_mbox_cmd_write(priv, info, data_size);
338}
339
340static int sdsi_mbox_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, size_t *data_size)
341{
342 int ret;
343
344 lockdep_assert_held(&priv->mb_lock);
345
346 ret = sdsi_mbox_acquire(priv, info);
347 if (ret)
348 return ret;
349
350 return sdsi_mbox_cmd_read(priv, info, data_size);
351}
352
353static bool sdsi_ib_locked(struct sdsi_priv *priv)
354{
355 return !!FIELD_GET(CTRL_INBAND_LOCK, readq(priv->control_addr));
356}
357
358static ssize_t sdsi_provision(struct sdsi_priv *priv, char *buf, size_t count,
359 enum sdsi_command command)
360{
361 struct sdsi_mbox_info info = {};
362 int ret;
363
364 if (count > (SDSI_SIZE_WRITE_MSG - SDSI_SIZE_CMD))
365 return -EOVERFLOW;
366
367 /* Make sure In-band lock is not set */
368 if (sdsi_ib_locked(priv))
369 return -EPERM;
370
371 /* Qword aligned message + command qword */
372 info.size = round_up(count, SDSI_SIZE_CMD) + SDSI_SIZE_CMD;
373
374 info.payload = kzalloc(info.size, GFP_KERNEL);
375 if (!info.payload)
376 return -ENOMEM;
377
378 /* Copy message to payload buffer */
379 memcpy(info.payload, buf, count);
380
381 /* Command is last qword of payload buffer */
382 info.payload[(info.size - SDSI_SIZE_CMD) / SDSI_SIZE_CMD] = command;
383
384 ret = mutex_lock_interruptible(&priv->mb_lock);
385 if (ret)
386 goto free_payload;
387
388 ret = sdsi_mbox_write(priv, &info, NULL);
389
390 mutex_unlock(&priv->mb_lock);
391
392free_payload:
393 kfree(info.payload);
394
395 if (ret)
396 return ret;
397
398 return count;
399}
400
401static ssize_t provision_akc_write(struct file *filp, struct kobject *kobj,
402 struct bin_attribute *attr, char *buf, loff_t off,
403 size_t count)
404{
405 struct device *dev = kobj_to_dev(kobj);
406 struct sdsi_priv *priv = dev_get_drvdata(dev);
407
408 if (off)
409 return -ESPIPE;
410
411 return sdsi_provision(priv, buf, count, SDSI_CMD_PROVISION_AKC);
412}
413static BIN_ATTR_WO(provision_akc, SDSI_SIZE_WRITE_MSG);
414
415static ssize_t provision_cap_write(struct file *filp, struct kobject *kobj,
416 struct bin_attribute *attr, char *buf, loff_t off,
417 size_t count)
418{
419 struct device *dev = kobj_to_dev(kobj);
420 struct sdsi_priv *priv = dev_get_drvdata(dev);
421
422 if (off)
423 return -ESPIPE;
424
425 return sdsi_provision(priv, buf, count, SDSI_CMD_PROVISION_CAP);
426}
427static BIN_ATTR_WO(provision_cap, SDSI_SIZE_WRITE_MSG);
428
429static ssize_t
430certificate_read(u64 command, u64 control_flags, struct sdsi_priv *priv,
431 char *buf, loff_t off, size_t count)
432{
433 struct sdsi_mbox_info info = {};
434 size_t size;
435 int ret;
436
437 if (off)
438 return 0;
439
440 /* Buffer for return data */
441 info.buffer = kmalloc(SDSI_SIZE_READ_MSG, GFP_KERNEL);
442 if (!info.buffer)
443 return -ENOMEM;
444
445 info.payload = &command;
446 info.size = sizeof(command);
447 info.control_flags = control_flags;
448
449 ret = mutex_lock_interruptible(&priv->mb_lock);
450 if (ret)
451 goto free_buffer;
452 ret = sdsi_mbox_read(priv, &info, &size);
453 mutex_unlock(&priv->mb_lock);
454 if (ret < 0)
455 goto free_buffer;
456
457 if (size > count)
458 size = count;
459
460 memcpy(buf, info.buffer, size);
461
462free_buffer:
463 kfree(info.buffer);
464
465 if (ret)
466 return ret;
467
468 return size;
469}
470
471static ssize_t
472state_certificate_read(struct file *filp, struct kobject *kobj,
473 struct bin_attribute *attr, char *buf, loff_t off,
474 size_t count)
475{
476 struct device *dev = kobj_to_dev(kobj);
477 struct sdsi_priv *priv = dev_get_drvdata(dev);
478
479 return certificate_read(SDSI_CMD_READ_STATE, 0, priv, buf, off, count);
480}
481static BIN_ATTR_ADMIN_RO(state_certificate, SDSI_SIZE_READ_MSG);
482
483static ssize_t
484meter_certificate_read(struct file *filp, struct kobject *kobj,
485 struct bin_attribute *attr, char *buf, loff_t off,
486 size_t count)
487{
488 struct device *dev = kobj_to_dev(kobj);
489 struct sdsi_priv *priv = dev_get_drvdata(dev);
490
491 return certificate_read(SDSI_CMD_READ_METER, 0, priv, buf, off, count);
492}
493static BIN_ATTR_ADMIN_RO(meter_certificate, SDSI_SIZE_READ_MSG);
494
495static ssize_t
496meter_current_read(struct file *filp, struct kobject *kobj,
497 struct bin_attribute *attr, char *buf, loff_t off,
498 size_t count)
499{
500 struct device *dev = kobj_to_dev(kobj);
501 struct sdsi_priv *priv = dev_get_drvdata(dev);
502
503 return certificate_read(SDSI_CMD_READ_METER, CTRL_METER_ENABLE_DRAM,
504 priv, buf, off, count);
505}
506static BIN_ATTR_ADMIN_RO(meter_current, SDSI_SIZE_READ_MSG);
507
508static ssize_t registers_read(struct file *filp, struct kobject *kobj,
509 struct bin_attribute *attr, char *buf, loff_t off,
510 size_t count)
511{
512 struct device *dev = kobj_to_dev(kobj);
513 struct sdsi_priv *priv = dev_get_drvdata(dev);
514 void __iomem *addr = priv->regs_addr;
515 int size = priv->registers_size;
516
517 /*
518 * The check below is performed by the sysfs caller based on the static
519 * file size. But this may be greater than the actual size which is based
520 * on the GUID. So check here again based on actual size before reading.
521 */
522 if (off >= size)
523 return 0;
524
525 if (off + count > size)
526 count = size - off;
527
528 memcpy_fromio(buf, addr + off, count);
529
530 return count;
531}
532static BIN_ATTR_ADMIN_RO(registers, SDSI_SIZE_REGS);
533
534static struct bin_attribute *sdsi_bin_attrs[] = {
535 &bin_attr_registers,
536 &bin_attr_state_certificate,
537 &bin_attr_meter_certificate,
538 &bin_attr_meter_current,
539 &bin_attr_provision_akc,
540 &bin_attr_provision_cap,
541 NULL
542};
543
544static umode_t
545sdsi_battr_is_visible(struct kobject *kobj, struct bin_attribute *attr, int n)
546{
547 struct device *dev = kobj_to_dev(kobj);
548 struct sdsi_priv *priv = dev_get_drvdata(dev);
549
550 /* Registers file is always readable if the device is present */
551 if (attr == &bin_attr_registers)
552 return attr->attr.mode;
553
554 /* All other attributes not visible if BIOS has not enabled On Demand */
555 if (!(priv->features & SDSI_FEATURE_SDSI))
556 return 0;
557
558 if (attr == &bin_attr_meter_certificate || attr == &bin_attr_meter_current)
559 return (priv->features & SDSI_FEATURE_METERING) ?
560 attr->attr.mode : 0;
561
562 return attr->attr.mode;
563}
564
565static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf)
566{
567 struct sdsi_priv *priv = dev_get_drvdata(dev);
568
569 return sysfs_emit(buf, "0x%x\n", priv->guid);
570}
571static DEVICE_ATTR_RO(guid);
572
573static struct attribute *sdsi_attrs[] = {
574 &dev_attr_guid.attr,
575 NULL
576};
577
578static const struct attribute_group sdsi_group = {
579 .attrs = sdsi_attrs,
580 .bin_attrs = sdsi_bin_attrs,
581 .is_bin_visible = sdsi_battr_is_visible,
582};
583__ATTRIBUTE_GROUPS(sdsi);
584
585static int sdsi_get_layout(struct sdsi_priv *priv, struct disc_table *table)
586{
587 switch (table->guid) {
588 case SDSI_GUID_V1:
589 priv->control_size = GUID_V1_CNTRL_SIZE;
590 priv->registers_size = GUID_V1_REGS_SIZE;
591 break;
592 case SDSI_GUID_V2:
593 priv->control_size = GUID_V2_CNTRL_SIZE;
594 priv->registers_size = GUID_V2_REGS_SIZE;
595 break;
596 default:
597 dev_err(priv->dev, "Unrecognized GUID 0x%x\n", table->guid);
598 return -EINVAL;
599 }
600 return 0;
601}
602
603static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *parent,
604 struct disc_table *disc_table, struct resource *disc_res)
605{
606 u32 access_type = FIELD_GET(DT_ACCESS_TYPE, disc_table->access_info);
607 u32 size = FIELD_GET(DT_SIZE, disc_table->access_info);
608 u32 tbir = FIELD_GET(DT_TBIR, disc_table->offset);
609 u32 offset = DT_OFFSET(disc_table->offset);
610 struct resource res = {};
611
612 /* Starting location of SDSi MMIO region based on access type */
613 switch (access_type) {
614 case ACCESS_TYPE_LOCAL:
615 if (tbir) {
616 dev_err(priv->dev, "Unsupported BAR index %u for access type %u\n",
617 tbir, access_type);
618 return -EINVAL;
619 }
620
621 /*
622 * For access_type LOCAL, the base address is as follows:
623 * base address = end of discovery region + base offset + 1
624 */
625 res.start = disc_res->end + offset + 1;
626 break;
627
628 case ACCESS_TYPE_BARID:
629 res.start = pci_resource_start(parent, tbir) + offset;
630 break;
631
632 default:
633 dev_err(priv->dev, "Unrecognized access_type %u\n", access_type);
634 return -EINVAL;
635 }
636
637 res.end = res.start + size * sizeof(u32) - 1;
638 res.flags = IORESOURCE_MEM;
639
640 priv->control_addr = devm_ioremap_resource(priv->dev, &res);
641 if (IS_ERR(priv->control_addr))
642 return PTR_ERR(priv->control_addr);
643
644 priv->mbox_addr = priv->control_addr + priv->control_size;
645 priv->regs_addr = priv->mbox_addr + SDSI_SIZE_MAILBOX;
646
647 priv->features = readq(priv->regs_addr + SDSI_ENABLED_FEATURES_OFFSET);
648
649 return 0;
650}
651
652static int sdsi_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id)
653{
654 struct intel_vsec_device *intel_cap_dev = auxdev_to_ivdev(auxdev);
655 struct disc_table disc_table;
656 struct resource *disc_res;
657 void __iomem *disc_addr;
658 struct sdsi_priv *priv;
659 int ret;
660
661 priv = devm_kzalloc(&auxdev->dev, sizeof(*priv), GFP_KERNEL);
662 if (!priv)
663 return -ENOMEM;
664
665 priv->dev = &auxdev->dev;
666 mutex_init(&priv->mb_lock);
667 auxiliary_set_drvdata(auxdev, priv);
668
669 /* Get the SDSi discovery table */
670 disc_res = &intel_cap_dev->resource[0];
671 disc_addr = devm_ioremap_resource(&auxdev->dev, disc_res);
672 if (IS_ERR(disc_addr))
673 return PTR_ERR(disc_addr);
674
675 memcpy_fromio(&disc_table, disc_addr, DISC_TABLE_SIZE);
676
677 priv->guid = disc_table.guid;
678
679 /* Get guid based layout info */
680 ret = sdsi_get_layout(priv, &disc_table);
681 if (ret)
682 return ret;
683
684 /* Map the SDSi mailbox registers */
685 ret = sdsi_map_mbox_registers(priv, intel_cap_dev->pcidev, &disc_table, disc_res);
686 if (ret)
687 return ret;
688
689 return 0;
690}
691
692static const struct auxiliary_device_id sdsi_aux_id_table[] = {
693 { .name = "intel_vsec.sdsi" },
694 {}
695};
696MODULE_DEVICE_TABLE(auxiliary, sdsi_aux_id_table);
697
698static struct auxiliary_driver sdsi_aux_driver = {
699 .driver = {
700 .dev_groups = sdsi_groups,
701 },
702 .id_table = sdsi_aux_id_table,
703 .probe = sdsi_probe,
704 /* No remove. All resources are handled under devm */
705};
706module_auxiliary_driver(sdsi_aux_driver);
707
708MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
709MODULE_DESCRIPTION("Intel On Demand (SDSi) driver");
710MODULE_LICENSE("GPL");