Re: [PATCH v2 1/4] platform/x86: simatic-ipc: add main driver for Siemens devices

From: Andy Shevchenko
Date: Mon Mar 15 2021 - 06:32:27 EST


On Mon, Mar 15, 2021 at 12:02 PM Henning Schild
<henning.schild@xxxxxxxxxxx> wrote:
>
> This mainly implements detection of these devices and will allow
> secondary drivers to work on such machines.
>
> The identification is DMI-based with a vendor specific way to tell them
> apart in a reliable way.
>
> Drivers for LEDs and Watchdogs will follow to make use of that platform
> detection.

...

> +static int register_platform_devices(u32 station_id)
> +{
> + u8 ledmode = SIMATIC_IPC_DEVICE_NONE;
> + u8 wdtmode = SIMATIC_IPC_DEVICE_NONE;
> + int i;
> +
> + platform_data.devmode = SIMATIC_IPC_DEVICE_NONE;
> +
> + for (i = 0; i < ARRAY_SIZE(device_modes); i++) {
> + if (device_modes[i].station_id == station_id) {
> + ledmode = device_modes[i].led_mode;
> + wdtmode = device_modes[i].wdt_mode;
> + break;
> + }
> + }
> +
> + if (ledmode != SIMATIC_IPC_DEVICE_NONE) {
> + platform_data.devmode = ledmode;
> + ipc_led_platform_device =
> + platform_device_register_data(NULL,
> + KBUILD_MODNAME "_leds", PLATFORM_DEVID_NONE,
> + &platform_data,
> + sizeof(struct simatic_ipc_platform));
> + if (IS_ERR(ipc_led_platform_device))
> + return PTR_ERR(ipc_led_platform_device);
> +
> + pr_debug("device=%s created\n",
> + ipc_led_platform_device->name);
> + }
> +
> + if (wdtmode != SIMATIC_IPC_DEVICE_NONE) {
> + platform_data.devmode = wdtmode;
> + ipc_wdt_platform_device =
> + platform_device_register_data(NULL,
> + KBUILD_MODNAME "_wdt", PLATFORM_DEVID_NONE,
> + &platform_data,
> + sizeof(struct simatic_ipc_platform));
> + if (IS_ERR(ipc_wdt_platform_device))
> + return PTR_ERR(ipc_wdt_platform_device);
> +
> + pr_debug("device=%s created\n",
> + ipc_wdt_platform_device->name);
> + }
> +
> + if (ledmode == SIMATIC_IPC_DEVICE_NONE &&
> + wdtmode == SIMATIC_IPC_DEVICE_NONE) {
> + pr_warn("unsupported IPC detected, station id=%08x\n",
> + station_id);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}

Why not use MFD here?

...

> +/*
> + * Get membase address from PCI, used in leds and wdt modul. Here we read
> + * the bar0. The final address calculation is done in the appropriate modules
> + */

No blank line here.

I would add FIXME or REVISIT here to point out that this should be
deduplicated in the future.

> +u32 simatic_ipc_get_membase0(unsigned int p2sb)
> +{
> + struct pci_bus *bus;
> + u32 bar0 = 0;
> +
> + /*
> + * The GPIO memory is bar0 of the hidden P2SB device. Unhide the device

No, it's not a GPIO's bar. It's P2SB's one. GPIO resides in that bar somewhere.

> + * to have a quick look at it, before we hide it again.
> + * Also grab the pci rescan lock so that device does not get discovered
> + * and remapped while it is visible.
> + * This code is inspired by drivers/mfd/lpc_ich.c
> + */
> + bus = pci_find_bus(0, 0);
> + pci_lock_rescan_remove();
> + pci_bus_write_config_byte(bus, p2sb, 0xE1, 0x0);
> + pci_bus_read_config_dword(bus, p2sb, PCI_BASE_ADDRESS_0, &bar0);
> +
> + bar0 &= ~0xf;
> + pci_bus_write_config_byte(bus, p2sb, 0xE1, 0x1);
> + pci_unlock_rescan_remove();
> +
> + return bar0;
> +}
> +EXPORT_SYMBOL(simatic_ipc_get_membase0);

...

> +static inline u32 simatic_ipc_get_station_id(u8 *data, int max_len)
> +{
> + u32 station_id = SIMATIC_IPC_INVALID_STATION_ID;
> + int i;

Reversed xmas tree order, please.

> + struct {
> + u8 type; /* type (0xff = binary) */
> + u8 len; /* len of data entry */
> + u8 reserved[3];
> + u32 station_id; /* station id (LE) */

> + } __packed
> + *data_entry = (void *)data + sizeof(struct dmi_header);

Can be one line.

> + /* find 4th entry in OEM data */
> + for (i = 0; i < 3; i++)

3 is magic!

> + data_entry = (void *)((u8 *)(data_entry) + data_entry->len);
> +
> + /* decode station id */
> + if (data_entry && (u8 *)data_entry < data + max_len &&
> + data_entry->type == 0xff && data_entry->len == 9)
> + station_id = le32_to_cpu(data_entry->station_id);
> +
> + return station_id;
> +}

--
With Best Regards,
Andy Shevchenko