Skip to content

Commit

Permalink
misc: surface_sam: Update based on module
Browse files Browse the repository at this point in the history
Update Surface System Aggregator Module driver based on module.

Changes:
- Fix bug in packet submission leading to a potential deadlock when
  packets need to be resent in constested situations
- Misc. other fixes.
- Rename surface_aggregator_debugfs module to surface_aggregator_cdev
  and make it a proper character device (miscdevice).
- Add copyright notices.
- Continued cleanup and code improvements.

Links:
- SAM: linux-surface/surface-aggregator-module@47bb8f0
  • Loading branch information
qzed committed Oct 1, 2020
1 parent 62d3bd8 commit 674e306
Show file tree
Hide file tree
Showing 32 changed files with 855 additions and 664 deletions.
4 changes: 3 additions & 1 deletion drivers/misc/surface_aggregator/Kconfig
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>

menuconfig SURFACE_AGGREGATOR
tristate "Microsoft Surface System Aggregator Module Subsystem and Drivers"
depends on SERIAL_DEV_BUS
Expand Down Expand Up @@ -51,7 +54,6 @@ config SURFACE_AGGREGATOR_ERROR_INJECTION
bool "Surface System Aggregator Module Error Injection Capabilities"
depends on SURFACE_AGGREGATOR
depends on FUNCTION_ERROR_INJECTION
default n
help
Provides error-injection capabilities for the Surface System
Aggregator Module subsystem and Surface Serial Hub driver.
Expand Down
1 change: 1 addition & 0 deletions drivers/misc/surface_aggregator/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>

# For include/trace/define_trace.h to include trace.h
CFLAGS_core.o = -I$(src)
Expand Down
7 changes: 6 additions & 1 deletion drivers/misc/surface_aggregator/bus.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Surface System Aggregator Module bus and device integration.
*
* Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
*/

#include <linux/device.h>
#include <linux/slab.h>
Expand Down Expand Up @@ -139,7 +144,7 @@ int ssam_device_add(struct ssam_device *sdev)
*/
ssam_controller_statelock(sdev->ctrl);

if (READ_ONCE(sdev->ctrl->state) != SSAM_CONTROLLER_STARTED) {
if (sdev->ctrl->state != SSAM_CONTROLLER_STARTED) {
ssam_controller_stateunlock(sdev->ctrl);
return -ENXIO;
}
Expand Down
5 changes: 5 additions & 0 deletions drivers/misc/surface_aggregator/bus.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Surface System Aggregator Module bus and device integration.
*
* Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
*/

#ifndef _SURFACE_AGGREGATOR_BUS_H
#define _SURFACE_AGGREGATOR_BUS_H
Expand Down
27 changes: 14 additions & 13 deletions drivers/misc/surface_aggregator/clients/Kconfig
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
config SURFACE_AGGREGATOR_DEBUGFS
tristate "Surface System Aggregator Module DebugFS interface"
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>

config SURFACE_AGGREGATOR_CDEV
tristate "Surface System Aggregator Module User-Space Interface"
depends on SURFACE_AGGREGATOR
depends on DEBUG_FS
default n
help
Provides a DebugFS interface to the Surface System Aggregator Module
(SSAM) controller.

This option provides a module (called surface_aggregator_debugfs),
that, when loaded, will add a client device (and its respective
driver) to the SSAM controller. Said client device manages a DebugFS
interface (/sys/kernel/debug/surface_aggregator/controller), which can
be used by user-space tools to directly communicate with the SSAM EC
by sending requests and receiving the correspondign responses.
Provides a misc-device interface to the Surface System Aggregator
Module (SSAM) controller.

This option provides a module (called surface_aggregator_cdev), that,
when loaded, will add a client device (and its respective driver) to
the SSAM controller. Said client device manages a misc-device
interface (/dev/surface/aggregator), which can be used by user-space
tools to directly communicate with the SSAM EC by sending requests and
receiving the correspondign responses.

The provided interface is intended for debugging and development only,
and should not be used otherwise.
Expand Down
3 changes: 2 additions & 1 deletion drivers/misc/surface_aggregator/clients/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>

obj-$(CONFIG_SURFACE_AGGREGATOR_DEBUGFS) += surface_aggregator_debugfs.o
obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o
obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o
obj-$(CONFIG_SURFACE_ACPI_NOTIFY) += surface_acpi_notify.o
obj-$(CONFIG_SURFACE_BATTERY) += surface_battery.o
Expand Down
2 changes: 2 additions & 0 deletions drivers/misc/surface_aggregator/clients/surface_acpi_notify.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* events back to ACPI notifications. Allows handling of discrete GPU
* notifications sent from ACPI via the SAN interface by providing them to any
* registered external driver.
*
* Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
*/

#include <asm/unaligned.h>
Expand Down
228 changes: 228 additions & 0 deletions drivers/misc/surface_aggregator/clients/surface_aggregator_cdev.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Provides user-space access to the SSAM EC via the /dev/surface/aggregator
* misc device. Intended for debugging and development.
*
* Copyright (C) 2020 Maximilian Luz <luzmaximilian@gmail.com>
*/

#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#include <linux/surface_aggregator/cdev.h>
#include <linux/surface_aggregator/controller.h>

#define SSAM_CDEV_DEVICE_NAME "surface_aggregator_cdev"

struct ssam_cdev {
struct ssam_controller *ctrl;
struct miscdevice mdev;
};

static int ssam_cdev_device_open(struct inode *inode, struct file *filp)
{
struct miscdevice *mdev = filp->private_data;

filp->private_data = container_of(mdev, struct ssam_cdev, mdev);
return nonseekable_open(inode, filp);
}

static long ssam_cdev_request(struct file *file, unsigned long arg)
{
struct ssam_cdev *cdev = file->private_data;
struct ssam_cdev_request __user *r;
struct ssam_cdev_request rqst;
struct ssam_request spec;
struct ssam_response rsp;
const void __user *plddata;
void __user *rspdata;
int status = 0, ret = 0, tmp;

r = (struct ssam_cdev_request __user *)arg;
ret = copy_struct_from_user(&rqst, sizeof(rqst), r, sizeof(*r));
if (ret)
goto out;

plddata = u64_to_user_ptr(rqst.payload.data);
rspdata = u64_to_user_ptr(rqst.response.data);

// setup basic request fields
spec.target_category = rqst.target_category;
spec.target_id = rqst.target_id;
spec.command_id = rqst.command_id;
spec.instance_id = rqst.instance_id;
spec.flags = rqst.flags;
spec.length = rqst.payload.length;
spec.payload = NULL;

rsp.capacity = rqst.response.length;
rsp.length = 0;
rsp.pointer = NULL;

// get request payload from user-space
if (spec.length) {
if (!plddata) {
ret = -EINVAL;
goto out;
}

spec.payload = kzalloc(spec.length, GFP_KERNEL);
if (!spec.payload) {
status = -ENOMEM;
ret = -EFAULT;
goto out;
}

if (copy_from_user((void *)spec.payload, plddata, spec.length)) {
ret = -EFAULT;
goto out;
}
}

// allocate response buffer
if (rsp.capacity) {
if (!rspdata) {
ret = -EINVAL;
goto out;
}

rsp.pointer = kzalloc(rsp.capacity, GFP_KERNEL);
if (!rsp.pointer) {
status = -ENOMEM;
ret = -EFAULT;
goto out;
}
}

// perform request
status = ssam_request_sync(cdev->ctrl, &spec, &rsp);
if (status)
goto out;

// copy response to user-space
if (rsp.length && copy_to_user(rspdata, rsp.pointer, rsp.length))
ret = -EFAULT;

out:
// always try to set response-length and status
tmp = put_user(rsp.length, &r->response.length);
if (tmp)
ret = tmp;

tmp = put_user(status, &r->status);
if (tmp)
ret = tmp;

// cleanup
kfree(spec.payload);
kfree(rsp.pointer);

return ret;
}

static long ssam_cdev_device_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
case SSAM_CDEV_REQUEST:
return ssam_cdev_request(file, arg);

default:
return -ENOTTY;
}
}

static const struct file_operations ssam_controller_fops = {
.owner = THIS_MODULE,
.open = ssam_cdev_device_open,
.unlocked_ioctl = ssam_cdev_device_ioctl,
.compat_ioctl = ssam_cdev_device_ioctl,
.llseek = noop_llseek,
};

static int ssam_dbg_device_probe(struct platform_device *pdev)
{
struct ssam_controller *ctrl;
struct ssam_cdev *cdev;
int status;

status = ssam_client_bind(&pdev->dev, &ctrl);
if (status)
return status == -ENXIO ? -EPROBE_DEFER : status;

cdev = devm_kzalloc(&pdev->dev, sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return -ENOMEM;

cdev->ctrl = ctrl;
cdev->mdev.parent = &pdev->dev;
cdev->mdev.minor = MISC_DYNAMIC_MINOR;
cdev->mdev.name = "surface_aggregator";
cdev->mdev.nodename = "surface/aggregator";
cdev->mdev.fops = &ssam_controller_fops;

platform_set_drvdata(pdev, cdev);
return misc_register(&cdev->mdev);
}

static int ssam_dbg_device_remove(struct platform_device *pdev)
{
struct ssam_cdev *cdev = platform_get_drvdata(pdev);

misc_deregister(&cdev->mdev);
return 0;
}

static struct platform_device *ssam_cdev_device;

static struct platform_driver ssam_cdev_driver = {
.probe = ssam_dbg_device_probe,
.remove = ssam_dbg_device_remove,
.driver = {
.name = SSAM_CDEV_DEVICE_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};

static int __init ssam_debug_init(void)
{
int status;

ssam_cdev_device = platform_device_alloc(SSAM_CDEV_DEVICE_NAME,
PLATFORM_DEVID_NONE);
if (!ssam_cdev_device)
return -ENOMEM;

status = platform_device_add(ssam_cdev_device);
if (status)
goto err_device;

status = platform_driver_register(&ssam_cdev_driver);
if (status)
goto err_driver;

return 0;

err_driver:
platform_device_del(ssam_cdev_device);
err_device:
platform_device_put(ssam_cdev_device);
return status;
}
module_init(ssam_debug_init);

static void __exit ssam_debug_exit(void)
{
platform_driver_unregister(&ssam_cdev_driver);
platform_device_unregister(ssam_cdev_device);
}
module_exit(ssam_debug_exit);

MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
MODULE_DESCRIPTION("User-space interface for Surface System Aggregator Module");
MODULE_LICENSE("GPL");
Loading

0 comments on commit 674e306

Please sign in to comment.