Re: [RFC PATCH v3 9/9] ipu3-cio2: Add functionality allowing software_node connections to sensors on platforms designed for Windows

From: Dan Scally
Date: Sat Oct 24 2020 - 16:28:12 EST


On 24/10/2020 16:14, Sakari Ailus wrote:
> Hi Daniel,
>
> Thanks for the update.
Thanks for the comments as always
>> +// SPDX-License-Identifier: GPL-2.0
>> +// Author: Dan Scally <djrscally@xxxxxxxxx>
> /* Author: ... */
>
> But not the SPDX tag.
Weird - okedokey
>> +#include <linux/acpi.h>
>> +#include <linux/device.h>
>> +#include <linux/fwnode.h>
>> +#include <linux/i2c.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/pci.h>
>> +#include <linux/property.h>
>> +#include <media/v4l2-subdev.h>
>> +
>> +#include "cio2-bridge.h"
>> +
>> +/*
>> + * Extend this array with ACPI Hardware ID's of devices known to be
>> + * working
>> + */
>> +static const char * const supported_devices[] = {
>> + "INT33BE",
>> + "OVTI2680",
>> +};
>> +
>> +static struct software_node cio2_hid_node = { CIO2_HID };
>> +
>> +static struct cio2_bridge bridge;
>> +
>> +static const char * const port_names[] = {
>> + "port0", "port1", "port2", "port3"
>> +};
>> +
>> +static const struct property_entry remote_endpoints[] = {
> How about another dimension, for local and remote? Or make it a struct with
> local and remote fields. Perhaps a struct would be better?
>
> This could also be nicer to initialise in a function.
Sure; a struct probably would be cleaner I agree. I shall make that change
>> +static int create_fwnode_properties(struct sensor *sensor,
>> + struct sensor_bios_data *ssdb)
>> +{
>> + struct property_entry *cio2_properties = sensor->cio2_properties;
>> + struct property_entry *dev_properties = sensor->dev_properties;
>> + struct property_entry *ep_properties = sensor->ep_properties;
>> + int i;
>> +
>> + /* device fwnode properties */
>> + memset(dev_properties, 0, sizeof(struct property_entry) * 3);
> I'd put them all to the struct itself. Then the compiler will be able to
> check array indices.
Makes sense; I think I was just trying to save line length in the rest
of that function by that.
>> +
>> + dev_properties[0] = PROPERTY_ENTRY_U32("clock-frequency",
>> + ssdb->mclkspeed);
>> + dev_properties[1] = PROPERTY_ENTRY_U8("rotation", ssdb->degree);
>> +
>> + /* endpoint fwnode properties */
>> + memset(ep_properties, 0, sizeof(struct property_entry) * 4);
>> +
>> + sensor->data_lanes = kmalloc_array(ssdb->lanes, sizeof(u32),
>> + GFP_KERNEL);
>> +
>> + if (!sensor->data_lanes)
>> + return -ENOMEM;
>> +
>> + for (i = 0; i < ssdb->lanes; i++)
>> + sensor->data_lanes[i] = i + 1;
>> +
>> + ep_properties[0] = PROPERTY_ENTRY_U32("bus-type", 5);
>> + ep_properties[1] = PROPERTY_ENTRY_U32_ARRAY_LEN("data-lanes",
>> + sensor->data_lanes,
>> + ssdb->lanes);
>> + ep_properties[2] = remote_endpoints[(bridge.n_sensors * 2) + ENDPOINT_SENSOR];
>> +
>> + /* cio2 endpoint props */
>> + memset(cio2_properties, 0, sizeof(struct property_entry) * 3);
>> +
>> + cio2_properties[0] = PROPERTY_ENTRY_U32_ARRAY_LEN("data-lanes",
>> + sensor->data_lanes,
>> + ssdb->lanes);
>> + cio2_properties[1] = remote_endpoints[(bridge.n_sensors * 2) + ENDPOINT_CIO2];
>> +
>> + return 0;
>> +}
>> +
>> +static int create_connection_swnodes(struct sensor *sensor,
>> + struct sensor_bios_data *ssdb)
>> +{
>> + struct software_node *nodes = sensor->swnodes;
>> +
>> + memset(nodes, 0, sizeof(struct software_node) * 6);
> Could you make the index an enum, and add an item to the end used to tell
> the number of entries. It could be called e.g. NR_OF_SENSOR_SWNODES.
Ooh I like that, it's neat; thanks - will do.
>> +int cio2_bridge_build(struct pci_dev *cio2)
>> +{
>> + struct fwnode_handle *fwnode;
>> + int ret;
>> +
>> + pci_dev_get(cio2);
> Could you check that this isn't used by more than one user? The current
> implementation assumes that. I'm not sure if there could be more instances
> of CIO2 but if there were, that'd be an issue currently.

I can check; can't think of anything better than just failing out if it
turns out to be in use already though - any ideas or is that appropriate?

>> +struct sensor {
> How about calling this e.g. cio2_sensor? sensor is rather generic.
Yup, will probably prefix all such generically named vars with cio2_*
and functions with cio2_bridge_*().
>> + char name[ACPI_ID_LEN];
>> + struct device *dev;
>> + struct acpi_device *adev;
>> + struct software_node swnodes[6];
>> + struct property_entry dev_properties[3];
>> + struct property_entry ep_properties[4];
>> + struct property_entry cio2_properties[3];
>> + u32 *data_lanes;
> The maximum is four so you could as well make this static.
Ack
>> +};
>> +
>> +struct cio2_bridge {
>> + int n_sensors;
> Do you need negative values? %u, too, if not.
I do not, I will switch to using unsigned.
>> diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
>> index f68ef0f6b..827457110 100644
>> --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
>> +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
>> @@ -1715,9 +1715,27 @@ static void cio2_queues_exit(struct cio2_device *cio2)
>> static int cio2_pci_probe(struct pci_dev *pci_dev,
>> const struct pci_device_id *id)
>> {
>> + struct fwnode_handle *endpoint;
>> struct cio2_device *cio2;
>> int r;
>>
>> + /*
>> + * On some platforms no connections to sensors are defined in firmware,
>> + * if the device has no endpoints then we can try to build those as
>> + * software_nodes parsed from SSDB.
>> + *
>> + * This may EPROBE_DEFER if supported devices are found defined in ACPI
>> + * but not yet ready for use (either not attached to the i2c bus yet,
>> + * or not done probing themselves).
>> + */
>> +
>> + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&pci_dev->dev), NULL);
>> + if (!endpoint) {
>> + r = cio2_bridge_build(pci_dev);
>> + if (r)
>> + return r;
>> + }
> } else {
> fwnode_handle_put(endpoint);
> }
Ah, of course, thank you.