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