Message ID | 20170821220946.85617-3-cbostic@linux.vnet.ibm.com |
---|---|
State | Changes Requested |
Headers | show |
On Mon, 2017-08-21 at 17:09 -0500, Christopher Bostic wrote: > Add debugfs to list the mfr_status register and its gpiN_fault > fields. > > > Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com> > --- > v2 - Remove mfr_status directory in debugfs and place the files > up in the parent ucd9000 directory. > --- > drivers/hwmon/pmbus/ucd9000.c | 122 ++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 122 insertions(+) > > diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c > index 5cea5f6..f906d8e 100644 > --- a/drivers/hwmon/pmbus/ucd9000.c > +++ b/drivers/hwmon/pmbus/ucd9000.c > @@ -19,6 +19,7 @@ > * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > */ > > +#include <linux/debugfs.h> > #include <linux/kernel.h> > #include <linux/module.h> > #include <linux/init.h> > @@ -38,6 +39,7 @@ > > #define UCD9000_FAN_CONFIG_INDEX 0xe7 > > #define UCD9000_FAN_CONFIG 0xe8 > > #define UCD9000_LOGGED_FAULTS 0xea > > +#define UCD9000_MFR_STATUS 0xf3 > > #define UCD9000_GPIO_SELECT 0xfa > > #define UCD9000_GPIO_CONFIG 0xfb > > #define UCD9000_DEVICE_ID 0xfd > @@ -56,16 +58,25 @@ > > #define UCD9000_MON_VOLTAGE_HW 4 > > > #define UCD9000_NUM_FAN 4 > > +#define UCD9000_NAME_SIZE 24 > > > #define UCD90160_NUM_GPIOS 26 > > +#define UCD90160_GPI_COUNT 8 > > +#define UCD90160_GPI_FAULT_BASE 16 > > struct ucd9000_data { > > u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX]; > > struct pmbus_driver_info info; > > struct gpio_chip gpio; > > > + struct dentry *debugfs; /* debugfs device directory */ > }; > #define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) > > +struct ucd9000_debugfs_entry { > > + struct i2c_client *client; > > + u8 index; > +}; > + > static int ucd9000_get_fan_config(struct i2c_client *client, int fan) > { > > int fan_config = 0; > @@ -143,6 +154,7 @@ static int ucd9000_gpio_read_config(struct i2c_client *client, > > if (ret < 0) { > > dev_err(&client->dev, "Failed to select GPIO %d: %d\n", offset, > > ret); > + Can we fold the whitespace cleanups into the appropriate patch? Please audit the rest of the patch for similar issues. > > return ret; > > } > > @@ -157,6 +169,7 @@ static int ucd9000_gpio_get(struct gpio_chip *gc, unsigned int offset) > > ret = ucd9000_gpio_read_config(client, offset); > > if (ret < 0) { > > dev_err(&client->dev, "failed to read GPIO config\n"); > + > > return ret; > > } > > @@ -185,6 +198,108 @@ static int ucd9000_gpio_direction_input(struct gpio_chip *gc, > > return 0; > } > > +static struct dentry *ucd9000_debugfs_dir; > + > +#if IS_ENABLED(CONFIG_DEBUG_FS) > +static int ucd9000_get_mfr_status(struct i2c_client *client, u32 *buffer) > +{ > > + int ret; > + > > + ret = pmbus_set_page(client, 0); > > + if (ret < 0) { > > + dev_err(&client->dev, "pmbus_set_page failed. rc:%d\n", ret); > > + return ret; > > + } > > + return i2c_smbus_read_block_data(client, UCD9000_MFR_STATUS, > > + (u8 *)buffer); I know you don't intend to support the device but this will cause stack corruption on the ucd90240. Maybe it's not worth fixing at the moment, but it's probably worth a comment. From the command reference, page 81: With the UCD90120 and UCD90124 devices, this command [MFR_STATUS] is 2 bytes long (bits 0-15). With the UCD90240, this command is 5 bytes long. With all other devices, it is 4 bytes long. > +} > + > +static int ucd9000_debugfs_get_mfr_status_bit(void *data, u64 *val) > +{ > > + struct ucd9000_debugfs_entry *entry = data; > > + struct i2c_client *client = entry->client; > > + int nr = entry->index; > > + u32 buffer; > > + int ret; > + > > + ret = ucd9000_get_mfr_status(client, &buffer); > > + if (ret < 0) { > > + dev_err(&client->dev, > > + "Failed to read mfr status. rc:%d\n", ret); > > + return ret; > > + } > + > > + *val = ret & BIT(nr) ? 1 : 0; We should switch this to the non-branchy solution. > + > > + return 0; > +} > +DEFINE_DEBUGFS_ATTRIBUTE(ucd9000_debugfs_ops_mfr_status_bit, > > + ucd9000_debugfs_get_mfr_status_bit, NULL, "%1lld\n"); > + > +static int ucd9000_debugfs_get_mfr_status_word(void *data, u64 *val) > +{ > > + struct ucd9000_debugfs_entry *entry = data; > > + struct i2c_client *client = entry->client; > > + u32 buffer; > > + int ret; > + > > + ret = ucd9000_get_mfr_status(client, &buffer); > > + if (ret < 0) { > > + dev_err(&client->dev, > > + "Failed to read mfr status. rc:%d\n", ret); > > + return ret; > > + } > + > > + *val = ret; > + > > + return 0; > +} > +DEFINE_DEBUGFS_ATTRIBUTE(ucd9000_debugfs_ops_mfr_status_word, > > + ucd9000_debugfs_get_mfr_status_word, NULL, "%08llx\n"); > + > +static int ucd9000_init_debugfs(struct i2c_client *client, > > + struct ucd9000_data *data) > +{ > > + struct ucd9000_debugfs_entry *entries; > > + char name[UCD9000_NAME_SIZE]; > > + int i; > + > > + ucd9000_debugfs_dir = debugfs_create_dir("ucd9000", NULL); > > + if (IS_ERR(ucd9000_debugfs_dir)) { > > + ucd9000_debugfs_dir = NULL; > > + dev_warn(&client->dev, "Failed to create debugfs dir\n"); > > + return 0; > > + } > + > > + entries = devm_kzalloc(&client->dev, sizeof(*entries) * > > + (UCD90160_GPI_COUNT + 1) * 10, > > + GFP_KERNEL); > > + if (!entries) > > + return -ENOMEM; > + > > + for (i = 0; i < UCD90160_GPI_COUNT; i++) { > > + entries[i].client = client; > > + entries[i].index = UCD90160_GPI_FAULT_BASE + i; > > + scnprintf(name, UCD9000_NAME_SIZE, "gpi%d_alarm", i+1); > > + debugfs_create_file(name, 0444, ucd9000_debugfs_dir, > > + &entries[i], > > + &ucd9000_debugfs_ops_mfr_status_bit); > > + } > > + entries[i].client = client; > > + scnprintf(name, UCD9000_NAME_SIZE, "mfr_status"); > > + debugfs_create_file(name, 0444, ucd9000_debugfs_dir, &entries[i], > > + &ucd9000_debugfs_ops_mfr_status_word); Given the static ucd9000_debugfs_dir, how does this work if there are multiple devices? It's a naive question - I haven't looked into it at all, but I'm curious. Cheers, Andrew > + > > + return 0; > +} > +#else > +static int ucd9000_init_debugfs(struct i2c_client *client, > > + struct ucd9000_data *data) > +{ > > + return 0; > +} > +#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ > + > static ssize_t ucd9000_clear_logged_faults(struct device *dev, > > struct device_attribute *attr, const char *buf, > > size_t count) > @@ -345,12 +460,19 @@ static int ucd9000_probe(struct i2c_client *client, > > if (ret < 0) > > return ret; > > > + if (mid->driver_data == ucd90160) { > > + ret = ucd9000_init_debugfs(client, data); > > + if (ret < 0) > > + dev_warn(&client->dev, "Failed to register debugfs\n"); > > + } > + > > return pmbus_do_probe(client, mid, info); > } > > static int ucd9000_remove(struct i2c_client *client) > { > > sysfs_remove_group(&client->dev.kobj, &ucd9000_attr_group); > > + debugfs_remove_recursive(ucd9000_debugfs_dir); > > return pmbus_do_remove(client); > } >
On 8/21/17 9:01 PM, Andrew Jeffery wrote: > On Mon, 2017-08-21 at 17:09 -0500, Christopher Bostic wrote: >> Add debugfs to list the mfr_status register and its gpiN_fault >> fields. >> >>> Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com> >> --- >> v2 - Remove mfr_status directory in debugfs and place the files >> up in the parent ucd9000 directory. >> --- >> drivers/hwmon/pmbus/ucd9000.c | 122 ++++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 122 insertions(+) >> >> diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c >> index 5cea5f6..f906d8e 100644 >> --- a/drivers/hwmon/pmbus/ucd9000.c >> +++ b/drivers/hwmon/pmbus/ucd9000.c >> @@ -19,6 +19,7 @@ >> * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >> */ >> >> +#include <linux/debugfs.h> >> #include <linux/kernel.h> >> #include <linux/module.h> >> #include <linux/init.h> >> @@ -38,6 +39,7 @@ >>> #define UCD9000_FAN_CONFIG_INDEX 0xe7 >>> #define UCD9000_FAN_CONFIG 0xe8 >>> #define UCD9000_LOGGED_FAULTS 0xea >>> +#define UCD9000_MFR_STATUS 0xf3 >>> #define UCD9000_GPIO_SELECT 0xfa >>> #define UCD9000_GPIO_CONFIG 0xfb >>> #define UCD9000_DEVICE_ID 0xfd >> @@ -56,16 +58,25 @@ >>> #define UCD9000_MON_VOLTAGE_HW 4 >> >>> #define UCD9000_NUM_FAN 4 >>> +#define UCD9000_NAME_SIZE 24 >> >>> #define UCD90160_NUM_GPIOS 26 >>> +#define UCD90160_GPI_COUNT 8 >>> +#define UCD90160_GPI_FAULT_BASE 16 >> >> struct ucd9000_data { >>> u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX]; >>> struct pmbus_driver_info info; >>> struct gpio_chip gpio; >>>> + struct dentry *debugfs; /* debugfs device directory */ >> }; >> #define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) >> >> +struct ucd9000_debugfs_entry { >>> + struct i2c_client *client; >>> + u8 index; >> +}; >> + >> static int ucd9000_get_fan_config(struct i2c_client *client, int fan) >> { >>> int fan_config = 0; >> @@ -143,6 +154,7 @@ static int ucd9000_gpio_read_config(struct i2c_client *client, >>> if (ret < 0) { >>> dev_err(&client->dev, "Failed to select GPIO %d: %d\n", offset, >>> ret); >> + > Can we fold the whitespace cleanups into the appropriate patch? Please audit > the rest of the patch for similar issues. Yes, will do that. >>> return ret; >>> } >> >> @@ -157,6 +169,7 @@ static int ucd9000_gpio_get(struct gpio_chip *gc, unsigned int offset) >>> ret = ucd9000_gpio_read_config(client, offset); >>> if (ret < 0) { >>> dev_err(&client->dev, "failed to read GPIO config\n"); >> + >>> return ret; >>> } >> >> @@ -185,6 +198,108 @@ static int ucd9000_gpio_direction_input(struct gpio_chip *gc, >>> return 0; >> } >> >> +static struct dentry *ucd9000_debugfs_dir; >> + >> +#if IS_ENABLED(CONFIG_DEBUG_FS) >> +static int ucd9000_get_mfr_status(struct i2c_client *client, u32 *buffer) >> +{ >>> + int ret; >> + >>> + ret = pmbus_set_page(client, 0); >>> + if (ret < 0) { >>> + dev_err(&client->dev, "pmbus_set_page failed. rc:%d\n", ret); >>> + return ret; >>> + } >>> + return i2c_smbus_read_block_data(client, UCD9000_MFR_STATUS, >>> + (u8 *)buffer); > I know you don't intend to support the device but this will cause stack > corruption on the ucd90240. Maybe it's not worth fixing at the moment, but it's > probably worth a comment. From the command reference, page 81: > > With the UCD90120 and UCD90124 devices, this command [MFR_STATUS] is 2 > bytes long (bits 0-15). With the UCD90240, this command is 5 bytes > long. With all other devices, it is 4 bytes long. Will add a comment. > >> +} >> + >> +static int ucd9000_debugfs_get_mfr_status_bit(void *data, u64 *val) >> +{ >>> + struct ucd9000_debugfs_entry *entry = data; >>> + struct i2c_client *client = entry->client; >>> + int nr = entry->index; >>> + u32 buffer; >>> + int ret; >> + >>> + ret = ucd9000_get_mfr_status(client, &buffer); >>> + if (ret < 0) { >>> + dev_err(&client->dev, >>> + "Failed to read mfr status. rc:%d\n", ret); >>> + return ret; >>> + } >> + >>> + *val = ret & BIT(nr) ? 1 : 0; > We should switch this to the non-branchy solution. Will fix. > >> + >>> + return 0; >> +} >> +DEFINE_DEBUGFS_ATTRIBUTE(ucd9000_debugfs_ops_mfr_status_bit, >>> + ucd9000_debugfs_get_mfr_status_bit, NULL, "%1lld\n"); >> + >> +static int ucd9000_debugfs_get_mfr_status_word(void *data, u64 *val) >> +{ >>> + struct ucd9000_debugfs_entry *entry = data; >>> + struct i2c_client *client = entry->client; >>> + u32 buffer; >>> + int ret; >> + >>> + ret = ucd9000_get_mfr_status(client, &buffer); >>> + if (ret < 0) { >>> + dev_err(&client->dev, >>> + "Failed to read mfr status. rc:%d\n", ret); >>> + return ret; >>> + } >> + >>> + *val = ret; >> + >>> + return 0; >> +} >> +DEFINE_DEBUGFS_ATTRIBUTE(ucd9000_debugfs_ops_mfr_status_word, >>> + ucd9000_debugfs_get_mfr_status_word, NULL, "%08llx\n"); >> + >> +static int ucd9000_init_debugfs(struct i2c_client *client, >>> + struct ucd9000_data *data) >> +{ >>> + struct ucd9000_debugfs_entry *entries; >>> + char name[UCD9000_NAME_SIZE]; >>> + int i; >> + >>> + ucd9000_debugfs_dir = debugfs_create_dir("ucd9000", NULL); >>> + if (IS_ERR(ucd9000_debugfs_dir)) { >>> + ucd9000_debugfs_dir = NULL; >>> + dev_warn(&client->dev, "Failed to create debugfs dir\n"); >>> + return 0; >>> + } >> + >>> + entries = devm_kzalloc(&client->dev, sizeof(*entries) * >>> + (UCD90160_GPI_COUNT + 1) * 10, >>> + GFP_KERNEL); >>> + if (!entries) >>> + return -ENOMEM; >> + >>> + for (i = 0; i < UCD90160_GPI_COUNT; i++) { >>> + entries[i].client = client; >>> + entries[i].index = UCD90160_GPI_FAULT_BASE + i; >>> + scnprintf(name, UCD9000_NAME_SIZE, "gpi%d_alarm", i+1); >>> + debugfs_create_file(name, 0444, ucd9000_debugfs_dir, >>> + &entries[i], >>> + &ucd9000_debugfs_ops_mfr_status_bit); >>> + } >>> + entries[i].client = client; >>> + scnprintf(name, UCD9000_NAME_SIZE, "mfr_status"); >>> + debugfs_create_file(name, 0444, ucd9000_debugfs_dir, &entries[i], >>> + &ucd9000_debugfs_ops_mfr_status_word); > Given the static ucd9000_debugfs_dir, how does this work if there are multiple > devices? It's a naive question - I haven't looked into it at all, but I'm > curious. Right, this won't work well given that. Will add some unique identifier for each device. Thanks, Chris > Cheers, > > Andrew > >> + >>> + return 0; >> +} >> +#else >> +static int ucd9000_init_debugfs(struct i2c_client *client, >>> + struct ucd9000_data *data) >> +{ >>> + return 0; >> +} >> +#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ >> + >> static ssize_t ucd9000_clear_logged_faults(struct device *dev, >>> struct device_attribute *attr, const char *buf, >>> size_t count) >> @@ -345,12 +460,19 @@ static int ucd9000_probe(struct i2c_client *client, >>> if (ret < 0) >>> return ret; >> >>> + if (mid->driver_data == ucd90160) { >>> + ret = ucd9000_init_debugfs(client, data); >>> + if (ret < 0) >>> + dev_warn(&client->dev, "Failed to register debugfs\n"); >>> + } >> + >>> return pmbus_do_probe(client, mid, info); >> } >> >> static int ucd9000_remove(struct i2c_client *client) >> { >>> sysfs_remove_group(&client->dev.kobj, &ucd9000_attr_group); >>> + debugfs_remove_recursive(ucd9000_debugfs_dir); >>> return pmbus_do_remove(client); >> } >>
diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index 5cea5f6..f906d8e 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -19,6 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <linux/debugfs.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -38,6 +39,7 @@ #define UCD9000_FAN_CONFIG_INDEX 0xe7 #define UCD9000_FAN_CONFIG 0xe8 #define UCD9000_LOGGED_FAULTS 0xea +#define UCD9000_MFR_STATUS 0xf3 #define UCD9000_GPIO_SELECT 0xfa #define UCD9000_GPIO_CONFIG 0xfb #define UCD9000_DEVICE_ID 0xfd @@ -56,16 +58,25 @@ #define UCD9000_MON_VOLTAGE_HW 4 #define UCD9000_NUM_FAN 4 +#define UCD9000_NAME_SIZE 24 #define UCD90160_NUM_GPIOS 26 +#define UCD90160_GPI_COUNT 8 +#define UCD90160_GPI_FAULT_BASE 16 struct ucd9000_data { u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX]; struct pmbus_driver_info info; struct gpio_chip gpio; + struct dentry *debugfs; /* debugfs device directory */ }; #define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) +struct ucd9000_debugfs_entry { + struct i2c_client *client; + u8 index; +}; + static int ucd9000_get_fan_config(struct i2c_client *client, int fan) { int fan_config = 0; @@ -143,6 +154,7 @@ static int ucd9000_gpio_read_config(struct i2c_client *client, if (ret < 0) { dev_err(&client->dev, "Failed to select GPIO %d: %d\n", offset, ret); + return ret; } @@ -157,6 +169,7 @@ static int ucd9000_gpio_get(struct gpio_chip *gc, unsigned int offset) ret = ucd9000_gpio_read_config(client, offset); if (ret < 0) { dev_err(&client->dev, "failed to read GPIO config\n"); + return ret; } @@ -185,6 +198,108 @@ static int ucd9000_gpio_direction_input(struct gpio_chip *gc, return 0; } +static struct dentry *ucd9000_debugfs_dir; + +#if IS_ENABLED(CONFIG_DEBUG_FS) +static int ucd9000_get_mfr_status(struct i2c_client *client, u32 *buffer) +{ + int ret; + + ret = pmbus_set_page(client, 0); + if (ret < 0) { + dev_err(&client->dev, "pmbus_set_page failed. rc:%d\n", ret); + return ret; + } + return i2c_smbus_read_block_data(client, UCD9000_MFR_STATUS, + (u8 *)buffer); +} + +static int ucd9000_debugfs_get_mfr_status_bit(void *data, u64 *val) +{ + struct ucd9000_debugfs_entry *entry = data; + struct i2c_client *client = entry->client; + int nr = entry->index; + u32 buffer; + int ret; + + ret = ucd9000_get_mfr_status(client, &buffer); + if (ret < 0) { + dev_err(&client->dev, + "Failed to read mfr status. rc:%d\n", ret); + return ret; + } + + *val = ret & BIT(nr) ? 1 : 0; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(ucd9000_debugfs_ops_mfr_status_bit, + ucd9000_debugfs_get_mfr_status_bit, NULL, "%1lld\n"); + +static int ucd9000_debugfs_get_mfr_status_word(void *data, u64 *val) +{ + struct ucd9000_debugfs_entry *entry = data; + struct i2c_client *client = entry->client; + u32 buffer; + int ret; + + ret = ucd9000_get_mfr_status(client, &buffer); + if (ret < 0) { + dev_err(&client->dev, + "Failed to read mfr status. rc:%d\n", ret); + return ret; + } + + *val = ret; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(ucd9000_debugfs_ops_mfr_status_word, + ucd9000_debugfs_get_mfr_status_word, NULL, "%08llx\n"); + +static int ucd9000_init_debugfs(struct i2c_client *client, + struct ucd9000_data *data) +{ + struct ucd9000_debugfs_entry *entries; + char name[UCD9000_NAME_SIZE]; + int i; + + ucd9000_debugfs_dir = debugfs_create_dir("ucd9000", NULL); + if (IS_ERR(ucd9000_debugfs_dir)) { + ucd9000_debugfs_dir = NULL; + dev_warn(&client->dev, "Failed to create debugfs dir\n"); + return 0; + } + + entries = devm_kzalloc(&client->dev, sizeof(*entries) * + (UCD90160_GPI_COUNT + 1) * 10, + GFP_KERNEL); + if (!entries) + return -ENOMEM; + + for (i = 0; i < UCD90160_GPI_COUNT; i++) { + entries[i].client = client; + entries[i].index = UCD90160_GPI_FAULT_BASE + i; + scnprintf(name, UCD9000_NAME_SIZE, "gpi%d_alarm", i+1); + debugfs_create_file(name, 0444, ucd9000_debugfs_dir, + &entries[i], + &ucd9000_debugfs_ops_mfr_status_bit); + } + entries[i].client = client; + scnprintf(name, UCD9000_NAME_SIZE, "mfr_status"); + debugfs_create_file(name, 0444, ucd9000_debugfs_dir, &entries[i], + &ucd9000_debugfs_ops_mfr_status_word); + + return 0; +} +#else +static int ucd9000_init_debugfs(struct i2c_client *client, + struct ucd9000_data *data) +{ + return 0; +} +#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ + static ssize_t ucd9000_clear_logged_faults(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -345,12 +460,19 @@ static int ucd9000_probe(struct i2c_client *client, if (ret < 0) return ret; + if (mid->driver_data == ucd90160) { + ret = ucd9000_init_debugfs(client, data); + if (ret < 0) + dev_warn(&client->dev, "Failed to register debugfs\n"); + } + return pmbus_do_probe(client, mid, info); } static int ucd9000_remove(struct i2c_client *client) { sysfs_remove_group(&client->dev.kobj, &ucd9000_attr_group); + debugfs_remove_recursive(ucd9000_debugfs_dir); return pmbus_do_remove(client); }
Add debugfs to list the mfr_status register and its gpiN_fault fields. Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com> --- v2 - Remove mfr_status directory in debugfs and place the files up in the parent ucd9000 directory. --- drivers/hwmon/pmbus/ucd9000.c | 122 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+)