mbox series

[v7,0/6] Add Intel LJCA device driver

Message ID 20230325154711.2419569-1-xiang.ye@intel.com
Headers show
Series Add Intel LJCA device driver | expand

Message

Ye Xiang March 25, 2023, 3:47 p.m. UTC
Add driver for Intel La Jolla Cove Adapter (LJCA) device.
This is a USB-GPIO, USB-I2C and USB-SPI device. We add 4
drivers to support this device: a USB driver, a GPIO chip
driver, a I2C controller driver and a SPI controller driver.

---
v7:
 - ljca: remove unused field `udev` in struct ljca_dev.
 - ljca: rename ljca module name to usb-ljca.
 - ljca: use CONFIG_ACPI to enclose acpi related code.
 - ljca/gpio/i2c/spi: aligh MACRO defination.

v6:
 - ljca: split LJCA USB driver into two commits: USB part and API part.
 - gpio/i2c/spi: use auxiliary bus for sub-module device enumeration instead of MFD.
 - move document patch for LJCA sysfs entry to the 3th patch of this patch series.
 - ljca: fix potential race condition when wait response timeout.
 - ljca: use devm_kzalloc to malloc ljca device struct. 

v5:
 - move ljca.h from drivers/include/mfd to drivers/include/usb.
 - ljca: fix a potential memory leak issue.
 - add a blank line before return to adust to kernel code style.
 - ljca: sysfs: split "cmd" to "ljca_dfu" and "ljca_trace_level".

v4:
 - move ljca.c from drivers/mfd to drivers/usb/misc folder.
 - fix index warning in sysfs-bus-devices-ljca.

v3:
 - spi: make ljca_spi_transfer inline and fix an endian issue.

v2:
 - ljca: remove reset command.
 - gpio/spi/i2c: add `default MFD_LJCA` in Kconfig.
 - gpio: add "select GPIOLIB_IRQCHIP" in Kconfig.

Ye Xiang (6):
  usb: Add support for Intel LJCA device
  usb: ljca: Add transport interfaces for sub-module drivers
  Documentation: Add ABI doc for attributes of LJCA device
  gpio: Add support for Intel LJCA USB GPIO driver
  i2c: Add support for Intel LJCA USB I2C driver
  spi: Add support for Intel LJCA USB SPI driver

 .../ABI/testing/sysfs-bus-usb-devices-ljca    |   36 +
 drivers/gpio/Kconfig                          |   12 +
 drivers/gpio/Makefile                         |    1 +
 drivers/gpio/gpio-ljca.c                      |  458 ++++++++
 drivers/i2c/busses/Kconfig                    |   11 +
 drivers/i2c/busses/Makefile                   |    1 +
 drivers/i2c/busses/i2c-ljca.c                 |  355 ++++++
 drivers/spi/Kconfig                           |   11 +
 drivers/spi/Makefile                          |    1 +
 drivers/spi/spi-ljca.c                        |  289 +++++
 drivers/usb/misc/Kconfig                      |   13 +
 drivers/usb/misc/Makefile                     |    1 +
 drivers/usb/misc/usb-ljca.c                   | 1027 +++++++++++++++++
 include/linux/usb/ljca.h                      |   95 ++
 14 files changed, 2311 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-usb-devices-ljca
 create mode 100644 drivers/gpio/gpio-ljca.c
 create mode 100644 drivers/i2c/busses/i2c-ljca.c
 create mode 100644 drivers/spi/spi-ljca.c
 create mode 100644 drivers/usb/misc/usb-ljca.c
 create mode 100644 include/linux/usb/ljca.h

Comments

Greg Kroah-Hartman March 25, 2023, 4:20 p.m. UTC | #1
On Sat, Mar 25, 2023 at 11:47:06PM +0800, Ye Xiang wrote:
> This patch implements the USB part of Intel USB-I2C/GPIO/SPI adapter
> device named "La Jolla Cove Adapter" (LJCA).
> 
> The communication between the various LJCA module drivers and the
> hardware will be muxed/demuxed by this driver. Three modules (
> I2C, GPIO, and SPI) are supported currently.
> 
> Each sub-module of LJCA device is identified by type field within
> the LJCA message header.
> 
> The minimum code in ASL that covers this board is

As this requires ACPI, why are you not saying so in your Kconfig entry?
What good would this driver be without ACPI enabled?

thanks,

greg k-h
Ye Xiang March 25, 2023, 5:26 p.m. UTC | #2
Hi Greg,

Thanks for the review.
On Sat, Mar 25, 2023 at 05:20:09PM +0100, Greg Kroah-Hartman wrote:
> On Sat, Mar 25, 2023 at 11:47:06PM +0800, Ye Xiang wrote:
> > This patch implements the USB part of Intel USB-I2C/GPIO/SPI adapter
> > device named "La Jolla Cove Adapter" (LJCA).
> > 
> > The communication between the various LJCA module drivers and the
> > hardware will be muxed/demuxed by this driver. Three modules (
> > I2C, GPIO, and SPI) are supported currently.
> > 
> > Each sub-module of LJCA device is identified by type field within
> > the LJCA message header.
> > 
> > The minimum code in ASL that covers this board is
> 
> As this requires ACPI, why are you not saying so in your Kconfig entry?
I would add a `depends on ACPI` item on the Kconfig entry so that the
CONFI_ACPI macro can be removed from usb-ljca, because our use case with
LJCA currently needs the ACPI binding.
> What good would this driver be without ACPI enabled?
Before, I just tried to make it compatible with other platforms that
don't support ACPI but want to use LJCA device. But, We don't have
this use case until now.

Thanks
Ye Xiang
Greg Kroah-Hartman March 25, 2023, 5:35 p.m. UTC | #3
On Sun, Mar 26, 2023 at 01:26:55AM +0800, Ye, Xiang wrote:
> Hi Greg,
> 
> Thanks for the review.
> On Sat, Mar 25, 2023 at 05:20:09PM +0100, Greg Kroah-Hartman wrote:
> > On Sat, Mar 25, 2023 at 11:47:06PM +0800, Ye Xiang wrote:
> > > This patch implements the USB part of Intel USB-I2C/GPIO/SPI adapter
> > > device named "La Jolla Cove Adapter" (LJCA).
> > > 
> > > The communication between the various LJCA module drivers and the
> > > hardware will be muxed/demuxed by this driver. Three modules (
> > > I2C, GPIO, and SPI) are supported currently.
> > > 
> > > Each sub-module of LJCA device is identified by type field within
> > > the LJCA message header.
> > > 
> > > The minimum code in ASL that covers this board is
> > 
> > As this requires ACPI, why are you not saying so in your Kconfig entry?
> I would add a `depends on ACPI` item on the Kconfig entry so that the
> CONFI_ACPI macro can be removed from usb-ljca, because our use case with
> LJCA currently needs the ACPI binding.

That would make more sense.

thanks,

greg k-h
Mark Brown March 25, 2023, 6:05 p.m. UTC | #4
On Sun, Mar 26, 2023 at 01:26:55AM +0800, Ye, Xiang wrote:
> On Sat, Mar 25, 2023 at 05:20:09PM +0100, Greg Kroah-Hartman wrote:

> > As this requires ACPI, why are you not saying so in your Kconfig entry?

> I would add a `depends on ACPI` item on the Kconfig entry so that the
> CONFI_ACPI macro can be removed from usb-ljca, because our use case with

> LJCA currently needs the ACPI binding.

> > What good would this driver be without ACPI enabled?
> Before, I just tried to make it compatible with other platforms that
> don't support ACPI but want to use LJCA device. But, We don't have
> this use case until now.

If it builds without ACPI then making the dependency ACPI ||
COMPILE_TEST will help improve build coverage for people doing
treewide or subsystem work.
Greg Kroah-Hartman March 25, 2023, 10:27 p.m. UTC | #5
On Sat, Mar 25, 2023 at 11:47:06PM +0800, Ye Xiang wrote:
> +static void ljca_aux_release(struct device *dev) {}

Sorry, but creating an empty release function just to shut the kernel up
is NOT how to properly do this, you all know better.  This is totally
broken.  The kernel was telling you what you had to do, don't think that
you are being smarter than it by doing this, otherwise we would have
never had the kernel spit out that error in the first place, right?

Now I will ask you to follow the proper Intel kernel review rules and
get proper approval for the patchset before submitting it to us again,
as basic things like this are not supposed to be caught by us, but by
your internal review process first.

good luck!

greg k-h
Ye Xiang March 26, 2023, 9:04 a.m. UTC | #6
On Sat, Mar 25, 2023 at 11:27:03PM +0100, Greg Kroah-Hartman wrote:
> On Sat, Mar 25, 2023 at 11:47:06PM +0800, Ye Xiang wrote:
> > +static void ljca_aux_release(struct device *dev) {}
> 
> Sorry, but creating an empty release function just to shut the kernel up
> is NOT how to properly do this, you all know better.  This is totally
> broken.  The kernel was telling you what you had to do, don't think that
> you are being smarter than it by doing this, otherwise we would have
> never had the kernel spit out that error in the first place, right?
Got it. Will use the release callback to free memory used by the auxiliary
device instead.
> 
> Now I will ask you to follow the proper Intel kernel review rules and
> get proper approval for the patchset before submitting it to us again,
> as basic things like this are not supposed to be caught by us, but by
> your internal review process first.
Thanks. I will get approval on Intel's internal review first before sending
the next version out for review.

--
Thanks
Ye Xiang
Oliver Neukum March 27, 2023, 11:08 a.m. UTC | #7
On 25.03.23 16:47, Ye Xiang wrote:

Hi,

> +static int ljca_parse(struct ljca_dev *dev, struct ljca_msg *header)
> +{
> +	struct ljca_stub *stub;
> +
> +	stub = ljca_stub_find(dev, header->type);
> +	if (IS_ERR(stub))
> +		return PTR_ERR(stub);
> +
> +	if (!(header->flags & LJCA_ACK_FLAG)) {
> +		ljca_stub_notify(stub, header->cmd, header->data, header->len);
> +		return 0;
> +	}
> +
> +	if (stub->cur_cmd != header->cmd) {
> +		dev_err(&dev->intf->dev, "header and stub current command mismatch (%x vs %x)\n",
> +			header->cmd, stub->cur_cmd);
> +		return -EINVAL;
> +	}
> +
> +	if (stub->ipacket.ibuf && stub->ipacket.ibuf_len) {

Here you read those values from ipacket.

> +		unsigned int newlen;
> +
> +		newlen = min_t(unsigned int, header->len, *stub->ipacket.ibuf_len);

Here you read them again.

> +
> +		*stub->ipacket.ibuf_len = newlen;
> +		memcpy(stub->ipacket.ibuf, header->data, newlen);

And here you read them again. The compiler is free to generate a memory access for
ipacket.ibuf, which may read a new value from RAM. That means here you have a window
in which you can no longer guarantee stub->ipacket.ibuf != NULL,
if you set it to NULL elsewhere.

> +	}
> +
> +	stub->acked = true;
> +	wake_up(&dev->ack_wq);
> +
> +	return 0;
> +}
> +
> +static int ljca_stub_write(struct ljca_stub *stub, u8 cmd, const void *obuf, unsigned int obuf_len,
> +			   void *ibuf, unsigned int *ibuf_len, bool wait_ack, unsigned long timeout)
> +{
> +	struct ljca_dev *dev = usb_get_intfdata(stub->intf);
> +	u8 flags = LJCA_CMPL_FLAG;
> +	struct ljca_msg *header;
> +	unsigned int msg_len = sizeof(*header) + obuf_len;
> +	int actual;
> +	int ret;
> +
> +	if (msg_len > LJCA_MAX_PACKET_SIZE)
> +		return -EINVAL;
> +
> +	if (wait_ack)
> +		flags |= LJCA_ACK_FLAG;
> +
> +	header = kmalloc(msg_len, GFP_KERNEL);
> +	if (!header)
> +		return -ENOMEM;
> +
> +	header->type = stub->type;
> +	header->cmd = cmd;
> +	header->flags = flags;
> +	header->len = obuf_len;
> +
> +	if (obuf)
> +		memcpy(header->data, obuf, obuf_len);
> +
> +	dev_dbg(&dev->intf->dev, "send: type:%d cmd:%d flags:%d len:%d\n", header->type,
> +		header->cmd, header->flags, header->len);
> +
> +	usb_autopm_get_interface(dev->intf);
> +	if (!dev->started) {
> +		kfree(header);
> +		ret = -ENODEV;
> +		goto error_put;
> +	}
> +
> +	mutex_lock(&dev->mutex);
> +	stub->cur_cmd = cmd;
> +	stub->ipacket.ibuf = ibuf;
> +	stub->ipacket.ibuf_len = ibuf_len;
> +	stub->acked = false;
> +	ret = usb_bulk_msg(interface_to_usbdev(dev->intf),
> +			   usb_sndbulkpipe(interface_to_usbdev(dev->intf), dev->out_ep), header,
> +			   msg_len, &actual, LJCA_USB_WRITE_TIMEOUT_MS);
> +	kfree(header);
> +	if (ret) {
> +		dev_err(&dev->intf->dev, "bridge write failed ret:%d\n", ret);
> +		goto error_unlock;
> +	}
> +
> +	if (actual != msg_len) {
> +		dev_err(&dev->intf->dev, "bridge write length mismatch (%d vs %d)\n", msg_len,
> +			actual);
> +		ret = -EINVAL;
> +		goto error_unlock;
> +	}
> +
> +	if (wait_ack) {
> +		ret = wait_event_timeout(dev->ack_wq, stub->acked, msecs_to_jiffies(timeout));
> +		if (!ret) {
> +			dev_err(&dev->intf->dev, "acked wait timeout\n");
> +			ret = -ETIMEDOUT;
> +			goto error_unlock;
> +		}
> +	}
> +
> +	ret = 0;
> +error_unlock:
> +	stub->ipacket.ibuf = NULL;
> +	stub->ipacket.ibuf_len = NULL;

And here you set stub->ipacket.ibuf to NULL.
If you do that and want consistency, you'll need to use READ_ONCE
and a local variable if you read this in interrupt.

> +	mutex_unlock(&dev->mutex);
> +error_put:
> +	usb_autopm_put_interface(dev->intf);
> +
> +	return ret;
> +}
> +

	HTH,
		Oliver