On Mon, 6 Nov 2023, Henry Shi wrote: > platform/x86: Add Silicom Platform Driver > > Add Silicom platform (silicom-platform) Linux driver for Swisscom > Business Box (Swisscom BB) as well as Cordoba family products. > > This platform driver provides support for various functions via > the Linux LED framework, GPIO framework, Hardware Monitoring (HWMON) > and device attributes. > > Signed-off-by: Henry Shi <henryshi2018@xxxxxxxxx> > --- > > Changes from v1 to v2: > =========================== > > Suggested by Hans de Goede <hdegoede@xxxxxxxxxx> > .Use git send-email to submit patch. > .patch contents should be in message body. > .Kconfig bit for the driver should be in drivers/platform/x86/Kconfig. > > changes from patch v2 to v3 > =========================== > > changes suggested by Guenter Roeck <groeck7@xxxxxxxxx> > .Removed unnecessary include file linux/thermal.h. > .Removed EXPORT_SYMBOL for mutex lock/unlock function. > > Changes suggested by Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx> > .Remove extra new line in code on multiple position. > .Use table instead of space in code. > .Uss Linux defined bit operation MACRO define. > .Removed local variable in rpm_get(). > .Corrected typo in comments. > .Corrected incorrect indentation. > .Removed unnecessary comments in silicom_mc_leds_register(). > .Rewrite efuse_status_show() to used defined variable and removed > uncessary local variables. > .Rewrite uc_version_show() to used defined variable and removed > uncessary local variables. > .Removed unused MACRO define: #define CHANNEL_TO_BIT(chan) ((chan) & 0x07). > .Rewrite powercycle_uc() to used defined variable and removed uncessary > local variables. > .use GENMASK() and use FIELD_GET() instead of bit shift. > .Added define for constant 0x28 used in efuse_status_show(). > .Added define for constant 0x0 used in uc_version_show(). > .Added define for constant 0x0 used in powercycle_uc(). > .Rearrange functions to avoid uncessary pre-define. > .Rewrite rpm_get() to used defined variable and removed uncessary > local variables. > .Rewrite temp_get() to used defined variable and removed uncessary > local variables. > .Use FIELD_GET instead of bit shift in temp_get(). > .Used #define for constant variable 0/1. > > Changes suggested by Christophe JAILLET <christophe.jaillet@xxxxxxxxxx>: > .use "if (!led->subled_info)" instead of > "if (IS_ERR_OR_NULL(led->subled_info)) > "in silicom_mc_leds_register > > changes from patch v3 to v4 > =========================== > > changes suggested by Guenter Roeck <groeck7@xxxxxxxxx> > > Changes suggested by Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>: > .Rewrite silicom_mec_led/gpip_set/get() functions to use two newly created > silicom_mec_port_get()/silicom_mec_port_set() which have common code. > .Remove duplicate code in silicom_mec_port_get() > .Rewrite uc_version_show() to use Linux bit operation MACRO, and add > logic to check un-supported register value. > .Added "#define MEC_EFUSE_LSB_ADDR 0x28" and "#define > MEC_POWER_CYCLE_ADDR 0x24" > .Added "#define MEC_VERSION_MAJOR GENMASK(15, 14)" and "#define > MEC_VERSION_MINOR GENMASK(13, 8)". > > Changes suggested by Christophe JAILLET <christophe.jaillet@xxxxxxxxxx>: > .Used a local variable to store "sizeof(struct mc_subled)" in function > silicom_mc_leds_register(). > > change from patch v4 to v5 > =========================================== > > changes suggested by Guenter Roeck <groeck7@xxxxxxxxx>: > .Corrected return value in temp_get() to return 1/10000th degree. > .Removed local variable struct silicom_fan_control_data *ctl in > silicom_fan_control_read_fan(), > removed storing rpm value to ctl variable. > .Removed local variable struct silicom_fan_control_data *ctl in > silicom_fan_control_read_temp(), > .removed storing rpm value to ctl variable. > .Changed return string in silicom_fan_control_read_labels() to > specific string for Silicom platform driver. > .Removed silicom_fan_control_data structure. > .Removed static variable mec_io_base and mec_io_len, and added > "#define MEC_IO_BASE 0x0800 and #define MEC_IO_LEN 0x8". > .Removed ".write = NULL" in silicom_fan_control_hwmon_ops > structure defination. > .Removed unnecessary function silicom_fan_control_write(). > .Removed unnecessary check for silicom_led_info in function > silicom_platform_probe. > .Removed unnecessary local variable "silicom_fan_control_data *ctl" > in silicom_platform_probe(). > .Clean out driver initialization error handling in > silicom_platform_init(); > .Add patch version and changelog for patch submission. > > Changes suggested by Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>: > .Rename "#define MEC_DATA(offset) to "#define MEC_DATA_OFFSET(offset). > .Use constant defined in include/linux/units.h instead of a literal. > .return directly instead of go to err condition when > platform_device_register_simple() failed. > .Remove unnecessary check for silicom_led_info and silicom_gpiochip. > .Use a local variable to how multiple use of array size. > .Align the arguments to the same column in > silicom_mec_led_mc_brightness_set. > .Add patch version and changelog that shows version to version changes > for patch submission. > > Changes suggested by Christophe JAILLET <christophe.jaillet@xxxxxxxxxx>: > .Use "sizeof(*led)" instead of "sizeof(struct led_classdev_mc)" > .Use "if (!led)" instead of "if (IS_ERR_OR_NULL(led))" > .Removed unnecessary error message: > "dev_err(dev, "Failed to alloc led_classdev_mc[%d]: > %ld\n", i, PTR_ERR(led)). > > change from patch vv5 to v6 > =========================================== > > changes suggested by Guenter Roeck <groeck7@xxxxxxxxx>: > .Removed checkpath warnings. > .Resoved dependencies between CONFIG_HWMON and CONFIG_SILICOM_PLATFORM. > > change from patch v6 to v7 > =========================================== > > changes suggested by Hans de Goede <hdegoede@xxxxxxxxxx>: > .Usa a proper subsystem prefix for this patch subject: > Subject: platform/x86: Add Silicom Platform Driver. > > change from patch v7 to v8 > =========================================== > > changes suggested by Hans de Goede <hdegoede@xxxxxxxxxx>: > .Chnage commit message of this driver. > .Adjust location of change log and signed-off-by. > .Change "config SILICOM_PLATFORM" and help contents location, > and put it to source "drivers/platform/x86/siemens/Kconfig". > .Set editor tab to 8 and align the start of extra function > parameters to directly after (. This should be applied for > all function. > .Do not manually create a sysfs dir and register sysfs attribute, > instead define a platform_driver structure. > .Move MODULE_DEVICE_TABLE(dmi, silicom_dmi_ids) directly after > table declaration. > .Using pr_info() instead of dev_info() in function > silicom_platform_info_init(). > .Made dmi_check_system() check the first thing to do in > silicom_platform_init(). > .Instead of separate platform_device creation + driver registration, > switched to using platform_create_bundle(). > .Removed mutex_destroy(&mec_io_mutex). > > > Changes suggested by Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>: > .Too many GENMASK() within to code itself, need put them to > #define. Removed all GENMASK() in c functions. > > change from patch v8 to v9 > =========================================== > > Changes suggested by Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>: > .Just do the same (like MEC_VERSION_MAJOR) with all places in the where > you previously had GENMASK() in the code (currently MEC_GET_BITS() > is there, obviously, but it should go away and be replaced with > FIELD_GET(GOODPREFIX_GOODNAME, ...))). > .This is sysfs so it's odd to print pr_err() like that here. If the driver > does not support those versions at all, the probe should fail. If driver is > fine but just doesn't know how to interpret such a version, you should > return -Esomething here. Driver returns -EINVAL here. > .Replace CENTI with 100 > .Align FIELD_GET()s to the same column for line 661. > .Change variables efuse_status, mec_uc_version, power_cycle to unsigned > int from int. > > changes suggested by Hans de Goede <hdegoede@xxxxxxxxxx>: > .Please add a Documentation/ABI/testing/sysfs-platform-silicom > file to document driver specific the sysfs attributes of this driver. > .Like with the Kconfig part, group this together with the other industrial > PC drivers we have at the end of the Makefile after Siemens > Simatic Industrial PCs. > > change from patch v9 to v10 > =========================================== > > Changes suggested by Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>: > .Added missing newline in kernel document file. > .Changed the order #define to make sure they are in increasing order. > .Removed printing in init function silicom_platform_info_init(); > .Changed #define name MEC_PREFIX_HIGH_BYTES to MEC_TEMPERATURE. > .Removed dev_err(dev, "Failed to register[%d]: %d\n", i, err) > in function silicom_mc_leds_register() before ruturn err. > .Changed %du to %u in function power_cycle_store(...). > .Chnaged sprintf() to sysfs_emit(). > .Changed start point for multi-line comments. > .Added empty line to seperate #define. > .Remove parenthesis around MEC_IO_BASE. > .Changed #define EC_ADDR_MSB (MEC_IO_BASE + 0x3), use > a constant value instead of MEC_DATA_OFFSET_MASK. > .Changed define name MEC_PREFIX_NAME to MEC_PORT_LOC. > .Changed define MEC_PREFIX_HIGH_BYTES to MEC_TEMP_LOC. > .Removed "PREFIX" from define name, changed > MEC_PREFIX_SEC_BYTE to MEC_VERSION_LOC. > > change from patch v10 to v11 (current patch) > =========================================== > > Changes suggested by Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>: > .Don't print anything when userspace gives an invalid value, > just return -EINVAL in function power_cycle_store(). > .The includes should be in alphabethical order. > .Just make the calculation once and store into a local variable > in function silicom_mec_port_set(). > .Use GENMASK for MEC_PORT_OFFSET_MASK, MEC_PORT_CHANNEL_MASK, > MEC_DATA_OFFSET_MASK. > .Rename MEC_PORT_LOC to MEC_PORT_DWORD_OFFSET. > .Add local variable to function silicom_mec_port_set() and > silicom_mec_port_get() to make the code less heavy to read. > .Allgned defines start from same column mostly. > .Kernel test robot WARNING sys/devices/platform/silicom-platform/hwmon/hwmon1/ > is defined 4 times. > Thanks, seems almost there now, a few editorial things below. > +#include <linux/dmi.h> > +#include <linux/gpio/driver.h> > +#include <linux/hwmon.h> The usual convention is to put the subdir headers separately: #include <linux/dmi.h> #include <linux/hwmon.h> [... more include files under linux/ ...] #include <linux/units.h> #include <linux/gpio/driver.h> > +#define MEC_POWER_CYCLE_ADDR 0x24 > +#define MEC_EFUSE_LSB_ADDR 0x28 > +#define MEC_GPIO_IN_POS 0x08 > +#define MEC_IO_BASE 0x0800 > +#define MEC_IO_LEN 0x8 > +#define IO_REG_BANK 0x0 > +#define DEFAULT_CHAN_LO 0 > +#define DEFAULT_CHAN_HI 0 > +#define DEFAULT_CHAN_LO_T 0xc > +#define MEC_ADDR (MEC_IO_BASE + 0x02) > +#define EC_ADDR_LSB MEC_ADDR > +#define SILICOM_MEC_MAGIC 0x5a > + > +#define MEC_PORT_CHANNEL_MASK GENMASK(2, 0) > +#define MEC_PORT_DWORD_OFFSET GENMASK(31, 3) > +#define MEC_DATA_OFFSET_MASK GENMASK(1, 0) > +#define MEC_PORT_OFFSET_MASK GENMASK(7, 2) Newline here > +#define MEC_TEMP_LOC GENMASK(31, 16) > +#define MEC_VERSION_LOC GENMASK(15, 8) > +#define MEC_VERSION_MAJOR GENMASK(15, 14) > +#define MEC_VERSION_MINOR GENMASK(13, 8) Newline here > +#define EC_ADDR_MSB (MEC_IO_BASE + 0x3) > +#define MEC_DATA_OFFSET(offset) (MEC_IO_BASE + 0x04 + offset) Newline here > +#define OFFSET_BIT_TO_CHANNEL(off, bit) (((off + 0x014) << 3) | bit) > +#define CHANNEL_TO_OFFSET(chan) ((chan >> 3) - 0x14) Please use () around all macro arguments to be on the safe side, so the last one becomes: #define CHANNEL_TO_OFFSET(chan) (((chan) >> 3) - 0x14) (Please do this for all your macros, if I counted correctly, there are 3 of such macros with unprotected arguments currently). > +static int silicom_mec_port_get(unsigned int offset) > +{ > + u8 reg; > + unsigned short mec_data_addr; > + unsigned short mec_port_addr; > + > + mec_data_addr = FIELD_GET(MEC_PORT_DWORD_OFFSET, offset) & MEC_DATA_OFFSET_MASK; > + mec_port_addr = FIELD_GET(MEC_PORT_DWORD_OFFSET, offset) & MEC_PORT_OFFSET_MASK; Newline here since you're starting a critical section. > + mutex_lock(&mec_io_mutex); > + /* Get the dword offset from the channel */ This comment is out of place, perhaps it isn't really needed at all. > + outb(mec_port_addr, MEC_ADDR); > + /* Get the current register */ This comment too is pretty obvious from the code so it should be dropped. > + reg = inb(MEC_DATA_OFFSET(mec_data_addr)); > + mutex_unlock(&mec_io_mutex); > + > + return (reg >> (offset & MEC_PORT_CHANNEL_MASK)) & 0x01; FIELD_GET(MEC_PORT_CHANNEL_MASK, offset) This function is much easier to read now! > +} > + > +static enum led_brightness silicom_mec_led_get(int channel) > +{ > + /* Outputs are active low */ > + return silicom_mec_port_get(channel) ? LED_OFF : LED_ON; > +} > + > +static void silicom_mec_port_set(int channel, int on) > +{ > + u8 reg; > + unsigned short mec_data_addr; > + unsigned short mec_port_addr; > + > + mec_data_addr = FIELD_GET(MEC_PORT_DWORD_OFFSET, channel) & MEC_DATA_OFFSET_MASK; > + mec_port_addr = FIELD_GET(MEC_PORT_DWORD_OFFSET, channel) & MEC_PORT_OFFSET_MASK; Newline due to start of critical section. > + mutex_lock(&mec_io_mutex); > + /* Get the dword offset from the channel */ Same comment related feedback applies to here too. > + outb(mec_port_addr, MEC_ADDR); > + /* Get the current port settings */ > + reg = inb(MEC_DATA_OFFSET(mec_data_addr)); > + /* Outputs are active low, so clear the bit for on, or set it for off */ This is useful comment and should not be dropped. > + if (on) > + reg &= ~(1 << (channel & MEC_PORT_CHANNEL_MASK)); > + else > + reg |= 1 << (channel & MEC_PORT_CHANNEL_MASK); > + /* Write back the updated register */ Extremely obvious thing, just drop this comment. > + outb(reg, MEC_DATA_OFFSET(mec_data_addr)); > + mutex_unlock(&mec_io_mutex); > +} > +static u32 rpm_get(void) > +{ > + u32 reg; > + > + mutex_lock(&mec_io_mutex); > + /* Select memory region */ > + outb(IO_REG_BANK, EC_ADDR_MSB); > + outb(DEFAULT_CHAN_LO_T, EC_ADDR_LSB); > + /* Get current data from the address */ This is again a comment which is not very useful and should just dropped (check if you have similar ones, I won't mark more of them in this reply). > + reg = inw(MEC_DATA_OFFSET(DEFAULT_CHAN_LO)); > + mutex_unlock(&mec_io_mutex); > + > + return reg; > +} -- i.