Hi, On 3/17/21 8:13 PM, Henning Schild wrote: > Am Mon, 15 Mar 2021 12:31:11 +0200 > schrieb Andy Shevchenko <andy.shevchenko@xxxxxxxxx>: > >> 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? > > Never had a close look at mfd to be honest. I might > > With the custom dmi matching on 129 being part of the header, and the > p2sb unhide moving out as well ... that first driver ends up being not > too valuable indeed > > It just identifies the box and tells subsequent drivers which one it > is, which watchdog and LED path to take. Moving the knowledge of which > box has which LED/watchdog into the respective drivers seems to be the > better way to go. > > So we would end up with a LED and a watchdog driver both > MODULE_ALIAS("dmi:*:svnSIEMENSAG:*"); > and doing the identification with the inline dmi from that header, > doing p2sb with the support to come ... possibly a "//TODO\ninline" in > the meantime. > > So no "main platform" driver anymore, but still central platform > headers. > > Not sure how this sounds, but i think making that change should be > possible. And that is what i will try and go for in v3. Dropping the main drivers/platform/x86 driver sounds good to me, I was already wondering a bit about its function since it just instantiates devs to which the other ones bind to then instantiate more devs (in the LED case). Regards, Hans >> ... >> >>> +/* >>> + * 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; >>> +} >> >