Re: [PATCH v3 4/5] efi: call get_event_log before ExitBootServices

2018-03-05 Thread Marc-André Lureau
t; +#include 
> +
> +/*
> + * Reserve the memory associated with the TPM Event Log configuration table.
> + */
> +int __init efi_tpm_eventlog_init(void)
> +{
> +   struct linux_efi_tpm_eventlog *log_tbl;
> +   unsigned int tbl_size;
> +
> +   if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
> +   return 0;
> +
> +   log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl));
> +   if (!log_tbl) {
> +   pr_err("Failed to map TPM Event Log table @ 0x%lx\n",
> +   efi.tpm_log);
> +   efi.tpm_log = EFI_INVALID_TABLE_ADDR;
> +   return -ENOMEM;
> +   }
> +
> +   tbl_size = sizeof(*log_tbl) + log_tbl->size;
> +   memblock_reserve(efi.tpm_log, tbl_size);
> +   early_memunmap(log_tbl, sizeof(*log_tbl));
> +   return 0;
> +}
> +
> diff --git a/include/linux/efi.h b/include/linux/efi.h
> index 8dc3d94a3e3c..c5805eb601b1 100644
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -472,6 +472,39 @@ typedef struct {
> u64 get_all;
>  } apple_properties_protocol_64_t;
>
> +typedef struct {
> +   u32 get_capability;
> +   u32 get_event_log;
> +   u32 hash_log_extend_event;
> +   u32 submit_command;
> +   u32 get_active_pcr_banks;
> +   u32 set_active_pcr_banks;
> +   u32 get_result_of_set_active_pcr_banks;
> +} efi_tcg2_protocol_32_t;
> +
> +typedef struct {
> +   u64 get_capability;
> +   u64 get_event_log;
> +   u64 hash_log_extend_event;
> +   u64 submit_command;
> +   u64 get_active_pcr_banks;
> +   u64 set_active_pcr_banks;
> +   u64 get_result_of_set_active_pcr_banks;
> +} efi_tcg2_protocol_64_t;
> +
> +typedef u32 efi_tcg2_event_log_format;
> +
> +typedef struct {
> +   void *get_capability;
> +   efi_status_t (*get_event_log)(efi_handle_t, efi_tcg2_event_log_format,
> +   efi_physical_addr_t *, efi_physical_addr_t *, efi_bool_t *);
> +   void *hash_log_extend_event;
> +   void *submit_command;
> +   void *get_active_pcr_banks;
> +   void *set_active_pcr_banks;
> +   void *get_result_of_set_active_pcr_banks;
> +} efi_tcg2_protocol_t;
> +
>  /*
>   * Types and defines for EFI ResetSystem
>   */
> @@ -622,6 +655,7 @@ void efi_native_runtime_setup(void);
>  #define EFI_MEMORY_ATTRIBUTES_TABLE_GUID   EFI_GUID(0xdcfa911d, 0x26eb, 
> 0x469f,  0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20)
>  #define EFI_CONSOLE_OUT_DEVICE_GUIDEFI_GUID(0xd3b36f2c, 0xd551, 
> 0x11d4,  0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>  #define APPLE_PROPERTIES_PROTOCOL_GUID EFI_GUID(0x91bd12fe, 0xf6c3, 
> 0x44fb,  0xa5, 0xb7, 0x51, 0x22, 0xab, 0x30, 0x3a, 0xe0)
> +#define EFI_TCG2_PROTOCOL_GUID EFI_GUID(0x607f766c, 0x7455, 
> 0x42be,  0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f)
>
>  #define EFI_IMAGE_SECURITY_DATABASE_GUID   EFI_GUID(0xd719b2cb, 0x3d3a, 
> 0x4596,  0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
>  #define EFI_SHIM_LOCK_GUID EFI_GUID(0x605dab50, 0xe046, 
> 0x4300,  0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
> @@ -634,6 +668,7 @@ void efi_native_runtime_setup(void);
>  #define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID   EFI_GUID(0xe03fc20a, 0x85dc, 
> 0x406e,  0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
>  #define LINUX_EFI_LOADER_ENTRY_GUIDEFI_GUID(0x4a67b082, 0x0a4c, 
> 0x41cf,  0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
>  #define LINUX_EFI_RANDOM_SEED_TABLE_GUID   EFI_GUID(0x1ce1e5bc, 0x7ceb, 
> 0x42f2,  0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
> +#define LINUX_EFI_TPM_EVENT_LOG_GUID   EFI_GUID(0xb7799cb0, 0xeca2, 
> 0x4943,  0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa)
>
>  typedef struct {
> efi_guid_t guid;
> @@ -908,6 +943,7 @@ extern struct efi {
>     unsigned long properties_table; /* properties table */
> unsigned long mem_attr_table;   /* memory attributes table */
> unsigned long rng_seed; /* UEFI firmware random seed */
> +   unsigned long tpm_log;  /* TPM2 Event Log table */
> efi_get_time_t *get_time;
> efi_set_time_t *set_time;
> efi_get_wakeup_time_t *get_wakeup_time;
> @@ -1504,6 +1540,8 @@ static inline void
>  efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg) { }
>  #endif
>
> +void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table);
> +
>  /*
>   * Arch code can implement the following three template macros, avoiding
>   * reptition for the void/non-void return cases of {__,}efi_call_virt():
> @@ -1571,4 +1609,12 @@ struct linux_efi_random_seed {
> u8  bits[];
>  };
>
> +struct linux_efi_tpm_eventlog {
> +   u32 size;
> +   u8  version;
> +   u8  log[];
> +};
> +
> +extern int efi_tpm_eventlog_init(void);
> +
>  #endif /* _LINUX_EFI_H */
> --
> 2.14.1.821.g8fa685d3b7-goog
>



-- 
Marc-André Lureau


Re: [PATCH v3 4/5] efi: call get_event_log before ExitBootServices

2018-03-05 Thread Marc-André Lureau
+int __init efi_tpm_eventlog_init(void)
> +{
> +   struct linux_efi_tpm_eventlog *log_tbl;
> +   unsigned int tbl_size;
> +
> +   if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
> +   return 0;
> +
> +   log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl));
> +   if (!log_tbl) {
> +   pr_err("Failed to map TPM Event Log table @ 0x%lx\n",
> +   efi.tpm_log);
> +   efi.tpm_log = EFI_INVALID_TABLE_ADDR;
> +   return -ENOMEM;
> +   }
> +
> +   tbl_size = sizeof(*log_tbl) + log_tbl->size;
> +   memblock_reserve(efi.tpm_log, tbl_size);
> +   early_memunmap(log_tbl, sizeof(*log_tbl));
> +   return 0;
> +}
> +
> diff --git a/include/linux/efi.h b/include/linux/efi.h
> index 8dc3d94a3e3c..c5805eb601b1 100644
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -472,6 +472,39 @@ typedef struct {
> u64 get_all;
>  } apple_properties_protocol_64_t;
>
> +typedef struct {
> +   u32 get_capability;
> +   u32 get_event_log;
> +   u32 hash_log_extend_event;
> +   u32 submit_command;
> +   u32 get_active_pcr_banks;
> +   u32 set_active_pcr_banks;
> +   u32 get_result_of_set_active_pcr_banks;
> +} efi_tcg2_protocol_32_t;
> +
> +typedef struct {
> +   u64 get_capability;
> +   u64 get_event_log;
> +   u64 hash_log_extend_event;
> +   u64 submit_command;
> +   u64 get_active_pcr_banks;
> +   u64 set_active_pcr_banks;
> +   u64 get_result_of_set_active_pcr_banks;
> +} efi_tcg2_protocol_64_t;
> +
> +typedef u32 efi_tcg2_event_log_format;
> +
> +typedef struct {
> +   void *get_capability;
> +   efi_status_t (*get_event_log)(efi_handle_t, efi_tcg2_event_log_format,
> +   efi_physical_addr_t *, efi_physical_addr_t *, efi_bool_t *);
> +   void *hash_log_extend_event;
> +   void *submit_command;
> +   void *get_active_pcr_banks;
> +   void *set_active_pcr_banks;
> +   void *get_result_of_set_active_pcr_banks;
> +} efi_tcg2_protocol_t;
> +
>  /*
>   * Types and defines for EFI ResetSystem
>   */
> @@ -622,6 +655,7 @@ void efi_native_runtime_setup(void);
>  #define EFI_MEMORY_ATTRIBUTES_TABLE_GUID   EFI_GUID(0xdcfa911d, 0x26eb, 
> 0x469f,  0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20)
>  #define EFI_CONSOLE_OUT_DEVICE_GUIDEFI_GUID(0xd3b36f2c, 0xd551, 
> 0x11d4,  0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>  #define APPLE_PROPERTIES_PROTOCOL_GUID EFI_GUID(0x91bd12fe, 0xf6c3, 
> 0x44fb,  0xa5, 0xb7, 0x51, 0x22, 0xab, 0x30, 0x3a, 0xe0)
> +#define EFI_TCG2_PROTOCOL_GUID EFI_GUID(0x607f766c, 0x7455, 
> 0x42be,  0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f)
>
>  #define EFI_IMAGE_SECURITY_DATABASE_GUID   EFI_GUID(0xd719b2cb, 0x3d3a, 
> 0x4596,  0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
>  #define EFI_SHIM_LOCK_GUID EFI_GUID(0x605dab50, 0xe046, 
> 0x4300,  0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
> @@ -634,6 +668,7 @@ void efi_native_runtime_setup(void);
>  #define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID   EFI_GUID(0xe03fc20a, 0x85dc, 
> 0x406e,  0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
>  #define LINUX_EFI_LOADER_ENTRY_GUIDEFI_GUID(0x4a67b082, 0x0a4c, 
> 0x41cf,  0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
>  #define LINUX_EFI_RANDOM_SEED_TABLE_GUID   EFI_GUID(0x1ce1e5bc, 0x7ceb, 
> 0x42f2,  0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
> +#define LINUX_EFI_TPM_EVENT_LOG_GUID   EFI_GUID(0xb7799cb0, 0xeca2, 
> 0x4943,  0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa)
>
>  typedef struct {
> efi_guid_t guid;
> @@ -908,6 +943,7 @@ extern struct efi {
> unsigned long properties_table; /* properties table */
> unsigned long mem_attr_table;   /* memory attributes table */
> unsigned long rng_seed; /* UEFI firmware random seed */
> +   unsigned long tpm_log;  /* TPM2 Event Log table */
> efi_get_time_t *get_time;
> efi_set_time_t *set_time;
> efi_get_wakeup_time_t *get_wakeup_time;
> @@ -1504,6 +1540,8 @@ static inline void
>  efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg) { }
>  #endif
>
> +void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table);
> +
>  /*
>   * Arch code can implement the following three template macros, avoiding
>   * reptition for the void/non-void return cases of {__,}efi_call_virt():
> @@ -1571,4 +1609,12 @@ struct linux_efi_random_seed {
> u8  bits[];
>  };
>
> +struct linux_efi_tpm_eventlog {
> +   u32 size;
> +   u8  version;
> +   u8  log[];
> +};
> +
> +extern int efi_tpm_eventlog_init(void);
> +
>  #endif /* _LINUX_EFI_H */
> --
> 2.14.1.821.g8fa685d3b7-goog
>



-- 
Marc-André Lureau


Re: [PATCH v16 09/11] crash: export paddr_vmcoreinfo_note()

2018-03-02 Thread Marc-André Lureau
Hi

On Fri, Mar 2, 2018 at 7:03 PM, Michael S. Tsirkin <m...@redhat.com> wrote:
> On Fri, Mar 02, 2018 at 10:32:04AM +0800, Dave Young wrote:
>> Hi
>>
>> On 02/28/18 at 04:06pm, Marc-André Lureau wrote:
>> > The following patch is going to use the symbol from the fw_cfg module,
>> > to call the function and write the note location details in the
>> > vmcoreinfo entry, so qemu can produce dumps with the vmcoreinfo note.
>> >
>> > CC: Andrew Morton <a...@linux-foundation.org>
>> > CC: Baoquan He <b...@redhat.com>
>> > CC: Dave Young <dyo...@redhat.com>
>> > CC: Dave Young <dyo...@redhat.com>
>>
>> Above duplicated a CC, btw, I remember both Baoquan and me acked it
>> before, you can find the old email and carry the acked-by.
>
> I fixed it but all this is submitter's job really.

Thanks, my bad, I missed it from v6.

>
>> > CC: Hari Bathini <hbath...@linux.vnet.ibm.com>
>> > CC: Tony Luck <tony.l...@intel.com>
>> > CC: Vivek Goyal <vgo...@redhat.com>
>> > Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
>> > Acked-by: Gabriel Somlo <so...@cmu.edu>
>> > ---
>> >  kernel/crash_core.c | 1 +
>> >  1 file changed, 1 insertion(+)
>> >
>> > diff --git a/kernel/crash_core.c b/kernel/crash_core.c
>> > index 4f63597c824d..a93590cdd9e1 100644
>> > --- a/kernel/crash_core.c
>> > +++ b/kernel/crash_core.c
>> > @@ -376,6 +376,7 @@ phys_addr_t __weak paddr_vmcoreinfo_note(void)
>> >  {
>> > return __pa(vmcoreinfo_note);
>> >  }
>> > +EXPORT_SYMBOL(paddr_vmcoreinfo_note);
>> >
>> >  static int __init crash_save_vmcoreinfo_init(void)
>> >  {
>> > --
>> > 2.16.1.73.g5832b7e9f2
>> >
>>
>> Thanks
>> Dave


Re: [PATCH v16 09/11] crash: export paddr_vmcoreinfo_note()

2018-03-02 Thread Marc-André Lureau
Hi

On Fri, Mar 2, 2018 at 7:03 PM, Michael S. Tsirkin  wrote:
> On Fri, Mar 02, 2018 at 10:32:04AM +0800, Dave Young wrote:
>> Hi
>>
>> On 02/28/18 at 04:06pm, Marc-André Lureau wrote:
>> > The following patch is going to use the symbol from the fw_cfg module,
>> > to call the function and write the note location details in the
>> > vmcoreinfo entry, so qemu can produce dumps with the vmcoreinfo note.
>> >
>> > CC: Andrew Morton 
>> > CC: Baoquan He 
>> > CC: Dave Young 
>> > CC: Dave Young 
>>
>> Above duplicated a CC, btw, I remember both Baoquan and me acked it
>> before, you can find the old email and carry the acked-by.
>
> I fixed it but all this is submitter's job really.

Thanks, my bad, I missed it from v6.

>
>> > CC: Hari Bathini 
>> > CC: Tony Luck 
>> > CC: Vivek Goyal 
>> > Signed-off-by: Marc-André Lureau 
>> > Acked-by: Gabriel Somlo 
>> > ---
>> >  kernel/crash_core.c | 1 +
>> >  1 file changed, 1 insertion(+)
>> >
>> > diff --git a/kernel/crash_core.c b/kernel/crash_core.c
>> > index 4f63597c824d..a93590cdd9e1 100644
>> > --- a/kernel/crash_core.c
>> > +++ b/kernel/crash_core.c
>> > @@ -376,6 +376,7 @@ phys_addr_t __weak paddr_vmcoreinfo_note(void)
>> >  {
>> > return __pa(vmcoreinfo_note);
>> >  }
>> > +EXPORT_SYMBOL(paddr_vmcoreinfo_note);
>> >
>> >  static int __init crash_save_vmcoreinfo_init(void)
>> >  {
>> > --
>> > 2.16.1.73.g5832b7e9f2
>> >
>>
>> Thanks
>> Dave


Re: rmi4 defunct on T460p [was: [git pull] Input updates for v4.15-rc8]

2018-03-01 Thread Marc-André Lureau
Hi

On Tue, Feb 13, 2018 at 9:22 AM, Jiri Slaby <jsl...@suse.cz> wrote:
> On 02/09/2018, 02:39 AM, Dmitry Torokhov wrote:
>> On Thu, Feb 08, 2018 at 11:04:22AM +0100, Jiri Slaby wrote:
>>> On 01/19/2018, 06:42 PM, Dmitry Torokhov wrote:
>>>> Please pull from:
>>>>
>>>> git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git for-linus
>>>>
>>>> to receive updates for the input subsystem. You will get:
>>>>
>>> ...
>>>> - touchpad on Lenovo T640p is switched over to SMbus/RMI
>>> ...
>>>
>>>> 王振杰 (1):
>>>>   Input: synaptics - Lenovo Thinkpad T460p devices should use RMI
>>>
>>> Hi,
>>>
>>> one of openSUSE users with T460p reports that the touchpad is defunct
>>> after resume in 4.15. psmouse.synaptics_intertouch=0 works around the
>>> problem.
>>>
>>> The problem is:
>>>  kernel: rmi4_smbus 8-002c: failed to get SMBus version number!
>>>  kernel: rmi4_physical rmi4-00: rmi_driver_reset_handler: Failed to read
>>> current IRQ mask.
>>>  kernel: rmi4_f01 rmi4-00.fn01: Failed to restore normal operation: -16.
>>>  kernel: rmi4_f01 rmi4-00.fn01: Resume failed with code -16.
>>>  kernel: rmi4_physical rmi4-00: Failed to suspend functions: -16
>>>  kernel: rmi4_smbus 8-002c: Failed to resume device: -16
>>>  kernel: rmi4_f03 rmi4-00.fn03: rmi_f03_pt_write: Failed to write to F03
>>> TX register (-16).
>>>
>>> The downstream bug is at:
>>> https://bugzilla.suse.com/show_bug.cgi?id=1079862
>>>
>>> Any ideas?
>>
>> Hmm, maybe the seuence between psmouse and rmi/smbus is not quite right
>> on resume on that box. Can you ask the reporter to:
>>
>> echo 1 > /sys/power/pm_print_times
>> suspend/resume
>
> He uploaded it here:
> https://bugzilla.suse.com/attachment.cgi?id=759933
>

Same problem (with f27 and upstream kernel), is there anything else we
can do to help? Should we open a bug on http://bugzilla.kernel.org ?

thanks

-- 
Marc-André Lureau


Re: rmi4 defunct on T460p [was: [git pull] Input updates for v4.15-rc8]

2018-03-01 Thread Marc-André Lureau
Hi

On Tue, Feb 13, 2018 at 9:22 AM, Jiri Slaby  wrote:
> On 02/09/2018, 02:39 AM, Dmitry Torokhov wrote:
>> On Thu, Feb 08, 2018 at 11:04:22AM +0100, Jiri Slaby wrote:
>>> On 01/19/2018, 06:42 PM, Dmitry Torokhov wrote:
>>>> Please pull from:
>>>>
>>>> git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git for-linus
>>>>
>>>> to receive updates for the input subsystem. You will get:
>>>>
>>> ...
>>>> - touchpad on Lenovo T640p is switched over to SMbus/RMI
>>> ...
>>>
>>>> 王振杰 (1):
>>>>   Input: synaptics - Lenovo Thinkpad T460p devices should use RMI
>>>
>>> Hi,
>>>
>>> one of openSUSE users with T460p reports that the touchpad is defunct
>>> after resume in 4.15. psmouse.synaptics_intertouch=0 works around the
>>> problem.
>>>
>>> The problem is:
>>>  kernel: rmi4_smbus 8-002c: failed to get SMBus version number!
>>>  kernel: rmi4_physical rmi4-00: rmi_driver_reset_handler: Failed to read
>>> current IRQ mask.
>>>  kernel: rmi4_f01 rmi4-00.fn01: Failed to restore normal operation: -16.
>>>  kernel: rmi4_f01 rmi4-00.fn01: Resume failed with code -16.
>>>  kernel: rmi4_physical rmi4-00: Failed to suspend functions: -16
>>>  kernel: rmi4_smbus 8-002c: Failed to resume device: -16
>>>  kernel: rmi4_f03 rmi4-00.fn03: rmi_f03_pt_write: Failed to write to F03
>>> TX register (-16).
>>>
>>> The downstream bug is at:
>>> https://bugzilla.suse.com/show_bug.cgi?id=1079862
>>>
>>> Any ideas?
>>
>> Hmm, maybe the seuence between psmouse and rmi/smbus is not quite right
>> on resume on that box. Can you ask the reporter to:
>>
>> echo 1 > /sys/power/pm_print_times
>> suspend/resume
>
> He uploaded it here:
> https://bugzilla.suse.com/attachment.cgi?id=759933
>

Same problem (with f27 and upstream kernel), is there anything else we
can do to help? Should we open a bug on http://bugzilla.kernel.org ?

thanks

-- 
Marc-André Lureau


Re: [PATCH v16 06/11] fw_cfg: handle fw_cfg_read_blob() error

2018-03-01 Thread Marc-André Lureau
Hi

On Wed, Feb 28, 2018 at 6:32 PM, Michael S. Tsirkin  wrote:
>> @@ -557,7 +566,10 @@ static int fw_cfg_sysfs_probe(struct platform_device 
>> *pdev)
>>   goto err_probe;
>>
>>   /* get revision number, add matching top-level attribute */
>> - fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
>> + err = fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
>> + if (err < 0)
>> + goto err_probe;
>> +
>>   fw_cfg_rev = le32_to_cpu(rev);
>>   err = sysfs_create_file(fw_cfg_top_ko, _cfg_rev_attr.attr);
>>   if (err)
>
> So on this one, maybe we should just drop this attribute.
> Does anyone use it?
> Removing it will speed up boot slightly.

We can't skip reading FW_CFG_ID (rev) as we need it to check DMA
support. I don't mind if we remove the sysfs entry, but I doubt it
makes a difference in boot time.

>> --
>> 2.16.1.73.g5832b7e9f2


Re: [PATCH v16 06/11] fw_cfg: handle fw_cfg_read_blob() error

2018-03-01 Thread Marc-André Lureau
Hi

On Wed, Feb 28, 2018 at 6:32 PM, Michael S. Tsirkin  wrote:
>> @@ -557,7 +566,10 @@ static int fw_cfg_sysfs_probe(struct platform_device 
>> *pdev)
>>   goto err_probe;
>>
>>   /* get revision number, add matching top-level attribute */
>> - fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
>> + err = fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
>> + if (err < 0)
>> + goto err_probe;
>> +
>>   fw_cfg_rev = le32_to_cpu(rev);
>>   err = sysfs_create_file(fw_cfg_top_ko, _cfg_rev_attr.attr);
>>   if (err)
>
> So on this one, maybe we should just drop this attribute.
> Does anyone use it?
> Removing it will speed up boot slightly.

We can't skip reading FW_CFG_ID (rev) as we need it to check DMA
support. I don't mind if we remove the sysfs entry, but I doubt it
makes a difference in boot time.

>> --
>> 2.16.1.73.g5832b7e9f2


Re: [PATCH v15 11/11] RFC: fw_cfg: do DMA read operation

2018-02-28 Thread Marc-André Lureau
Hi

On Wed, Feb 28, 2018 at 6:17 PM, Michael S. Tsirkin <m...@redhat.com> wrote:
> On Wed, Feb 28, 2018 at 04:41:51PM +0100, Marc-André Lureau wrote:
>> I don't know if it's always safe to enable dma in read_raw(), how
>> could we know? Is there a check we could use to choose one or ther
>> other (and thus avoiding explicit dma/readfn argument)?
>
> IMHO the way to go is not to try to do zero copy.
> Allocate a buffer and DMA there, then copy.

Sounds fine to me, I'll resend this patch separately if the rest from
v16 is applied.

thanks


Re: [PATCH v15 11/11] RFC: fw_cfg: do DMA read operation

2018-02-28 Thread Marc-André Lureau
Hi

On Wed, Feb 28, 2018 at 6:17 PM, Michael S. Tsirkin  wrote:
> On Wed, Feb 28, 2018 at 04:41:51PM +0100, Marc-André Lureau wrote:
>> I don't know if it's always safe to enable dma in read_raw(), how
>> could we know? Is there a check we could use to choose one or ther
>> other (and thus avoiding explicit dma/readfn argument)?
>
> IMHO the way to go is not to try to do zero copy.
> Allocate a buffer and DMA there, then copy.

Sounds fine to me, I'll resend this patch separately if the rest from
v16 is applied.

thanks


Re: [PATCH v15 11/11] RFC: fw_cfg: do DMA read operation

2018-02-28 Thread Marc-André Lureau
Hi

On Wed, Feb 28, 2018 at 4:48 PM, Michael S. Tsirkin <m...@redhat.com> wrote:
> On Wed, Feb 28, 2018 at 04:41:51PM +0100, Marc-André Lureau wrote:
>> I don't know if it's always safe to enable dma in read_raw(), how
>> could we know? Is there a check we could use to choose one or ther
>> other (and thus avoiding explicit dma/readfn argument)?
>
> I'm not sure - but does it really matter? Is anyone reading large files
> like this in production where speed matters?
> Why even bother with DMA?

The difference is quite significante for not so small files, as shown above.

And if they access the fw_cfg entries at boot time, or when starting
things etc, this may speed things up.


Re: [PATCH v15 11/11] RFC: fw_cfg: do DMA read operation

2018-02-28 Thread Marc-André Lureau
Hi

On Wed, Feb 28, 2018 at 4:48 PM, Michael S. Tsirkin  wrote:
> On Wed, Feb 28, 2018 at 04:41:51PM +0100, Marc-André Lureau wrote:
>> I don't know if it's always safe to enable dma in read_raw(), how
>> could we know? Is there a check we could use to choose one or ther
>> other (and thus avoiding explicit dma/readfn argument)?
>
> I'm not sure - but does it really matter? Is anyone reading large files
> like this in production where speed matters?
> Why even bother with DMA?

The difference is quite significante for not so small files, as shown above.

And if they access the fw_cfg entries at boot time, or when starting
things etc, this may speed things up.


Re: [PATCH v15 11/11] RFC: fw_cfg: do DMA read operation

2018-02-28 Thread Marc-André Lureau
On Wed, Feb 28, 2018 at 4:35 PM, Michael S. Tsirkin <m...@redhat.com> wrote:
> On Wed, Feb 28, 2018 at 01:27:02PM +0100, Marc-André Lureau wrote:
>> Hi
>>
>> On Tue, Feb 27, 2018 at 1:04 AM, Michael S. Tsirkin <m...@redhat.com> wrote:
>> > On Thu, Feb 15, 2018 at 10:33:12PM +0100, Marc-André Lureau wrote:
>> >> Modify fw_cfg_read_blob() to use DMA if the device supports it.
>> >> Return errors, because the operation may fail.
>> >>
>> >> So far, only one call in fw_cfg_register_dir_entries() is using
>> >> kmalloc'ed buf and is thus clearly eligible to DMA read.
>> >>
>> >> Initially, I didn't implement DMA read to speed up boot time, but as a
>> >> first step before introducing DMA write (since read operations were
>> >> already presents). Even more, I didn't realize fw-cfg entries were
>> >> being read by the kernel during boot by default. But actally fw-cfg
>> >> entries are being populated during module probe. I knew DMA improved a
>> >> lot bios boot time (the main reason the DMA interface was added
>> >> afaik). Let see the time it would take to read the whole ACPI
>> >> tables (128kb allocated)
>> >>
>> >>  # time cat /sys/firmware/qemu_fw_cfg/by_name/etc/acpi/tables/raw
>> >>   - with DMA: sys 0m0.003s
>> >>   - without DMA (-global fw_cfg.dma_enabled=off): sys 0m7.674s
>> >>
>> >> FW_CFG_FILE_DIR (0x19) is the only "file" that is read during kernel
>> >> boot to populate sysfs qemu_fw_cfg directory, and it is quite
>> >> small (1-2kb). Since it does not expose itself, in order to measure
>> >> the time it takes to read such small file, I took a comparable sized
>> >> file of 2048 bytes and exposed it (-fw_cfg test,file=file with a
>> >> modified read_raw enabling DMA)
>> >>
>> >>  # perf stat -r 100 cat /sys/firmware/qemu_fw_cfg/by_name/test/raw 
>> >> >/dev/null
>> >>   - with DMA:
>> >>   0.636037  task-clock (msec) #0.141 CPUs 
>> >> utilized( +-  1.19% )
>> >>   - without DMA:
>> >>   6.430128  task-clock (msec) #0.622 CPUs 
>> >> utilized( +-  0.22% )
>> >>
>> >> That's a few msec saved during boot by enabling DMA read (the gain
>> >> would be more substantial if other & bigger fw-cfg entries are read by
>> >> others from sysfs, unfortunately, it's not clear if we can always
>> >> enable DMA there)
>> >>
>> >> Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
>> >> ---
>> >>  drivers/firmware/qemu_fw_cfg.c | 61 
>> >> ++
>> >>  1 file changed, 50 insertions(+), 11 deletions(-)
>> >>
>> >> diff --git a/drivers/firmware/qemu_fw_cfg.c 
>> >> b/drivers/firmware/qemu_fw_cfg.c
>> >> index 3015e77aebca..94df57e9be66 100644
>> >> --- a/drivers/firmware/qemu_fw_cfg.c
>> >> +++ b/drivers/firmware/qemu_fw_cfg.c
>> >> @@ -124,12 +124,47 @@ static ssize_t fw_cfg_dma_transfer(void *address, 
>> >> u32 length, u32 control)
>> >>   return ret;
>> >>  }
>> >>
>> >> +/* with acpi & dev locks taken */
>> >> +static ssize_t fw_cfg_read_blob_dma(u16 key,
>> >> + void *buf, loff_t pos, size_t count)
>> >> +{
>> >> + ssize_t ret;
>> >> +
>> >> + if (pos == 0) {
>> >> + ret = fw_cfg_dma_transfer(buf, count, key << 16
>> >> + | FW_CFG_DMA_CTL_SELECT
>> >> + | FW_CFG_DMA_CTL_READ);
>> >> + } else {
>> >> + fw_cfg_sel_endianness(key);
>> >> + ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
>> >> + if (ret < 0)
>> >> + return ret;
>> >> + ret = fw_cfg_dma_transfer(buf, count,
>> >> + FW_CFG_DMA_CTL_READ);
>> >> + }
>> >> +
>> >> + return ret;
>> >> +}
>> >> +
>> >> +/* with acpi & dev locks taken */
>> >> +static ssize_t fw_cfg_read_blob_io(u16 key,
>> >> + void *buf, loff

Re: [PATCH v15 11/11] RFC: fw_cfg: do DMA read operation

2018-02-28 Thread Marc-André Lureau
On Wed, Feb 28, 2018 at 4:35 PM, Michael S. Tsirkin  wrote:
> On Wed, Feb 28, 2018 at 01:27:02PM +0100, Marc-André Lureau wrote:
>> Hi
>>
>> On Tue, Feb 27, 2018 at 1:04 AM, Michael S. Tsirkin  wrote:
>> > On Thu, Feb 15, 2018 at 10:33:12PM +0100, Marc-André Lureau wrote:
>> >> Modify fw_cfg_read_blob() to use DMA if the device supports it.
>> >> Return errors, because the operation may fail.
>> >>
>> >> So far, only one call in fw_cfg_register_dir_entries() is using
>> >> kmalloc'ed buf and is thus clearly eligible to DMA read.
>> >>
>> >> Initially, I didn't implement DMA read to speed up boot time, but as a
>> >> first step before introducing DMA write (since read operations were
>> >> already presents). Even more, I didn't realize fw-cfg entries were
>> >> being read by the kernel during boot by default. But actally fw-cfg
>> >> entries are being populated during module probe. I knew DMA improved a
>> >> lot bios boot time (the main reason the DMA interface was added
>> >> afaik). Let see the time it would take to read the whole ACPI
>> >> tables (128kb allocated)
>> >>
>> >>  # time cat /sys/firmware/qemu_fw_cfg/by_name/etc/acpi/tables/raw
>> >>   - with DMA: sys 0m0.003s
>> >>   - without DMA (-global fw_cfg.dma_enabled=off): sys 0m7.674s
>> >>
>> >> FW_CFG_FILE_DIR (0x19) is the only "file" that is read during kernel
>> >> boot to populate sysfs qemu_fw_cfg directory, and it is quite
>> >> small (1-2kb). Since it does not expose itself, in order to measure
>> >> the time it takes to read such small file, I took a comparable sized
>> >> file of 2048 bytes and exposed it (-fw_cfg test,file=file with a
>> >> modified read_raw enabling DMA)
>> >>
>> >>  # perf stat -r 100 cat /sys/firmware/qemu_fw_cfg/by_name/test/raw 
>> >> >/dev/null
>> >>   - with DMA:
>> >>   0.636037  task-clock (msec) #0.141 CPUs 
>> >> utilized( +-  1.19% )
>> >>   - without DMA:
>> >>   6.430128  task-clock (msec) #0.622 CPUs 
>> >> utilized( +-  0.22% )
>> >>
>> >> That's a few msec saved during boot by enabling DMA read (the gain
>> >> would be more substantial if other & bigger fw-cfg entries are read by
>> >> others from sysfs, unfortunately, it's not clear if we can always
>> >> enable DMA there)
>> >>
>> >> Signed-off-by: Marc-André Lureau 
>> >> ---
>> >>  drivers/firmware/qemu_fw_cfg.c | 61 
>> >> ++
>> >>  1 file changed, 50 insertions(+), 11 deletions(-)
>> >>
>> >> diff --git a/drivers/firmware/qemu_fw_cfg.c 
>> >> b/drivers/firmware/qemu_fw_cfg.c
>> >> index 3015e77aebca..94df57e9be66 100644
>> >> --- a/drivers/firmware/qemu_fw_cfg.c
>> >> +++ b/drivers/firmware/qemu_fw_cfg.c
>> >> @@ -124,12 +124,47 @@ static ssize_t fw_cfg_dma_transfer(void *address, 
>> >> u32 length, u32 control)
>> >>   return ret;
>> >>  }
>> >>
>> >> +/* with acpi & dev locks taken */
>> >> +static ssize_t fw_cfg_read_blob_dma(u16 key,
>> >> + void *buf, loff_t pos, size_t count)
>> >> +{
>> >> + ssize_t ret;
>> >> +
>> >> + if (pos == 0) {
>> >> + ret = fw_cfg_dma_transfer(buf, count, key << 16
>> >> + | FW_CFG_DMA_CTL_SELECT
>> >> + | FW_CFG_DMA_CTL_READ);
>> >> + } else {
>> >> + fw_cfg_sel_endianness(key);
>> >> + ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
>> >> + if (ret < 0)
>> >> + return ret;
>> >> + ret = fw_cfg_dma_transfer(buf, count,
>> >> + FW_CFG_DMA_CTL_READ);
>> >> + }
>> >> +
>> >> + return ret;
>> >> +}
>> >> +
>> >> +/* with acpi & dev locks taken */
>> >> +static ssize_t fw_cfg_read_blob_io(u16 key,
>> >> + void *buf, loff_t pos, size_t count)
>> >> +{
>> >> + fw_cfg_sel_endianness(key);

[PATCH v16 01/11] fw_cfg: fix sparse warnings in fw_cfg_sel_endianness()

2018-02-28 Thread Marc-André Lureau
Dispatch to the appropriate iowrite() instead of casting restricted
type to u16.

- if fw_cfg_is_mmio:
  before: iowrite16(cpu_to_be16(key))
  after: iowrite16be(key)
- if !fw_cfg_is_mmio:
  before: iowrite16(cpu_to_le16(key))
  after: iowrite16(key)
  which is equivalent on little-endian systems, where fw_cfg IO is supported.

Fixes:
$ make C=1 CF=-D__CHECK_ENDIAN__ drivers/firmware/qemu_fw_cfg.o

drivers/firmware/qemu_fw_cfg.c:55:33: warning: restricted __be16 degrades to 
integer
drivers/firmware/qemu_fw_cfg.c:55:52: warning: restricted __le16 degrades to 
integer

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index a41b572eeeb1..e7ea2b3b1d11 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -68,9 +68,12 @@ static void __iomem *fw_cfg_reg_data;
 static DEFINE_MUTEX(fw_cfg_dev_lock);
 
 /* pick appropriate endianness for selector key */
-static inline u16 fw_cfg_sel_endianness(u16 key)
+static void fw_cfg_sel_endianness(u16 key)
 {
-   return fw_cfg_is_mmio ? cpu_to_be16(key) : cpu_to_le16(key);
+   if (fw_cfg_is_mmio)
+   iowrite16be(key, fw_cfg_reg_ctrl);
+   else
+   iowrite16(key, fw_cfg_reg_ctrl);
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
@@ -92,7 +95,7 @@ static inline void fw_cfg_read_blob(u16 key,
}
 
mutex_lock(_cfg_dev_lock);
-   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+   fw_cfg_sel_endianness(key);
while (pos-- > 0)
ioread8(fw_cfg_reg_data);
ioread8_rep(fw_cfg_reg_data, buf, count);
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 01/11] fw_cfg: fix sparse warnings in fw_cfg_sel_endianness()

2018-02-28 Thread Marc-André Lureau
Dispatch to the appropriate iowrite() instead of casting restricted
type to u16.

- if fw_cfg_is_mmio:
  before: iowrite16(cpu_to_be16(key))
  after: iowrite16be(key)
- if !fw_cfg_is_mmio:
  before: iowrite16(cpu_to_le16(key))
  after: iowrite16(key)
  which is equivalent on little-endian systems, where fw_cfg IO is supported.

Fixes:
$ make C=1 CF=-D__CHECK_ENDIAN__ drivers/firmware/qemu_fw_cfg.o

drivers/firmware/qemu_fw_cfg.c:55:33: warning: restricted __be16 degrades to 
integer
drivers/firmware/qemu_fw_cfg.c:55:52: warning: restricted __le16 degrades to 
integer

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index a41b572eeeb1..e7ea2b3b1d11 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -68,9 +68,12 @@ static void __iomem *fw_cfg_reg_data;
 static DEFINE_MUTEX(fw_cfg_dev_lock);
 
 /* pick appropriate endianness for selector key */
-static inline u16 fw_cfg_sel_endianness(u16 key)
+static void fw_cfg_sel_endianness(u16 key)
 {
-   return fw_cfg_is_mmio ? cpu_to_be16(key) : cpu_to_le16(key);
+   if (fw_cfg_is_mmio)
+   iowrite16be(key, fw_cfg_reg_ctrl);
+   else
+   iowrite16(key, fw_cfg_reg_ctrl);
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
@@ -92,7 +95,7 @@ static inline void fw_cfg_read_blob(u16 key,
}
 
mutex_lock(_cfg_dev_lock);
-   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+   fw_cfg_sel_endianness(key);
while (pos-- > 0)
ioread8(fw_cfg_reg_data);
ioread8_rep(fw_cfg_reg_data, buf, count);
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 04/11] fw_cfg: fix sparse warnings around FW_CFG_FILE_DIR read

2018-02-28 Thread Marc-André Lureau
Use struct fw_cfg_files to read the directory size, fixing the sparse
warnings:

drivers/firmware/qemu_fw_cfg.c:485:17: warning: cast to restricted __be32

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 0eb155fdfb35..00ad9b862414 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -496,19 +496,20 @@ static int fw_cfg_register_file(const struct fw_cfg_file 
*f)
 static int fw_cfg_register_dir_entries(void)
 {
int ret = 0;
+   __be32 files_count;
u32 count, i;
struct fw_cfg_file *dir;
size_t dir_size;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, , 0, sizeof(count));
-   count = be32_to_cpu(count);
+   fw_cfg_read_blob(FW_CFG_FILE_DIR, _count, 0, sizeof(files_count));
+   count = be32_to_cpu(files_count);
dir_size = count * sizeof(struct fw_cfg_file);
 
dir = kmalloc(dir_size, GFP_KERNEL);
if (!dir)
return -ENOMEM;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
+   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files_count), dir_size);
 
for (i = 0; i < count; i++) {
ret = fw_cfg_register_file([i]);
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 04/11] fw_cfg: fix sparse warnings around FW_CFG_FILE_DIR read

2018-02-28 Thread Marc-André Lureau
Use struct fw_cfg_files to read the directory size, fixing the sparse
warnings:

drivers/firmware/qemu_fw_cfg.c:485:17: warning: cast to restricted __be32

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 0eb155fdfb35..00ad9b862414 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -496,19 +496,20 @@ static int fw_cfg_register_file(const struct fw_cfg_file 
*f)
 static int fw_cfg_register_dir_entries(void)
 {
int ret = 0;
+   __be32 files_count;
u32 count, i;
struct fw_cfg_file *dir;
size_t dir_size;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, , 0, sizeof(count));
-   count = be32_to_cpu(count);
+   fw_cfg_read_blob(FW_CFG_FILE_DIR, _count, 0, sizeof(files_count));
+   count = be32_to_cpu(files_count);
dir_size = count * sizeof(struct fw_cfg_file);
 
dir = kmalloc(dir_size, GFP_KERNEL);
if (!dir)
return -ENOMEM;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
+   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files_count), dir_size);
 
for (i = 0; i < count; i++) {
ret = fw_cfg_register_file([i]);
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 06/11] fw_cfg: handle fw_cfg_read_blob() error

2018-02-28 Thread Marc-André Lureau
fw_cfg_read_blob() may fail, but does not return error. This may lead
to surprising behaviours, like populating zero file entries (in
register_file() or during read). Return an error if ACPI locking
failed. Also, the following DMA read/write extension will add more
error paths that should be handled appropriately.

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 32 ++--
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 0cc71d028ae3..45bfc389b226 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -77,8 +77,8 @@ static void fw_cfg_sel_endianness(u16 key)
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
-static void fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+static ssize_t fw_cfg_read_blob(u16 key,
+   void *buf, loff_t pos, size_t count)
 {
u32 glk = -1U;
acpi_status status;
@@ -91,7 +91,7 @@ static void fw_cfg_read_blob(u16 key,
/* Should never get here */
WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
memset(buf, 0, count);
-   return;
+   return -EINVAL;
}
 
mutex_lock(_cfg_dev_lock);
@@ -102,6 +102,7 @@ static void fw_cfg_read_blob(u16 key,
mutex_unlock(_cfg_dev_lock);
 
acpi_release_global_lock(glk);
+   return count;
 }
 
 /* clean up fw_cfg device i/o */
@@ -183,8 +184,9 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
}
 
/* verify fw_cfg device signature */
-   fw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE);
-   if (memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
+   if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
+   0, FW_CFG_SIG_SIZE) < 0 ||
+   memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
fw_cfg_io_cleanup();
return -ENODEV;
}
@@ -344,8 +346,7 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, 
struct kobject *kobj,
if (count > entry->size - pos)
count = entry->size - pos;
 
-   fw_cfg_read_blob(entry->select, buf, pos, count);
-   return count;
+   return fw_cfg_read_blob(entry->select, buf, pos, count);
 }
 
 static struct bin_attribute fw_cfg_sysfs_attr_raw = {
@@ -501,7 +502,11 @@ static int fw_cfg_register_dir_entries(void)
struct fw_cfg_file *dir;
size_t dir_size;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, _count, 0, sizeof(files_count));
+   ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, _count,
+   0, sizeof(files_count));
+   if (ret < 0)
+   return ret;
+
count = be32_to_cpu(files_count);
dir_size = count * sizeof(struct fw_cfg_file);
 
@@ -509,7 +514,10 @@ static int fw_cfg_register_dir_entries(void)
if (!dir)
return -ENOMEM;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files_count), dir_size);
+   ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, dir,
+   sizeof(files_count), dir_size);
+   if (ret < 0)
+   goto end;
 
for (i = 0; i < count; i++) {
ret = fw_cfg_register_file([i]);
@@ -517,6 +525,7 @@ static int fw_cfg_register_dir_entries(void)
break;
}
 
+end:
kfree(dir);
return ret;
 }
@@ -557,7 +566,10 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)
goto err_probe;
 
/* get revision number, add matching top-level attribute */
-   fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   err = fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   if (err < 0)
+   goto err_probe;
+
fw_cfg_rev = le32_to_cpu(rev);
err = sysfs_create_file(fw_cfg_top_ko, _cfg_rev_attr.attr);
if (err)
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 06/11] fw_cfg: handle fw_cfg_read_blob() error

2018-02-28 Thread Marc-André Lureau
fw_cfg_read_blob() may fail, but does not return error. This may lead
to surprising behaviours, like populating zero file entries (in
register_file() or during read). Return an error if ACPI locking
failed. Also, the following DMA read/write extension will add more
error paths that should be handled appropriately.

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 32 ++--
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 0cc71d028ae3..45bfc389b226 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -77,8 +77,8 @@ static void fw_cfg_sel_endianness(u16 key)
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
-static void fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+static ssize_t fw_cfg_read_blob(u16 key,
+   void *buf, loff_t pos, size_t count)
 {
u32 glk = -1U;
acpi_status status;
@@ -91,7 +91,7 @@ static void fw_cfg_read_blob(u16 key,
/* Should never get here */
WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
memset(buf, 0, count);
-   return;
+   return -EINVAL;
}
 
mutex_lock(_cfg_dev_lock);
@@ -102,6 +102,7 @@ static void fw_cfg_read_blob(u16 key,
mutex_unlock(_cfg_dev_lock);
 
acpi_release_global_lock(glk);
+   return count;
 }
 
 /* clean up fw_cfg device i/o */
@@ -183,8 +184,9 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
}
 
/* verify fw_cfg device signature */
-   fw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE);
-   if (memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
+   if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
+   0, FW_CFG_SIG_SIZE) < 0 ||
+   memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
fw_cfg_io_cleanup();
return -ENODEV;
}
@@ -344,8 +346,7 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, 
struct kobject *kobj,
if (count > entry->size - pos)
count = entry->size - pos;
 
-   fw_cfg_read_blob(entry->select, buf, pos, count);
-   return count;
+   return fw_cfg_read_blob(entry->select, buf, pos, count);
 }
 
 static struct bin_attribute fw_cfg_sysfs_attr_raw = {
@@ -501,7 +502,11 @@ static int fw_cfg_register_dir_entries(void)
struct fw_cfg_file *dir;
size_t dir_size;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, _count, 0, sizeof(files_count));
+   ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, _count,
+   0, sizeof(files_count));
+   if (ret < 0)
+   return ret;
+
count = be32_to_cpu(files_count);
dir_size = count * sizeof(struct fw_cfg_file);
 
@@ -509,7 +514,10 @@ static int fw_cfg_register_dir_entries(void)
if (!dir)
return -ENOMEM;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files_count), dir_size);
+   ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, dir,
+   sizeof(files_count), dir_size);
+   if (ret < 0)
+   goto end;
 
for (i = 0; i < count; i++) {
ret = fw_cfg_register_file([i]);
@@ -517,6 +525,7 @@ static int fw_cfg_register_dir_entries(void)
break;
}
 
+end:
kfree(dir);
return ret;
 }
@@ -557,7 +566,10 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)
goto err_probe;
 
/* get revision number, add matching top-level attribute */
-   fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   err = fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   if (err < 0)
+   goto err_probe;
+
fw_cfg_rev = le32_to_cpu(rev);
err = sysfs_create_file(fw_cfg_top_ko, _cfg_rev_attr.attr);
if (err)
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 05/11] fw_cfg: remove inline from fw_cfg_read_blob()

2018-02-28 Thread Marc-André Lureau
The function is not small and getting bigger.

Let the compiler decide instead. No profiling done, hopefully
unnecessary.

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 00ad9b862414..0cc71d028ae3 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -77,8 +77,8 @@ static void fw_cfg_sel_endianness(u16 key)
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
-static inline void fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+static void fw_cfg_read_blob(u16 key,
+   void *buf, loff_t pos, size_t count)
 {
u32 glk = -1U;
acpi_status status;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 05/11] fw_cfg: remove inline from fw_cfg_read_blob()

2018-02-28 Thread Marc-André Lureau
The function is not small and getting bigger.

Let the compiler decide instead. No profiling done, hopefully
unnecessary.

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 00ad9b862414..0cc71d028ae3 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -77,8 +77,8 @@ static void fw_cfg_sel_endianness(u16 key)
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
-static inline void fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+static void fw_cfg_read_blob(u16 key,
+   void *buf, loff_t pos, size_t count)
 {
u32 glk = -1U;
acpi_status status;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 09/11] crash: export paddr_vmcoreinfo_note()

2018-02-28 Thread Marc-André Lureau
The following patch is going to use the symbol from the fw_cfg module,
to call the function and write the note location details in the
vmcoreinfo entry, so qemu can produce dumps with the vmcoreinfo note.

CC: Andrew Morton <a...@linux-foundation.org>
CC: Baoquan He <b...@redhat.com>
CC: Dave Young <dyo...@redhat.com>
CC: Dave Young <dyo...@redhat.com>
CC: Hari Bathini <hbath...@linux.vnet.ibm.com>
CC: Tony Luck <tony.l...@intel.com>
CC: Vivek Goyal <vgo...@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
Acked-by: Gabriel Somlo <so...@cmu.edu>
---
 kernel/crash_core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 4f63597c824d..a93590cdd9e1 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -376,6 +376,7 @@ phys_addr_t __weak paddr_vmcoreinfo_note(void)
 {
return __pa(vmcoreinfo_note);
 }
+EXPORT_SYMBOL(paddr_vmcoreinfo_note);
 
 static int __init crash_save_vmcoreinfo_init(void)
 {
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 09/11] crash: export paddr_vmcoreinfo_note()

2018-02-28 Thread Marc-André Lureau
The following patch is going to use the symbol from the fw_cfg module,
to call the function and write the note location details in the
vmcoreinfo entry, so qemu can produce dumps with the vmcoreinfo note.

CC: Andrew Morton 
CC: Baoquan He 
CC: Dave Young 
CC: Dave Young 
CC: Hari Bathini 
CC: Tony Luck 
CC: Vivek Goyal 
Signed-off-by: Marc-André Lureau 
Acked-by: Gabriel Somlo 
---
 kernel/crash_core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 4f63597c824d..a93590cdd9e1 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -376,6 +376,7 @@ phys_addr_t __weak paddr_vmcoreinfo_note(void)
 {
return __pa(vmcoreinfo_note);
 }
+EXPORT_SYMBOL(paddr_vmcoreinfo_note);
 
 static int __init crash_save_vmcoreinfo_init(void)
 {
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 10/11] fw_cfg: write vmcoreinfo details

2018-02-28 Thread Marc-André Lureau
If the "etc/vmcoreinfo" fw_cfg file is present and we are not running
the kdump kernel, write the addr/size of the vmcoreinfo ELF note.

The DMA operation is expected to run synchronously with today qemu,
but the specification states that it may become async, so we run
"control" field check in a loop for eventual changes.

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c   | 145 ++-
 include/uapi/linux/qemu_fw_cfg.h |  31 +
 2 files changed, 173 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index df028faa2d00..14fedbeca724 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -34,11 +34,17 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo <so...@cmu.edu>");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
 MODULE_LICENSE("GPL");
 
+/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
+static u32 fw_cfg_rev;
+
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -60,6 +66,66 @@ static void fw_cfg_sel_endianness(u16 key)
iowrite16(key, fw_cfg_reg_ctrl);
 }
 
+#ifdef CONFIG_CRASH_CORE
+static inline bool fw_cfg_dma_enabled(void)
+{
+   return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
+}
+
+/* qemu fw_cfg device is sync today, but spec says it may become async */
+static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *d)
+{
+   for (;;) {
+   u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
+
+   /* do not reorder the read to d->control */
+   rmb();
+   if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
+   return;
+
+   cpu_relax();
+   }
+}
+
+static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
+{
+   phys_addr_t dma;
+   struct fw_cfg_dma_access *d = NULL;
+   ssize_t ret = length;
+
+   d = kmalloc(sizeof(*d), GFP_KERNEL);
+   if (!d) {
+   ret = -ENOMEM;
+   goto end;
+   }
+
+   /* fw_cfg device does not need IOMMU protection, so use physical 
addresses */
+   *d = (struct fw_cfg_dma_access) {
+   .address = cpu_to_be64(address ? virt_to_phys(address) : 0),
+   .length = cpu_to_be32(length),
+   .control = cpu_to_be32(control)
+   };
+
+   dma = virt_to_phys(d);
+
+   iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
+   /* force memory to sync before notifying device via MMIO */
+   wmb();
+   iowrite32be(dma, fw_cfg_reg_dma + 4);
+
+   fw_cfg_wait_for_control(d);
+
+   if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
+   ret = -EIO;
+   }
+
+end:
+   kfree(d);
+
+   return ret;
+}
+#endif
+
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
 static ssize_t fw_cfg_read_blob(u16 key,
void *buf, loff_t pos, size_t count)
@@ -89,6 +155,47 @@ static ssize_t fw_cfg_read_blob(u16 key,
return count;
 }
 
+#ifdef CONFIG_CRASH_CORE
+/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
+static ssize_t fw_cfg_write_blob(u16 key,
+void *buf, loff_t pos, size_t count)
+{
+   u32 glk = -1U;
+   acpi_status status;
+   ssize_t ret = count;
+
+   /* If we have ACPI, ensure mutual exclusion against any potential
+* device access by the firmware, e.g. via AML methods:
+*/
+   status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
+   if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
+   /* Should never get here */
+   WARN(1, "%s: Failed to lock ACPI!\n", __func__);
+   return -EINVAL;
+   }
+
+   mutex_lock(_cfg_dev_lock);
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+ | FW_CFG_DMA_CTL_SELECT
+ | FW_CFG_DMA_CTL_WRITE);
+   } else {
+   fw_cfg_sel_endianness(key);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (ret < 0)
+   goto end;
+   ret = fw_cfg_dma_transfer(buf, count, FW_CFG_DMA_CTL_WRITE);
+   }
+
+end:
+   mutex_unlock(_cfg_dev_lock);
+
+   acpi_release_global_lock(glk);
+
+   return ret;
+}
+#endif /* CONFIG_CRASH_CORE */
+
 /* clean up fw_cfg device i/o */
 static void fw_cfg_io_cleanup(void)
 {
@@ -188,9 +295,6 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
return 0;
 }
 
-/* fw_cfg revision attribut

[PATCH v16 10/11] fw_cfg: write vmcoreinfo details

2018-02-28 Thread Marc-André Lureau
If the "etc/vmcoreinfo" fw_cfg file is present and we are not running
the kdump kernel, write the addr/size of the vmcoreinfo ELF note.

The DMA operation is expected to run synchronously with today qemu,
but the specification states that it may become async, so we run
"control" field check in a loop for eventual changes.

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c   | 145 ++-
 include/uapi/linux/qemu_fw_cfg.h |  31 +
 2 files changed, 173 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index df028faa2d00..14fedbeca724 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -34,11 +34,17 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo ");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
 MODULE_LICENSE("GPL");
 
+/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
+static u32 fw_cfg_rev;
+
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -60,6 +66,66 @@ static void fw_cfg_sel_endianness(u16 key)
iowrite16(key, fw_cfg_reg_ctrl);
 }
 
+#ifdef CONFIG_CRASH_CORE
+static inline bool fw_cfg_dma_enabled(void)
+{
+   return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
+}
+
+/* qemu fw_cfg device is sync today, but spec says it may become async */
+static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *d)
+{
+   for (;;) {
+   u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
+
+   /* do not reorder the read to d->control */
+   rmb();
+   if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
+   return;
+
+   cpu_relax();
+   }
+}
+
+static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
+{
+   phys_addr_t dma;
+   struct fw_cfg_dma_access *d = NULL;
+   ssize_t ret = length;
+
+   d = kmalloc(sizeof(*d), GFP_KERNEL);
+   if (!d) {
+   ret = -ENOMEM;
+   goto end;
+   }
+
+   /* fw_cfg device does not need IOMMU protection, so use physical 
addresses */
+   *d = (struct fw_cfg_dma_access) {
+   .address = cpu_to_be64(address ? virt_to_phys(address) : 0),
+   .length = cpu_to_be32(length),
+   .control = cpu_to_be32(control)
+   };
+
+   dma = virt_to_phys(d);
+
+   iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
+   /* force memory to sync before notifying device via MMIO */
+   wmb();
+   iowrite32be(dma, fw_cfg_reg_dma + 4);
+
+   fw_cfg_wait_for_control(d);
+
+   if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
+   ret = -EIO;
+   }
+
+end:
+   kfree(d);
+
+   return ret;
+}
+#endif
+
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
 static ssize_t fw_cfg_read_blob(u16 key,
void *buf, loff_t pos, size_t count)
@@ -89,6 +155,47 @@ static ssize_t fw_cfg_read_blob(u16 key,
return count;
 }
 
+#ifdef CONFIG_CRASH_CORE
+/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
+static ssize_t fw_cfg_write_blob(u16 key,
+void *buf, loff_t pos, size_t count)
+{
+   u32 glk = -1U;
+   acpi_status status;
+   ssize_t ret = count;
+
+   /* If we have ACPI, ensure mutual exclusion against any potential
+* device access by the firmware, e.g. via AML methods:
+*/
+   status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
+   if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
+   /* Should never get here */
+   WARN(1, "%s: Failed to lock ACPI!\n", __func__);
+   return -EINVAL;
+   }
+
+   mutex_lock(_cfg_dev_lock);
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+ | FW_CFG_DMA_CTL_SELECT
+ | FW_CFG_DMA_CTL_WRITE);
+   } else {
+   fw_cfg_sel_endianness(key);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (ret < 0)
+   goto end;
+   ret = fw_cfg_dma_transfer(buf, count, FW_CFG_DMA_CTL_WRITE);
+   }
+
+end:
+   mutex_unlock(_cfg_dev_lock);
+
+   acpi_release_global_lock(glk);
+
+   return ret;
+}
+#endif /* CONFIG_CRASH_CORE */
+
 /* clean up fw_cfg device i/o */
 static void fw_cfg_io_cleanup(void)
 {
@@ -188,9 +295,6 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
return 0;
 }
 
-/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir

[PATCH v16 11/11] RFC: fw_cfg: do DMA read operation

2018-02-28 Thread Marc-André Lureau
Modify fw_cfg_read_blob() to use DMA if the device supports it.
Return errors, because the operation may fail.

So far, only one call in fw_cfg_register_dir_entries() is using
kmalloc'ed buf and is thus clearly eligible to DMA read.

Initially, I didn't implement DMA read to speed up boot time, but as a
first step before introducing DMA write (since read operations were
already presents). Even more, I didn't realize fw-cfg entries were
being read by the kernel during boot by default. But actally fw-cfg
entries are being populated during module probe. I knew DMA improved a
lot bios boot time (the main reason the DMA interface was added
afaik). Let see the time it would take to read the whole ACPI
tables (128kb allocated)

 # time cat /sys/firmware/qemu_fw_cfg/by_name/etc/acpi/tables/raw
  - with DMA: sys 0m0.003s
  - without DMA (-global fw_cfg.dma_enabled=off): sys 0m7.674s

FW_CFG_FILE_DIR (0x19) is the only "file" that is read during kernel
boot to populate sysfs qemu_fw_cfg directory, and it is quite
small (1-2kb). Since it does not expose itself, in order to measure
the time it takes to read such small file, I took a comparable sized
file of 2048 bytes and exposed it (-fw_cfg test,file=file with a
modified read_raw enabling DMA)

 # perf stat -r 100 cat /sys/firmware/qemu_fw_cfg/by_name/test/raw >/dev/null
  - with DMA:
  0.636037  task-clock (msec) #0.141 CPUs utilized  
  ( +-  1.19% )
  - without DMA:
  6.430128  task-clock (msec) #0.622 CPUs utilized  
  ( +-  0.22% )

That's a few msec saved during boot by enabling DMA read (the gain
would be more substantial if other & bigger fw-cfg entries are read by
others from sysfs, unfortunately, it's not clear if we can always
enable DMA there)

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 68 ++
 1 file changed, 55 insertions(+), 13 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 14fedbeca724..db1cba4f99bd 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -66,7 +66,6 @@ static void fw_cfg_sel_endianness(u16 key)
iowrite16(key, fw_cfg_reg_ctrl);
 }
 
-#ifdef CONFIG_CRASH_CORE
 static inline bool fw_cfg_dma_enabled(void)
 {
return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
@@ -124,14 +123,49 @@ static ssize_t fw_cfg_dma_transfer(void *address, u32 
length, u32 control)
 
return ret;
 }
-#endif
+
+/* with acpi & dev locks taken */
+static ssize_t fw_cfg_read_blob_dma(u16 key,
+   void *buf, loff_t pos, size_t count)
+{
+   ssize_t ret;
+
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+   | FW_CFG_DMA_CTL_SELECT
+   | FW_CFG_DMA_CTL_READ);
+   } else {
+   fw_cfg_sel_endianness(key);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (ret < 0)
+   return ret;
+   ret = fw_cfg_dma_transfer(buf, count,
+   FW_CFG_DMA_CTL_READ);
+   }
+
+   return ret;
+}
+
+/* with acpi & dev locks taken */
+static ssize_t fw_cfg_read_blob_io(u16 key,
+   void *buf, loff_t pos, size_t count)
+{
+   fw_cfg_sel_endianness(key);
+   while (pos-- > 0)
+   ioread8(fw_cfg_reg_data);
+   ioread8_rep(fw_cfg_reg_data, buf, count);
+   return count;
+}
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
 static ssize_t fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+   void *buf, loff_t pos, size_t count,
+   ssize_t (*readfn)(u16 key, void *buf,
+   loff_t pos, size_t count))
 {
u32 glk = -1U;
acpi_status status;
+   ssize_t ret;
 
/* If we have ACPI, ensure mutual exclusion against any potential
 * device access by the firmware, e.g. via AML methods:
@@ -145,14 +179,19 @@ static ssize_t fw_cfg_read_blob(u16 key,
}
 
mutex_lock(_cfg_dev_lock);
-   fw_cfg_sel_endianness(key);
-   while (pos-- > 0)
-   ioread8(fw_cfg_reg_data);
-   ioread8_rep(fw_cfg_reg_data, buf, count);
+
+   /* fallback to IO if DMA is not available */
+   if (readfn == fw_cfg_read_blob_dma && !fw_cfg_dma_enabled()) {
+   readfn = fw_cfg_read_blob_io;
+   }
+
+   ret = readfn(key, buf, pos, count);
+
mutex_unlock(_cfg_dev_lock);
 
acpi_release_global_lock(glk);
-   return count;
+
+   return ret;
 }
 
 #ifdef CONFIG_CRASH_CORE
@@ -286,7 +325,7 @@

[PATCH v16 11/11] RFC: fw_cfg: do DMA read operation

2018-02-28 Thread Marc-André Lureau
Modify fw_cfg_read_blob() to use DMA if the device supports it.
Return errors, because the operation may fail.

So far, only one call in fw_cfg_register_dir_entries() is using
kmalloc'ed buf and is thus clearly eligible to DMA read.

Initially, I didn't implement DMA read to speed up boot time, but as a
first step before introducing DMA write (since read operations were
already presents). Even more, I didn't realize fw-cfg entries were
being read by the kernel during boot by default. But actally fw-cfg
entries are being populated during module probe. I knew DMA improved a
lot bios boot time (the main reason the DMA interface was added
afaik). Let see the time it would take to read the whole ACPI
tables (128kb allocated)

 # time cat /sys/firmware/qemu_fw_cfg/by_name/etc/acpi/tables/raw
  - with DMA: sys 0m0.003s
  - without DMA (-global fw_cfg.dma_enabled=off): sys 0m7.674s

FW_CFG_FILE_DIR (0x19) is the only "file" that is read during kernel
boot to populate sysfs qemu_fw_cfg directory, and it is quite
small (1-2kb). Since it does not expose itself, in order to measure
the time it takes to read such small file, I took a comparable sized
file of 2048 bytes and exposed it (-fw_cfg test,file=file with a
modified read_raw enabling DMA)

 # perf stat -r 100 cat /sys/firmware/qemu_fw_cfg/by_name/test/raw >/dev/null
  - with DMA:
  0.636037  task-clock (msec) #0.141 CPUs utilized  
  ( +-  1.19% )
  - without DMA:
  6.430128  task-clock (msec) #0.622 CPUs utilized  
  ( +-  0.22% )

That's a few msec saved during boot by enabling DMA read (the gain
would be more substantial if other & bigger fw-cfg entries are read by
others from sysfs, unfortunately, it's not clear if we can always
enable DMA there)

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 68 ++
 1 file changed, 55 insertions(+), 13 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 14fedbeca724..db1cba4f99bd 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -66,7 +66,6 @@ static void fw_cfg_sel_endianness(u16 key)
iowrite16(key, fw_cfg_reg_ctrl);
 }
 
-#ifdef CONFIG_CRASH_CORE
 static inline bool fw_cfg_dma_enabled(void)
 {
return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
@@ -124,14 +123,49 @@ static ssize_t fw_cfg_dma_transfer(void *address, u32 
length, u32 control)
 
return ret;
 }
-#endif
+
+/* with acpi & dev locks taken */
+static ssize_t fw_cfg_read_blob_dma(u16 key,
+   void *buf, loff_t pos, size_t count)
+{
+   ssize_t ret;
+
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+   | FW_CFG_DMA_CTL_SELECT
+   | FW_CFG_DMA_CTL_READ);
+   } else {
+   fw_cfg_sel_endianness(key);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (ret < 0)
+   return ret;
+   ret = fw_cfg_dma_transfer(buf, count,
+   FW_CFG_DMA_CTL_READ);
+   }
+
+   return ret;
+}
+
+/* with acpi & dev locks taken */
+static ssize_t fw_cfg_read_blob_io(u16 key,
+   void *buf, loff_t pos, size_t count)
+{
+   fw_cfg_sel_endianness(key);
+   while (pos-- > 0)
+   ioread8(fw_cfg_reg_data);
+   ioread8_rep(fw_cfg_reg_data, buf, count);
+   return count;
+}
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
 static ssize_t fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+   void *buf, loff_t pos, size_t count,
+   ssize_t (*readfn)(u16 key, void *buf,
+   loff_t pos, size_t count))
 {
u32 glk = -1U;
acpi_status status;
+   ssize_t ret;
 
/* If we have ACPI, ensure mutual exclusion against any potential
 * device access by the firmware, e.g. via AML methods:
@@ -145,14 +179,19 @@ static ssize_t fw_cfg_read_blob(u16 key,
}
 
mutex_lock(_cfg_dev_lock);
-   fw_cfg_sel_endianness(key);
-   while (pos-- > 0)
-   ioread8(fw_cfg_reg_data);
-   ioread8_rep(fw_cfg_reg_data, buf, count);
+
+   /* fallback to IO if DMA is not available */
+   if (readfn == fw_cfg_read_blob_dma && !fw_cfg_dma_enabled()) {
+   readfn = fw_cfg_read_blob_io;
+   }
+
+   ret = readfn(key, buf, pos, count);
+
mutex_unlock(_cfg_dev_lock);
 
acpi_release_global_lock(glk);
-   return count;
+
+   return ret;
 }
 
 #ifdef CONFIG_CRASH_CORE
@@ -286,7 +325,7 @@ static int fw_cfg_do_platform_pro

[PATCH v16 07/11] fw_cfg: add a public uapi header

2018-02-28 Thread Marc-André Lureau
Create a common header file for well-known values and structures to be
shared by the Linux kernel with qemu or other projects.

It is based from qemu/docs/specs/fw_cfg.txt which references
qemu/include/hw/nvram/fw_cfg_keys.h "for the most up-to-date and
authoritative list" & vmcoreinfo.txt. Those files don't have an
explicit license, but qemu/hw/nvram/fw_cfg.c is BSD-license, so
Michael S. Tsirkin suggested to use the same license.

The patch intentionally left out DMA & vmcoreinfo structures &
defines, which are added in the commits making usage of it.

Suggested-by: Michael S. Tsirkin <m...@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>

---

The related qemu patch making use of it, to be submitted:
https://github.com/elmarco/qemu/commit/4884fc9e9c4c4467a371e5a40f3181239e1b70f5
---
 MAINTAINERS  |  1 +
 drivers/firmware/qemu_fw_cfg.c   | 22 ++
 include/uapi/linux/qemu_fw_cfg.h | 66 
 3 files changed, 69 insertions(+), 20 deletions(-)
 create mode 100644 include/uapi/linux/qemu_fw_cfg.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 93a12af4f180..0ce1b3e536fd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11353,6 +11353,7 @@ M:  "Michael S. Tsirkin" <m...@redhat.com>
 L: qemu-de...@nongnu.org
 S: Maintained
 F: drivers/firmware/qemu_fw_cfg.c
+F: include/uapi/linux/qemu_fw_cfg.h
 
 QIB DRIVER
 M: Dennis Dalessandro <dennis.dalessan...@intel.com>
diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 45bfc389b226..5de6bb406fb6 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -32,30 +32,12 @@
 #include 
 #include 
 #include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo <so...@cmu.edu>");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
 MODULE_LICENSE("GPL");
 
-/* selector key values for "well-known" fw_cfg entries */
-#define FW_CFG_SIGNATURE  0x00
-#define FW_CFG_ID 0x01
-#define FW_CFG_FILE_DIR   0x19
-
-/* size in bytes of fw_cfg signature */
-#define FW_CFG_SIG_SIZE 4
-
-/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
-#define FW_CFG_MAX_FILE_PATH 56
-
-/* fw_cfg file directory entry type */
-struct fw_cfg_file {
-   u32 size;
-   u16 select;
-   u16 reserved;
-   char name[FW_CFG_MAX_FILE_PATH];
-};
-
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -616,7 +598,7 @@ MODULE_DEVICE_TABLE(of, fw_cfg_sysfs_mmio_match);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id fw_cfg_sysfs_acpi_match[] = {
-   { "QEMU0002", },
+   { FW_CFG_ACPI_DEVICE_ID, },
{},
 };
 MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
diff --git a/include/uapi/linux/qemu_fw_cfg.h b/include/uapi/linux/qemu_fw_cfg.h
new file mode 100644
index ..c698ac3812f6
--- /dev/null
+++ b/include/uapi/linux/qemu_fw_cfg.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+#ifndef _LINUX_FW_CFG_H
+#define _LINUX_FW_CFG_H
+
+#include 
+
+#define FW_CFG_ACPI_DEVICE_ID  "QEMU0002"
+
+/* selector key values for "well-known" fw_cfg entries */
+#define FW_CFG_SIGNATURE   0x00
+#define FW_CFG_ID  0x01
+#define FW_CFG_UUID0x02
+#define FW_CFG_RAM_SIZE0x03
+#define FW_CFG_NOGRAPHIC   0x04
+#define FW_CFG_NB_CPUS 0x05
+#define FW_CFG_MACHINE_ID  0x06
+#define FW_CFG_KERNEL_ADDR 0x07
+#define FW_CFG_KERNEL_SIZE 0x08
+#define FW_CFG_KERNEL_CMDLINE  0x09
+#define FW_CFG_INITRD_ADDR 0x0a
+#define FW_CFG_INITRD_SIZE 0x0b
+#define FW_CFG_BOOT_DEVICE 0x0c
+#define FW_CFG_NUMA0x0d
+#define FW_CFG_BOOT_MENU   0x0e
+#define FW_CFG_MAX_CPUS0x0f
+#define FW_CFG_KERNEL_ENTRY0x10
+#define FW_CFG_KERNEL_DATA 0x11
+#define FW_CFG_INITRD_DATA 0x12
+#define FW_CFG_CMDLINE_ADDR0x13
+#define FW_CFG_CMDLINE_SIZE0x14
+#define FW_CFG_CMDLINE_DATA0x15
+#define FW_CFG_SETUP_ADDR  0x16
+#define FW_CFG_SETUP_SIZE  0x17
+#define FW_CFG_SETUP_DATA  0x18
+#define FW_CFG_FILE_DIR0x19
+
+#define FW_CFG_FILE_FIRST  0x20
+#define FW_CFG_FILE_SLOTS_MIN  0x10
+
+#define FW_CFG_WRITE_CHANNEL   0x4000
+#define FW_CFG_ARCH_LOCAL  0x8000
+#define FW_CFG_ENTRY_MASK  (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
+
+#define FW_CFG_INVALID 0x
+
+/* width in bytes of fw_cfg control register */
+#define FW_CFG_CTL_SIZE0x02
+
+/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
+#define FW_CFG_MAX_FILE_PATH   56
+
+/* size in bytes of fw_cfg signature */
+#define FW_CFG_SIG_SIZE 4
+
+/* FW_CFG_ID bits */
+#define FW_CFG_VERSION 0x01
+
+/* fw_cfg file directory entry 

[PATCH v16 08/11] fw_cfg: add DMA register

2018-02-28 Thread Marc-André Lureau
Add an optional  kernel module (or command line) parameter
using the following syntax:

  [qemu_fw_cfg.]ioport=@[::[:]]
 or
  [qemu_fw_cfg.]mmio=@[::[:]]

and initializes the register address using given or default offset.

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
Reviewed-by: Gabriel Somlo <so...@cmu.edu>
---
 drivers/firmware/qemu_fw_cfg.c | 53 --
 1 file changed, 41 insertions(+), 12 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 5de6bb406fb6..df028faa2d00 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -10,20 +10,21 @@
  * and select subsets of aarch64), a Device Tree node (on arm), or using
  * a kernel module (or command line) parameter with the following syntax:
  *
- *  [qemu_fw_cfg.]ioport=@[::]
+ *  [qemu_fw_cfg.]ioport=@[::[:]]
  * or
- *  [qemu_fw_cfg.]mmio=@[::]
+ *  [qemu_fw_cfg.]mmio=@[::[:]]
  *
  * where:
  *   := size of ioport or mmio range
  *   := physical base address of ioport or mmio range
  *   := (optional) offset of control register
  *   := (optional) offset of data register
+ *   := (optional) offset of dma register
  *
  * e.g.:
- *  qemu_fw_cfg.ioport=2@0x510:0:1 (the default on x86)
+ *  qemu_fw_cfg.ioport=12@0x510:0:1:4  (the default on x86)
  * or
- *  qemu_fw_cfg.mmio=0xA@0x902:8:0 (the default on arm)
+ *  qemu_fw_cfg.mmio=16@0x902:8:0:16   (the default on arm)
  */
 
 #include 
@@ -45,6 +46,7 @@ static resource_size_t fw_cfg_p_size;
 static void __iomem *fw_cfg_dev_base;
 static void __iomem *fw_cfg_reg_ctrl;
 static void __iomem *fw_cfg_reg_data;
+static void __iomem *fw_cfg_reg_dma;
 
 /* atomic access to fw_cfg device (potentially slow i/o, so using mutex) */
 static DEFINE_MUTEX(fw_cfg_dev_lock);
@@ -104,12 +106,14 @@ static void fw_cfg_io_cleanup(void)
 # if (defined(CONFIG_ARM) || defined(CONFIG_ARM64))
 #  define FW_CFG_CTRL_OFF 0x08
 #  define FW_CFG_DATA_OFF 0x00
+#  define FW_CFG_DMA_OFF 0x10
 # elif (defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC32)) /* ppc/mac,sun4m 
*/
 #  define FW_CFG_CTRL_OFF 0x00
 #  define FW_CFG_DATA_OFF 0x02
 # elif (defined(CONFIG_X86) || defined(CONFIG_SPARC64)) /* x86, sun4u */
 #  define FW_CFG_CTRL_OFF 0x00
 #  define FW_CFG_DATA_OFF 0x01
+#  define FW_CFG_DMA_OFF 0x04
 # else
 #  error "QEMU FW_CFG not available on this architecture!"
 # endif
@@ -119,7 +123,7 @@ static void fw_cfg_io_cleanup(void)
 static int fw_cfg_do_platform_probe(struct platform_device *pdev)
 {
char sig[FW_CFG_SIG_SIZE];
-   struct resource *range, *ctrl, *data;
+   struct resource *range, *ctrl, *data, *dma;
 
/* acquire i/o range details */
fw_cfg_is_mmio = false;
@@ -156,6 +160,7 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
/* were custom register offsets provided (e.g. on the command line)? */
ctrl = platform_get_resource_byname(pdev, IORESOURCE_REG, "ctrl");
data = platform_get_resource_byname(pdev, IORESOURCE_REG, "data");
+   dma = platform_get_resource_byname(pdev, IORESOURCE_REG, "dma");
if (ctrl && data) {
fw_cfg_reg_ctrl = fw_cfg_dev_base + ctrl->start;
fw_cfg_reg_data = fw_cfg_dev_base + data->start;
@@ -165,6 +170,13 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
fw_cfg_reg_data = fw_cfg_dev_base + FW_CFG_DATA_OFF;
}
 
+   if (dma)
+   fw_cfg_reg_dma = fw_cfg_dev_base + dma->start;
+#ifdef FW_CFG_DMA_OFF
+   else
+   fw_cfg_reg_dma = fw_cfg_dev_base + FW_CFG_DMA_OFF;
+#endif
+
/* verify fw_cfg device signature */
if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
0, FW_CFG_SIG_SIZE) < 0 ||
@@ -630,6 +642,7 @@ static struct platform_device *fw_cfg_cmdline_dev;
 /* use special scanf/printf modifier for phys_addr_t, resource_size_t */
 #define PH_ADDR_SCAN_FMT "@%" __PHYS_ADDR_PREFIX "i%n" \
 ":%" __PHYS_ADDR_PREFIX "i" \
+":%" __PHYS_ADDR_PREFIX "i%n" \
 ":%" __PHYS_ADDR_PREFIX "i%n"
 
 #define PH_ADDR_PR_1_FMT "0x%" __PHYS_ADDR_PREFIX "x@" \
@@ -639,12 +652,15 @@ static struct platform_device *fw_cfg_cmdline_dev;
 ":%" __PHYS_ADDR_PREFIX "u" \
 ":%" __PHYS_ADDR_PREFIX "u"
 
+#define PH_ADDR_PR_4_FMT PH_ADDR_PR_3_FMT \
+":%" __PHYS_ADDR_PREFIX "u"
+
 static int fw_cfg_cmdline_set(const char *arg, const struct kernel_param *kp)
 {
-   struct resource res[3] = {};
+   struct resource res[4] 

[PATCH v16 08/11] fw_cfg: add DMA register

2018-02-28 Thread Marc-André Lureau
Add an optional  kernel module (or command line) parameter
using the following syntax:

  [qemu_fw_cfg.]ioport=@[::[:]]
 or
  [qemu_fw_cfg.]mmio=@[::[:]]

and initializes the register address using given or default offset.

Signed-off-by: Marc-André Lureau 
Reviewed-by: Gabriel Somlo 
---
 drivers/firmware/qemu_fw_cfg.c | 53 --
 1 file changed, 41 insertions(+), 12 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 5de6bb406fb6..df028faa2d00 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -10,20 +10,21 @@
  * and select subsets of aarch64), a Device Tree node (on arm), or using
  * a kernel module (or command line) parameter with the following syntax:
  *
- *  [qemu_fw_cfg.]ioport=@[::]
+ *  [qemu_fw_cfg.]ioport=@[::[:]]
  * or
- *  [qemu_fw_cfg.]mmio=@[::]
+ *  [qemu_fw_cfg.]mmio=@[::[:]]
  *
  * where:
  *   := size of ioport or mmio range
  *   := physical base address of ioport or mmio range
  *   := (optional) offset of control register
  *   := (optional) offset of data register
+ *   := (optional) offset of dma register
  *
  * e.g.:
- *  qemu_fw_cfg.ioport=2@0x510:0:1 (the default on x86)
+ *  qemu_fw_cfg.ioport=12@0x510:0:1:4  (the default on x86)
  * or
- *  qemu_fw_cfg.mmio=0xA@0x902:8:0 (the default on arm)
+ *  qemu_fw_cfg.mmio=16@0x902:8:0:16   (the default on arm)
  */
 
 #include 
@@ -45,6 +46,7 @@ static resource_size_t fw_cfg_p_size;
 static void __iomem *fw_cfg_dev_base;
 static void __iomem *fw_cfg_reg_ctrl;
 static void __iomem *fw_cfg_reg_data;
+static void __iomem *fw_cfg_reg_dma;
 
 /* atomic access to fw_cfg device (potentially slow i/o, so using mutex) */
 static DEFINE_MUTEX(fw_cfg_dev_lock);
@@ -104,12 +106,14 @@ static void fw_cfg_io_cleanup(void)
 # if (defined(CONFIG_ARM) || defined(CONFIG_ARM64))
 #  define FW_CFG_CTRL_OFF 0x08
 #  define FW_CFG_DATA_OFF 0x00
+#  define FW_CFG_DMA_OFF 0x10
 # elif (defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC32)) /* ppc/mac,sun4m 
*/
 #  define FW_CFG_CTRL_OFF 0x00
 #  define FW_CFG_DATA_OFF 0x02
 # elif (defined(CONFIG_X86) || defined(CONFIG_SPARC64)) /* x86, sun4u */
 #  define FW_CFG_CTRL_OFF 0x00
 #  define FW_CFG_DATA_OFF 0x01
+#  define FW_CFG_DMA_OFF 0x04
 # else
 #  error "QEMU FW_CFG not available on this architecture!"
 # endif
@@ -119,7 +123,7 @@ static void fw_cfg_io_cleanup(void)
 static int fw_cfg_do_platform_probe(struct platform_device *pdev)
 {
char sig[FW_CFG_SIG_SIZE];
-   struct resource *range, *ctrl, *data;
+   struct resource *range, *ctrl, *data, *dma;
 
/* acquire i/o range details */
fw_cfg_is_mmio = false;
@@ -156,6 +160,7 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
/* were custom register offsets provided (e.g. on the command line)? */
ctrl = platform_get_resource_byname(pdev, IORESOURCE_REG, "ctrl");
data = platform_get_resource_byname(pdev, IORESOURCE_REG, "data");
+   dma = platform_get_resource_byname(pdev, IORESOURCE_REG, "dma");
if (ctrl && data) {
fw_cfg_reg_ctrl = fw_cfg_dev_base + ctrl->start;
fw_cfg_reg_data = fw_cfg_dev_base + data->start;
@@ -165,6 +170,13 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
fw_cfg_reg_data = fw_cfg_dev_base + FW_CFG_DATA_OFF;
}
 
+   if (dma)
+   fw_cfg_reg_dma = fw_cfg_dev_base + dma->start;
+#ifdef FW_CFG_DMA_OFF
+   else
+   fw_cfg_reg_dma = fw_cfg_dev_base + FW_CFG_DMA_OFF;
+#endif
+
/* verify fw_cfg device signature */
if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
0, FW_CFG_SIG_SIZE) < 0 ||
@@ -630,6 +642,7 @@ static struct platform_device *fw_cfg_cmdline_dev;
 /* use special scanf/printf modifier for phys_addr_t, resource_size_t */
 #define PH_ADDR_SCAN_FMT "@%" __PHYS_ADDR_PREFIX "i%n" \
 ":%" __PHYS_ADDR_PREFIX "i" \
+":%" __PHYS_ADDR_PREFIX "i%n" \
 ":%" __PHYS_ADDR_PREFIX "i%n"
 
 #define PH_ADDR_PR_1_FMT "0x%" __PHYS_ADDR_PREFIX "x@" \
@@ -639,12 +652,15 @@ static struct platform_device *fw_cfg_cmdline_dev;
 ":%" __PHYS_ADDR_PREFIX "u" \
 ":%" __PHYS_ADDR_PREFIX "u"
 
+#define PH_ADDR_PR_4_FMT PH_ADDR_PR_3_FMT \
+":%" __PHYS_ADDR_PREFIX "u"
+
 static int fw_cfg_cmdline_set(const char *arg, const struct kernel_param *kp)
 {
-   struct resource res[3] = {};
+   struct resource res[4] = {};
char *str;
phys_addr_t base;
-

[PATCH v16 07/11] fw_cfg: add a public uapi header

2018-02-28 Thread Marc-André Lureau
Create a common header file for well-known values and structures to be
shared by the Linux kernel with qemu or other projects.

It is based from qemu/docs/specs/fw_cfg.txt which references
qemu/include/hw/nvram/fw_cfg_keys.h "for the most up-to-date and
authoritative list" & vmcoreinfo.txt. Those files don't have an
explicit license, but qemu/hw/nvram/fw_cfg.c is BSD-license, so
Michael S. Tsirkin suggested to use the same license.

The patch intentionally left out DMA & vmcoreinfo structures &
defines, which are added in the commits making usage of it.

Suggested-by: Michael S. Tsirkin 
Signed-off-by: Marc-André Lureau 

---

The related qemu patch making use of it, to be submitted:
https://github.com/elmarco/qemu/commit/4884fc9e9c4c4467a371e5a40f3181239e1b70f5
---
 MAINTAINERS  |  1 +
 drivers/firmware/qemu_fw_cfg.c   | 22 ++
 include/uapi/linux/qemu_fw_cfg.h | 66 
 3 files changed, 69 insertions(+), 20 deletions(-)
 create mode 100644 include/uapi/linux/qemu_fw_cfg.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 93a12af4f180..0ce1b3e536fd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11353,6 +11353,7 @@ M:  "Michael S. Tsirkin" 
 L: qemu-de...@nongnu.org
 S: Maintained
 F: drivers/firmware/qemu_fw_cfg.c
+F: include/uapi/linux/qemu_fw_cfg.h
 
 QIB DRIVER
 M: Dennis Dalessandro 
diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 45bfc389b226..5de6bb406fb6 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -32,30 +32,12 @@
 #include 
 #include 
 #include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo ");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
 MODULE_LICENSE("GPL");
 
-/* selector key values for "well-known" fw_cfg entries */
-#define FW_CFG_SIGNATURE  0x00
-#define FW_CFG_ID 0x01
-#define FW_CFG_FILE_DIR   0x19
-
-/* size in bytes of fw_cfg signature */
-#define FW_CFG_SIG_SIZE 4
-
-/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
-#define FW_CFG_MAX_FILE_PATH 56
-
-/* fw_cfg file directory entry type */
-struct fw_cfg_file {
-   u32 size;
-   u16 select;
-   u16 reserved;
-   char name[FW_CFG_MAX_FILE_PATH];
-};
-
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -616,7 +598,7 @@ MODULE_DEVICE_TABLE(of, fw_cfg_sysfs_mmio_match);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id fw_cfg_sysfs_acpi_match[] = {
-   { "QEMU0002", },
+   { FW_CFG_ACPI_DEVICE_ID, },
{},
 };
 MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
diff --git a/include/uapi/linux/qemu_fw_cfg.h b/include/uapi/linux/qemu_fw_cfg.h
new file mode 100644
index ..c698ac3812f6
--- /dev/null
+++ b/include/uapi/linux/qemu_fw_cfg.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+#ifndef _LINUX_FW_CFG_H
+#define _LINUX_FW_CFG_H
+
+#include 
+
+#define FW_CFG_ACPI_DEVICE_ID  "QEMU0002"
+
+/* selector key values for "well-known" fw_cfg entries */
+#define FW_CFG_SIGNATURE   0x00
+#define FW_CFG_ID  0x01
+#define FW_CFG_UUID0x02
+#define FW_CFG_RAM_SIZE0x03
+#define FW_CFG_NOGRAPHIC   0x04
+#define FW_CFG_NB_CPUS 0x05
+#define FW_CFG_MACHINE_ID  0x06
+#define FW_CFG_KERNEL_ADDR 0x07
+#define FW_CFG_KERNEL_SIZE 0x08
+#define FW_CFG_KERNEL_CMDLINE  0x09
+#define FW_CFG_INITRD_ADDR 0x0a
+#define FW_CFG_INITRD_SIZE 0x0b
+#define FW_CFG_BOOT_DEVICE 0x0c
+#define FW_CFG_NUMA0x0d
+#define FW_CFG_BOOT_MENU   0x0e
+#define FW_CFG_MAX_CPUS0x0f
+#define FW_CFG_KERNEL_ENTRY0x10
+#define FW_CFG_KERNEL_DATA 0x11
+#define FW_CFG_INITRD_DATA 0x12
+#define FW_CFG_CMDLINE_ADDR0x13
+#define FW_CFG_CMDLINE_SIZE0x14
+#define FW_CFG_CMDLINE_DATA0x15
+#define FW_CFG_SETUP_ADDR  0x16
+#define FW_CFG_SETUP_SIZE  0x17
+#define FW_CFG_SETUP_DATA  0x18
+#define FW_CFG_FILE_DIR0x19
+
+#define FW_CFG_FILE_FIRST  0x20
+#define FW_CFG_FILE_SLOTS_MIN  0x10
+
+#define FW_CFG_WRITE_CHANNEL   0x4000
+#define FW_CFG_ARCH_LOCAL  0x8000
+#define FW_CFG_ENTRY_MASK  (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
+
+#define FW_CFG_INVALID 0x
+
+/* width in bytes of fw_cfg control register */
+#define FW_CFG_CTL_SIZE0x02
+
+/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
+#define FW_CFG_MAX_FILE_PATH   56
+
+/* size in bytes of fw_cfg signature */
+#define FW_CFG_SIG_SIZE 4
+
+/* FW_CFG_ID bits */
+#define FW_CFG_VERSION 0x01
+
+/* fw_cfg file directory entry type */
+struct fw_cfg_file {
+   __be32 size;
+   __be16 select;
+   __u16 reserved;
+   char name[FW_CFG_MAX_FILE_PATH];
+};
+
+#endif
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 03/11] fw_cfg: fix sparse warning reading FW_CFG_ID

2018-02-28 Thread Marc-André Lureau
Use a restricted type for reading FW_CFG_ID, fixing sparse warning:

drivers/firmware/qemu_fw_cfg.c:540:22: warning: cast to restricted __le32

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 7978844f6b37..0eb155fdfb35 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -530,6 +530,7 @@ static inline void fw_cfg_kobj_cleanup(struct kobject *kobj)
 static int fw_cfg_sysfs_probe(struct platform_device *pdev)
 {
int err;
+   __le32 rev;
 
/* NOTE: If we supported multiple fw_cfg devices, we'd first create
 * a subdirectory named after e.g. pdev->id, then hang per-device
@@ -555,8 +556,8 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)
goto err_probe;
 
/* get revision number, add matching top-level attribute */
-   fw_cfg_read_blob(FW_CFG_ID, _cfg_rev, 0, sizeof(fw_cfg_rev));
-   fw_cfg_rev = le32_to_cpu(fw_cfg_rev);
+   fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   fw_cfg_rev = le32_to_cpu(rev);
err = sysfs_create_file(fw_cfg_top_ko, _cfg_rev_attr.attr);
if (err)
goto err_rev;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 03/11] fw_cfg: fix sparse warning reading FW_CFG_ID

2018-02-28 Thread Marc-André Lureau
Use a restricted type for reading FW_CFG_ID, fixing sparse warning:

drivers/firmware/qemu_fw_cfg.c:540:22: warning: cast to restricted __le32

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 7978844f6b37..0eb155fdfb35 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -530,6 +530,7 @@ static inline void fw_cfg_kobj_cleanup(struct kobject *kobj)
 static int fw_cfg_sysfs_probe(struct platform_device *pdev)
 {
int err;
+   __le32 rev;
 
/* NOTE: If we supported multiple fw_cfg devices, we'd first create
 * a subdirectory named after e.g. pdev->id, then hang per-device
@@ -555,8 +556,8 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)
goto err_probe;
 
/* get revision number, add matching top-level attribute */
-   fw_cfg_read_blob(FW_CFG_ID, _cfg_rev, 0, sizeof(fw_cfg_rev));
-   fw_cfg_rev = le32_to_cpu(fw_cfg_rev);
+   fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   fw_cfg_rev = le32_to_cpu(rev);
err = sysfs_create_file(fw_cfg_top_ko, _cfg_rev_attr.attr);
if (err)
goto err_rev;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 02/11] fw_cfg: fix sparse warnings with fw_cfg_file

2018-02-28 Thread Marc-André Lureau
Modify fw_cfg_sysfs_entry to store entry values, instead of reusing
the restricted types.

Fixes warnings such as:

$ make C=1 CF=-D__CHECK_ENDIAN__ drivers/firmware/qemu_fw_cfg.o

drivers/firmware/qemu_fw_cfg.c:491:29: warning: incorrect type in assignment 
(different base types)
drivers/firmware/qemu_fw_cfg.c:491:29:expected restricted __be32 [usertype] 
size
drivers/firmware/qemu_fw_cfg.c:491:29:got unsigned int
drivers/firmware/qemu_fw_cfg.c:492:31: warning: incorrect type in assignment 
(different base types)
drivers/firmware/qemu_fw_cfg.c:492:31:expected restricted __be16 [usertype] 
select
drivers/firmware/qemu_fw_cfg.c:492:31:got int

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 28 +++-
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index e7ea2b3b1d11..7978844f6b37 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -211,7 +211,9 @@ static const struct {
 /* fw_cfg_sysfs_entry type */
 struct fw_cfg_sysfs_entry {
struct kobject kobj;
-   struct fw_cfg_file f;
+   u32 size;
+   u16 select;
+   char name[FW_CFG_MAX_FILE_PATH];
struct list_head list;
 };
 
@@ -275,17 +277,17 @@ struct fw_cfg_sysfs_attribute fw_cfg_sysfs_attr_##_attr = 
{ \
 
 static ssize_t fw_cfg_sysfs_show_size(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%u\n", e->f.size);
+   return sprintf(buf, "%u\n", e->size);
 }
 
 static ssize_t fw_cfg_sysfs_show_key(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%u\n", e->f.select);
+   return sprintf(buf, "%u\n", e->select);
 }
 
 static ssize_t fw_cfg_sysfs_show_name(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%s\n", e->f.name);
+   return sprintf(buf, "%s\n", e->name);
 }
 
 static FW_CFG_SYSFS_ATTR(size);
@@ -336,13 +338,13 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, 
struct kobject *kobj,
 {
struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
 
-   if (pos > entry->f.size)
+   if (pos > entry->size)
return -EINVAL;
 
-   if (count > entry->f.size - pos)
-   count = entry->f.size - pos;
+   if (count > entry->size - pos)
+   count = entry->size - pos;
 
-   fw_cfg_read_blob(entry->f.select, buf, pos, count);
+   fw_cfg_read_blob(entry->select, buf, pos, count);
return count;
 }
 
@@ -461,11 +463,13 @@ static int fw_cfg_register_file(const struct fw_cfg_file 
*f)
return -ENOMEM;
 
/* set file entry information */
-   memcpy(>f, f, sizeof(struct fw_cfg_file));
+   entry->size = be32_to_cpu(f->size);
+   entry->select = be16_to_cpu(f->select);
+   memcpy(entry->name, f->name, FW_CFG_MAX_FILE_PATH);
 
/* register entry under "/sys/firmware/qemu_fw_cfg/by_key/" */
err = kobject_init_and_add(>kobj, _cfg_sysfs_entry_ktype,
-  fw_cfg_sel_ko, "%d", entry->f.select);
+  fw_cfg_sel_ko, "%d", entry->select);
if (err)
goto err_register;
 
@@ -475,7 +479,7 @@ static int fw_cfg_register_file(const struct fw_cfg_file *f)
goto err_add_raw;
 
/* try adding "/sys/firmware/qemu_fw_cfg/by_name/" symlink */
-   fw_cfg_build_symlink(fw_cfg_fname_kset, >kobj, entry->f.name);
+   fw_cfg_build_symlink(fw_cfg_fname_kset, >kobj, entry->name);
 
/* success, add entry to global cache */
fw_cfg_sysfs_cache_enlist(entry);
@@ -507,8 +511,6 @@ static int fw_cfg_register_dir_entries(void)
fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
 
for (i = 0; i < count; i++) {
-   dir[i].size = be32_to_cpu(dir[i].size);
-   dir[i].select = be16_to_cpu(dir[i].select);
ret = fw_cfg_register_file([i]);
if (ret)
break;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 02/11] fw_cfg: fix sparse warnings with fw_cfg_file

2018-02-28 Thread Marc-André Lureau
Modify fw_cfg_sysfs_entry to store entry values, instead of reusing
the restricted types.

Fixes warnings such as:

$ make C=1 CF=-D__CHECK_ENDIAN__ drivers/firmware/qemu_fw_cfg.o

drivers/firmware/qemu_fw_cfg.c:491:29: warning: incorrect type in assignment 
(different base types)
drivers/firmware/qemu_fw_cfg.c:491:29:expected restricted __be32 [usertype] 
size
drivers/firmware/qemu_fw_cfg.c:491:29:got unsigned int
drivers/firmware/qemu_fw_cfg.c:492:31: warning: incorrect type in assignment 
(different base types)
drivers/firmware/qemu_fw_cfg.c:492:31:expected restricted __be16 [usertype] 
select
drivers/firmware/qemu_fw_cfg.c:492:31:got int

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 28 +++-
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index e7ea2b3b1d11..7978844f6b37 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -211,7 +211,9 @@ static const struct {
 /* fw_cfg_sysfs_entry type */
 struct fw_cfg_sysfs_entry {
struct kobject kobj;
-   struct fw_cfg_file f;
+   u32 size;
+   u16 select;
+   char name[FW_CFG_MAX_FILE_PATH];
struct list_head list;
 };
 
@@ -275,17 +277,17 @@ struct fw_cfg_sysfs_attribute fw_cfg_sysfs_attr_##_attr = 
{ \
 
 static ssize_t fw_cfg_sysfs_show_size(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%u\n", e->f.size);
+   return sprintf(buf, "%u\n", e->size);
 }
 
 static ssize_t fw_cfg_sysfs_show_key(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%u\n", e->f.select);
+   return sprintf(buf, "%u\n", e->select);
 }
 
 static ssize_t fw_cfg_sysfs_show_name(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%s\n", e->f.name);
+   return sprintf(buf, "%s\n", e->name);
 }
 
 static FW_CFG_SYSFS_ATTR(size);
@@ -336,13 +338,13 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, 
struct kobject *kobj,
 {
struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
 
-   if (pos > entry->f.size)
+   if (pos > entry->size)
return -EINVAL;
 
-   if (count > entry->f.size - pos)
-   count = entry->f.size - pos;
+   if (count > entry->size - pos)
+   count = entry->size - pos;
 
-   fw_cfg_read_blob(entry->f.select, buf, pos, count);
+   fw_cfg_read_blob(entry->select, buf, pos, count);
return count;
 }
 
@@ -461,11 +463,13 @@ static int fw_cfg_register_file(const struct fw_cfg_file 
*f)
return -ENOMEM;
 
/* set file entry information */
-   memcpy(>f, f, sizeof(struct fw_cfg_file));
+   entry->size = be32_to_cpu(f->size);
+   entry->select = be16_to_cpu(f->select);
+   memcpy(entry->name, f->name, FW_CFG_MAX_FILE_PATH);
 
/* register entry under "/sys/firmware/qemu_fw_cfg/by_key/" */
err = kobject_init_and_add(>kobj, _cfg_sysfs_entry_ktype,
-  fw_cfg_sel_ko, "%d", entry->f.select);
+  fw_cfg_sel_ko, "%d", entry->select);
if (err)
goto err_register;
 
@@ -475,7 +479,7 @@ static int fw_cfg_register_file(const struct fw_cfg_file *f)
goto err_add_raw;
 
/* try adding "/sys/firmware/qemu_fw_cfg/by_name/" symlink */
-   fw_cfg_build_symlink(fw_cfg_fname_kset, >kobj, entry->f.name);
+   fw_cfg_build_symlink(fw_cfg_fname_kset, >kobj, entry->name);
 
/* success, add entry to global cache */
fw_cfg_sysfs_cache_enlist(entry);
@@ -507,8 +511,6 @@ static int fw_cfg_register_dir_entries(void)
fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
 
for (i = 0; i < count; i++) {
-   dir[i].size = be32_to_cpu(dir[i].size);
-   dir[i].select = be16_to_cpu(dir[i].select);
ret = fw_cfg_register_file([i]);
if (ret)
break;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 00/11] fw_cfg: add DMA operations & etc/vmcoreinfo support

2018-02-28 Thread Marc-André Lureau
Hi,

This series adds DMA operations support to the qemu fw_cfg kernel
module and populates "etc/vmcoreinfo" with vmcoreinfo location
details (entry added since qemu 2.11 with -device vmcoreinfo).

v16:
- patch reordering
- commit message updates
- rename fw_cfg.h -> qemu_fw_cfg.h
- fix warning when CONFIG_CRASH_CORE=n without RFC DMA read patch
  applied
- use a function pointer rather than a dma hint to read_blob()

v15:
- fix fw_cfg.h uapi header #include
- use BSD license for fw_cfg.h uapi header
- move the uapi defines/structs for DMA & vmcoreinfo in the
  corresponding patch
- use cpu_relax() instead of usleep_range(50, 100);
- replace do { } while(true) by for (;;)
- fix the rmb() call location
- add a preliminary patch to handle error from fw_cfg_write_blob()
- rewrite fw_cfg_sel_endianness() to wrap iowrite() calls

v14:
- add "fw_cfg: add a public uapi header"
- fix sparse warnings & don't introduce new warnings
- add memory barriers to force IO ordering
- split fw_cfg_read_blob() in fw_cfg_read_blob_io() and
  fw_cfg_read_blob_dma()
- add error handling to fw_cfg_read_blob() callers
- minor stylistic changes

v13:
- reorder patch series, introduce DMA write before DMA read
- do some measurements of DMA read speed-ups

v12:
- fix virt_to_phys(NULL) panic with CONFIG_DEBUG_VIRTUAL=y
- do not use DMA read, except for kmalloc() memory we allocated
  ourself (only fw_cfg_register_dir_entries() so far)

v11:
- add #include  in last patch,
  fixing kbuild .config test

Marc-André Lureau (11):
  fw_cfg: fix sparse warnings in fw_cfg_sel_endianness()
  fw_cfg: fix sparse warnings with fw_cfg_file
  fw_cfg: fix sparse warning reading FW_CFG_ID
  fw_cfg: fix sparse warnings around FW_CFG_FILE_DIR read
  fw_cfg: remove inline from fw_cfg_read_blob()
  fw_cfg: handle fw_cfg_read_blob() error
  fw_cfg: add a public uapi header
  fw_cfg: add DMA register
  crash: export paddr_vmcoreinfo_note()
  fw_cfg: write vmcoreinfo details
  RFC: fw_cfg: do DMA read operation

 MAINTAINERS  |   1 +
 drivers/firmware/qemu_fw_cfg.c   | 339 +++
 include/uapi/linux/qemu_fw_cfg.h |  97 +++
 kernel/crash_core.c  |   1 +
 4 files changed, 374 insertions(+), 64 deletions(-)
 create mode 100644 include/uapi/linux/qemu_fw_cfg.h

-- 
2.16.1.73.g5832b7e9f2



[PATCH v16 00/11] fw_cfg: add DMA operations & etc/vmcoreinfo support

2018-02-28 Thread Marc-André Lureau
Hi,

This series adds DMA operations support to the qemu fw_cfg kernel
module and populates "etc/vmcoreinfo" with vmcoreinfo location
details (entry added since qemu 2.11 with -device vmcoreinfo).

v16:
- patch reordering
- commit message updates
- rename fw_cfg.h -> qemu_fw_cfg.h
- fix warning when CONFIG_CRASH_CORE=n without RFC DMA read patch
  applied
- use a function pointer rather than a dma hint to read_blob()

v15:
- fix fw_cfg.h uapi header #include
- use BSD license for fw_cfg.h uapi header
- move the uapi defines/structs for DMA & vmcoreinfo in the
  corresponding patch
- use cpu_relax() instead of usleep_range(50, 100);
- replace do { } while(true) by for (;;)
- fix the rmb() call location
- add a preliminary patch to handle error from fw_cfg_write_blob()
- rewrite fw_cfg_sel_endianness() to wrap iowrite() calls

v14:
- add "fw_cfg: add a public uapi header"
- fix sparse warnings & don't introduce new warnings
- add memory barriers to force IO ordering
- split fw_cfg_read_blob() in fw_cfg_read_blob_io() and
  fw_cfg_read_blob_dma()
- add error handling to fw_cfg_read_blob() callers
- minor stylistic changes

v13:
- reorder patch series, introduce DMA write before DMA read
- do some measurements of DMA read speed-ups

v12:
- fix virt_to_phys(NULL) panic with CONFIG_DEBUG_VIRTUAL=y
- do not use DMA read, except for kmalloc() memory we allocated
  ourself (only fw_cfg_register_dir_entries() so far)

v11:
- add #include  in last patch,
  fixing kbuild .config test

Marc-André Lureau (11):
  fw_cfg: fix sparse warnings in fw_cfg_sel_endianness()
  fw_cfg: fix sparse warnings with fw_cfg_file
  fw_cfg: fix sparse warning reading FW_CFG_ID
  fw_cfg: fix sparse warnings around FW_CFG_FILE_DIR read
  fw_cfg: remove inline from fw_cfg_read_blob()
  fw_cfg: handle fw_cfg_read_blob() error
  fw_cfg: add a public uapi header
  fw_cfg: add DMA register
  crash: export paddr_vmcoreinfo_note()
  fw_cfg: write vmcoreinfo details
  RFC: fw_cfg: do DMA read operation

 MAINTAINERS  |   1 +
 drivers/firmware/qemu_fw_cfg.c   | 339 +++
 include/uapi/linux/qemu_fw_cfg.h |  97 +++
 kernel/crash_core.c  |   1 +
 4 files changed, 374 insertions(+), 64 deletions(-)
 create mode 100644 include/uapi/linux/qemu_fw_cfg.h

-- 
2.16.1.73.g5832b7e9f2



Re: [PATCH] fw_cfg: avoid unused function warning

2018-02-28 Thread Marc-André Lureau
Hi

On Wed, Feb 28, 2018 at 2:33 PM, Arnd Bergmann  wrote:
> The newly introduced fw_cfg_dma_transfer() function is unused when
> CONFIG_CRASH_CORE is disabled:
>
> drivers/firmware/qemu_fw_cfg.c:89:16: error: 'fw_cfg_dma_transfer' defined 
> but not used [-Werror=unused-function]
>  static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
>
> This moves it into the #ifdef section that hides its caller to avoid the
> warning.
>
> Fixes: 47e78bfb5426 ("fw_cfg: write vmcoreinfo details")
> Signed-off-by: Arnd Bergmann 

I don't know from which tree you found this, I suppose from
mst/linux-next (which btw, I don't know which version got partially
applied).

This is a regression in v13, because dma read is last patch now, as RFC.
Fixed in upcoming v16.

thanks

> ---
>  drivers/firmware/qemu_fw_cfg.c | 60 
> +-
>  1 file changed, 30 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
> index 3015e77aebca..f002bb40519b 100644
> --- a/drivers/firmware/qemu_fw_cfg.c
> +++ b/drivers/firmware/qemu_fw_cfg.c
> @@ -66,6 +66,36 @@ static void fw_cfg_sel_endianness(u16 key)
> iowrite16(key, fw_cfg_reg_ctrl);
>  }
>
> +/* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
> +static ssize_t fw_cfg_read_blob(u16 key,
> +   void *buf, loff_t pos, size_t count)
> +{
> +   u32 glk = -1U;
> +   acpi_status status;
> +
> +   /* If we have ACPI, ensure mutual exclusion against any potential
> +* device access by the firmware, e.g. via AML methods:
> +*/
> +   status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
> +   if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
> +   /* Should never get here */
> +   WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
> +   memset(buf, 0, count);
> +   return -EINVAL;
> +   }
> +
> +   mutex_lock(_cfg_dev_lock);
> +   fw_cfg_sel_endianness(key);
> +   while (pos-- > 0)
> +   ioread8(fw_cfg_reg_data);
> +   ioread8_rep(fw_cfg_reg_data, buf, count);
> +   mutex_unlock(_cfg_dev_lock);
> +
> +   acpi_release_global_lock(glk);
> +   return count;
> +}
> +
> +#ifdef CONFIG_CRASH_CORE
>  static inline bool fw_cfg_dma_enabled(void)
>  {
> return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
> @@ -124,36 +154,6 @@ static ssize_t fw_cfg_dma_transfer(void *address, u32 
> length, u32 control)
> return ret;
>  }
>
> -/* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
> -static ssize_t fw_cfg_read_blob(u16 key,
> -   void *buf, loff_t pos, size_t count)
> -{
> -   u32 glk = -1U;
> -   acpi_status status;
> -
> -   /* If we have ACPI, ensure mutual exclusion against any potential
> -* device access by the firmware, e.g. via AML methods:
> -*/
> -   status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
> -   if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
> -   /* Should never get here */
> -   WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
> -   memset(buf, 0, count);
> -   return -EINVAL;
> -   }
> -
> -   mutex_lock(_cfg_dev_lock);
> -   fw_cfg_sel_endianness(key);
> -   while (pos-- > 0)
> -   ioread8(fw_cfg_reg_data);
> -   ioread8_rep(fw_cfg_reg_data, buf, count);
> -   mutex_unlock(_cfg_dev_lock);
> -
> -   acpi_release_global_lock(glk);
> -   return count;
> -}
> -
> -#ifdef CONFIG_CRASH_CORE
>  /* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
>  static ssize_t fw_cfg_write_blob(u16 key,
>  void *buf, loff_t pos, size_t count)
> --
> 2.9.0
>


Re: [PATCH] fw_cfg: avoid unused function warning

2018-02-28 Thread Marc-André Lureau
Hi

On Wed, Feb 28, 2018 at 2:33 PM, Arnd Bergmann  wrote:
> The newly introduced fw_cfg_dma_transfer() function is unused when
> CONFIG_CRASH_CORE is disabled:
>
> drivers/firmware/qemu_fw_cfg.c:89:16: error: 'fw_cfg_dma_transfer' defined 
> but not used [-Werror=unused-function]
>  static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
>
> This moves it into the #ifdef section that hides its caller to avoid the
> warning.
>
> Fixes: 47e78bfb5426 ("fw_cfg: write vmcoreinfo details")
> Signed-off-by: Arnd Bergmann 

I don't know from which tree you found this, I suppose from
mst/linux-next (which btw, I don't know which version got partially
applied).

This is a regression in v13, because dma read is last patch now, as RFC.
Fixed in upcoming v16.

thanks

> ---
>  drivers/firmware/qemu_fw_cfg.c | 60 
> +-
>  1 file changed, 30 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
> index 3015e77aebca..f002bb40519b 100644
> --- a/drivers/firmware/qemu_fw_cfg.c
> +++ b/drivers/firmware/qemu_fw_cfg.c
> @@ -66,6 +66,36 @@ static void fw_cfg_sel_endianness(u16 key)
> iowrite16(key, fw_cfg_reg_ctrl);
>  }
>
> +/* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
> +static ssize_t fw_cfg_read_blob(u16 key,
> +   void *buf, loff_t pos, size_t count)
> +{
> +   u32 glk = -1U;
> +   acpi_status status;
> +
> +   /* If we have ACPI, ensure mutual exclusion against any potential
> +* device access by the firmware, e.g. via AML methods:
> +*/
> +   status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
> +   if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
> +   /* Should never get here */
> +   WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
> +   memset(buf, 0, count);
> +   return -EINVAL;
> +   }
> +
> +   mutex_lock(_cfg_dev_lock);
> +   fw_cfg_sel_endianness(key);
> +   while (pos-- > 0)
> +   ioread8(fw_cfg_reg_data);
> +   ioread8_rep(fw_cfg_reg_data, buf, count);
> +   mutex_unlock(_cfg_dev_lock);
> +
> +   acpi_release_global_lock(glk);
> +   return count;
> +}
> +
> +#ifdef CONFIG_CRASH_CORE
>  static inline bool fw_cfg_dma_enabled(void)
>  {
> return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
> @@ -124,36 +154,6 @@ static ssize_t fw_cfg_dma_transfer(void *address, u32 
> length, u32 control)
> return ret;
>  }
>
> -/* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
> -static ssize_t fw_cfg_read_blob(u16 key,
> -   void *buf, loff_t pos, size_t count)
> -{
> -   u32 glk = -1U;
> -   acpi_status status;
> -
> -   /* If we have ACPI, ensure mutual exclusion against any potential
> -* device access by the firmware, e.g. via AML methods:
> -*/
> -   status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
> -   if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
> -   /* Should never get here */
> -   WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
> -   memset(buf, 0, count);
> -   return -EINVAL;
> -   }
> -
> -   mutex_lock(_cfg_dev_lock);
> -   fw_cfg_sel_endianness(key);
> -   while (pos-- > 0)
> -   ioread8(fw_cfg_reg_data);
> -   ioread8_rep(fw_cfg_reg_data, buf, count);
> -   mutex_unlock(_cfg_dev_lock);
> -
> -   acpi_release_global_lock(glk);
> -   return count;
> -}
> -
> -#ifdef CONFIG_CRASH_CORE
>  /* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
>  static ssize_t fw_cfg_write_blob(u16 key,
>  void *buf, loff_t pos, size_t count)
> --
> 2.9.0
>


Re: [PATCH v15 11/11] RFC: fw_cfg: do DMA read operation

2018-02-28 Thread Marc-André Lureau
Hi

On Tue, Feb 27, 2018 at 1:04 AM, Michael S. Tsirkin <m...@redhat.com> wrote:
> On Thu, Feb 15, 2018 at 10:33:12PM +0100, Marc-André Lureau wrote:
>> Modify fw_cfg_read_blob() to use DMA if the device supports it.
>> Return errors, because the operation may fail.
>>
>> So far, only one call in fw_cfg_register_dir_entries() is using
>> kmalloc'ed buf and is thus clearly eligible to DMA read.
>>
>> Initially, I didn't implement DMA read to speed up boot time, but as a
>> first step before introducing DMA write (since read operations were
>> already presents). Even more, I didn't realize fw-cfg entries were
>> being read by the kernel during boot by default. But actally fw-cfg
>> entries are being populated during module probe. I knew DMA improved a
>> lot bios boot time (the main reason the DMA interface was added
>> afaik). Let see the time it would take to read the whole ACPI
>> tables (128kb allocated)
>>
>>  # time cat /sys/firmware/qemu_fw_cfg/by_name/etc/acpi/tables/raw
>>   - with DMA: sys 0m0.003s
>>   - without DMA (-global fw_cfg.dma_enabled=off): sys 0m7.674s
>>
>> FW_CFG_FILE_DIR (0x19) is the only "file" that is read during kernel
>> boot to populate sysfs qemu_fw_cfg directory, and it is quite
>> small (1-2kb). Since it does not expose itself, in order to measure
>> the time it takes to read such small file, I took a comparable sized
>> file of 2048 bytes and exposed it (-fw_cfg test,file=file with a
>> modified read_raw enabling DMA)
>>
>>  # perf stat -r 100 cat /sys/firmware/qemu_fw_cfg/by_name/test/raw >/dev/null
>>   - with DMA:
>>   0.636037  task-clock (msec) #0.141 CPUs utilized   
>>  ( +-  1.19% )
>>   - without DMA:
>>   6.430128  task-clock (msec) #0.622 CPUs utilized   
>>  ( +-  0.22% )
>>
>> That's a few msec saved during boot by enabling DMA read (the gain
>> would be more substantial if other & bigger fw-cfg entries are read by
>> others from sysfs, unfortunately, it's not clear if we can always
>> enable DMA there)
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
>> ---
>>  drivers/firmware/qemu_fw_cfg.c | 61 
>> ++
>>  1 file changed, 50 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
>> index 3015e77aebca..94df57e9be66 100644
>> --- a/drivers/firmware/qemu_fw_cfg.c
>> +++ b/drivers/firmware/qemu_fw_cfg.c
>> @@ -124,12 +124,47 @@ static ssize_t fw_cfg_dma_transfer(void *address, u32 
>> length, u32 control)
>>   return ret;
>>  }
>>
>> +/* with acpi & dev locks taken */
>> +static ssize_t fw_cfg_read_blob_dma(u16 key,
>> + void *buf, loff_t pos, size_t count)
>> +{
>> + ssize_t ret;
>> +
>> + if (pos == 0) {
>> + ret = fw_cfg_dma_transfer(buf, count, key << 16
>> + | FW_CFG_DMA_CTL_SELECT
>> + | FW_CFG_DMA_CTL_READ);
>> + } else {
>> + fw_cfg_sel_endianness(key);
>> + ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
>> + if (ret < 0)
>> + return ret;
>> + ret = fw_cfg_dma_transfer(buf, count,
>> + FW_CFG_DMA_CTL_READ);
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +/* with acpi & dev locks taken */
>> +static ssize_t fw_cfg_read_blob_io(u16 key,
>> + void *buf, loff_t pos, size_t count)
>> +{
>> + fw_cfg_sel_endianness(key);
>> + while (pos-- > 0)
>> + ioread8(fw_cfg_reg_data);
>> + ioread8_rep(fw_cfg_reg_data, buf, count);
>> + return count;
>> +}
>> +
>>  /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
>>  static ssize_t fw_cfg_read_blob(u16 key,
>> - void *buf, loff_t pos, size_t count)
>> + void *buf, loff_t pos, size_t count,
>> + bool dma)
>>  {
>>   u32 glk = -1U;
>>   acpi_status status;
>> + ssize_t ret;
>>
>>   /* If we have ACPI, ensure mutual exclusion against any potential
>>* device access by the firmware, e.g. via AML methods:
>
> so this adds a dma flag to fw_cfg_read_blob.
>
>
>
>> @@

Re: [PATCH v15 11/11] RFC: fw_cfg: do DMA read operation

2018-02-28 Thread Marc-André Lureau
Hi

On Tue, Feb 27, 2018 at 1:04 AM, Michael S. Tsirkin  wrote:
> On Thu, Feb 15, 2018 at 10:33:12PM +0100, Marc-André Lureau wrote:
>> Modify fw_cfg_read_blob() to use DMA if the device supports it.
>> Return errors, because the operation may fail.
>>
>> So far, only one call in fw_cfg_register_dir_entries() is using
>> kmalloc'ed buf and is thus clearly eligible to DMA read.
>>
>> Initially, I didn't implement DMA read to speed up boot time, but as a
>> first step before introducing DMA write (since read operations were
>> already presents). Even more, I didn't realize fw-cfg entries were
>> being read by the kernel during boot by default. But actally fw-cfg
>> entries are being populated during module probe. I knew DMA improved a
>> lot bios boot time (the main reason the DMA interface was added
>> afaik). Let see the time it would take to read the whole ACPI
>> tables (128kb allocated)
>>
>>  # time cat /sys/firmware/qemu_fw_cfg/by_name/etc/acpi/tables/raw
>>   - with DMA: sys 0m0.003s
>>   - without DMA (-global fw_cfg.dma_enabled=off): sys 0m7.674s
>>
>> FW_CFG_FILE_DIR (0x19) is the only "file" that is read during kernel
>> boot to populate sysfs qemu_fw_cfg directory, and it is quite
>> small (1-2kb). Since it does not expose itself, in order to measure
>> the time it takes to read such small file, I took a comparable sized
>> file of 2048 bytes and exposed it (-fw_cfg test,file=file with a
>> modified read_raw enabling DMA)
>>
>>  # perf stat -r 100 cat /sys/firmware/qemu_fw_cfg/by_name/test/raw >/dev/null
>>   - with DMA:
>>   0.636037  task-clock (msec) #0.141 CPUs utilized   
>>  ( +-  1.19% )
>>   - without DMA:
>>   6.430128  task-clock (msec) #0.622 CPUs utilized   
>>  ( +-  0.22% )
>>
>> That's a few msec saved during boot by enabling DMA read (the gain
>> would be more substantial if other & bigger fw-cfg entries are read by
>> others from sysfs, unfortunately, it's not clear if we can always
>> enable DMA there)
>>
>> Signed-off-by: Marc-André Lureau 
>> ---
>>  drivers/firmware/qemu_fw_cfg.c | 61 
>> ++
>>  1 file changed, 50 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
>> index 3015e77aebca..94df57e9be66 100644
>> --- a/drivers/firmware/qemu_fw_cfg.c
>> +++ b/drivers/firmware/qemu_fw_cfg.c
>> @@ -124,12 +124,47 @@ static ssize_t fw_cfg_dma_transfer(void *address, u32 
>> length, u32 control)
>>   return ret;
>>  }
>>
>> +/* with acpi & dev locks taken */
>> +static ssize_t fw_cfg_read_blob_dma(u16 key,
>> + void *buf, loff_t pos, size_t count)
>> +{
>> + ssize_t ret;
>> +
>> + if (pos == 0) {
>> + ret = fw_cfg_dma_transfer(buf, count, key << 16
>> + | FW_CFG_DMA_CTL_SELECT
>> + | FW_CFG_DMA_CTL_READ);
>> + } else {
>> + fw_cfg_sel_endianness(key);
>> + ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
>> + if (ret < 0)
>> + return ret;
>> + ret = fw_cfg_dma_transfer(buf, count,
>> + FW_CFG_DMA_CTL_READ);
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +/* with acpi & dev locks taken */
>> +static ssize_t fw_cfg_read_blob_io(u16 key,
>> + void *buf, loff_t pos, size_t count)
>> +{
>> + fw_cfg_sel_endianness(key);
>> + while (pos-- > 0)
>> + ioread8(fw_cfg_reg_data);
>> + ioread8_rep(fw_cfg_reg_data, buf, count);
>> + return count;
>> +}
>> +
>>  /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
>>  static ssize_t fw_cfg_read_blob(u16 key,
>> - void *buf, loff_t pos, size_t count)
>> + void *buf, loff_t pos, size_t count,
>> + bool dma)
>>  {
>>   u32 glk = -1U;
>>   acpi_status status;
>> + ssize_t ret;
>>
>>   /* If we have ACPI, ensure mutual exclusion against any potential
>>* device access by the firmware, e.g. via AML methods:
>
> so this adds a dma flag to fw_cfg_read_blob.
>
>
>
>> @@ -143,14 +178,17 @@ static ssize_t fw_cfg_read_blob(u16 ke

Re: [PATCH v15 10/11] fw_cfg: write vmcoreinfo details

2018-02-28 Thread Marc-André Lureau
Hi

On Tue, Feb 27, 2018 at 1:28 AM, Michael S. Tsirkin <m...@redhat.com> wrote:
> On Thu, Feb 15, 2018 at 10:33:11PM +0100, Marc-André Lureau wrote:
>> If the "etc/vmcoreinfo" fw_cfg file is present and we are not running
>> the kdump kernel, write the addr/size of the vmcoreinfo ELF note.
>>
>> The DMA operation is expected to run synchronously with today qemu,
>> but the specification states that it may become async, so we run
>> "control" field check in a loop for eventual changes.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
>> ---
>>  drivers/firmware/qemu_fw_cfg.c | 143 
>> -
>>  include/uapi/linux/fw_cfg.h|  31 +
>>  2 files changed, 171 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
>> index c28bec4b5663..3015e77aebca 100644
>> --- a/drivers/firmware/qemu_fw_cfg.c
>> +++ b/drivers/firmware/qemu_fw_cfg.c
>> @@ -34,11 +34,17 @@
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>> +#include 
>> +#include 
>>
>>  MODULE_AUTHOR("Gabriel L. Somlo <so...@cmu.edu>");
>>  MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
>>  MODULE_LICENSE("GPL");
>>
>> +/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
>> +static u32 fw_cfg_rev;
>> +
>>  /* fw_cfg device i/o register addresses */
>>  static bool fw_cfg_is_mmio;
>>  static phys_addr_t fw_cfg_p_base;
>> @@ -60,6 +66,64 @@ static void fw_cfg_sel_endianness(u16 key)
>>   iowrite16(key, fw_cfg_reg_ctrl);
>>  }
>>
>> +static inline bool fw_cfg_dma_enabled(void)
>> +{
>> + return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
>> +}
>> +
>> +/* qemu fw_cfg device is sync today, but spec says it may become async */
>> +static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *d)
>> +{
>> + for (;;) {
>> + u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
>> +
>> + /* do not reorder the read to d->control */
>> + rmb();
>> + if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
>> + return;
>> +
>> + cpu_relax();
>> + }
>> +}
>> +
>> +static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
>> +{
>> + phys_addr_t dma;
>> + struct fw_cfg_dma_access *d = NULL;
>> + ssize_t ret = length;
>> +
>> + d = kmalloc(sizeof(*d), GFP_KERNEL);
>> + if (!d) {
>> + ret = -ENOMEM;
>> + goto end;
>> + }
>> +
>> + /* fw_cfg device does not need IOMMU protection, so use physical 
>> addresses */
>> + *d = (struct fw_cfg_dma_access) {
>> + .address = cpu_to_be64(address ? virt_to_phys(address) : 0),
>> + .length = cpu_to_be32(length),
>> + .control = cpu_to_be32(control)
>> + };
>> +
>> + dma = virt_to_phys(d);
>> +
>> + iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
>> + /* force memory to sync before notifying device via MMIO */
>> + wmb();
>> + iowrite32be(dma, fw_cfg_reg_dma + 4);
>> +
>> + fw_cfg_wait_for_control(d);
>> +
>> + if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
>> + ret = -EIO;
>> + }
>> +
>> +end:
>> + kfree(d);
>> +
>> + return ret;
>> +}
>> +
>>  /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
>>  static ssize_t fw_cfg_read_blob(u16 key,
>>   void *buf, loff_t pos, size_t count)
>> @@ -89,6 +153,47 @@ static ssize_t fw_cfg_read_blob(u16 key,
>>   return count;
>>  }
>>
>> +#ifdef CONFIG_CRASH_CORE
>> +/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
>> +static ssize_t fw_cfg_write_blob(u16 key,
>> +  void *buf, loff_t pos, size_t count)
>> +{
>> + u32 glk = -1U;
>> + acpi_status status;
>> + ssize_t ret = count;
>> +
>> + /* If we have ACPI, ensure mutual exclusion against any potential
>> +  * device access by the firmware, e.g. via AML methods:
>> +  */
>> + status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
>> + if (ACPI_FAILURE(status) && statu

Re: [PATCH v15 10/11] fw_cfg: write vmcoreinfo details

2018-02-28 Thread Marc-André Lureau
Hi

On Tue, Feb 27, 2018 at 1:28 AM, Michael S. Tsirkin  wrote:
> On Thu, Feb 15, 2018 at 10:33:11PM +0100, Marc-André Lureau wrote:
>> If the "etc/vmcoreinfo" fw_cfg file is present and we are not running
>> the kdump kernel, write the addr/size of the vmcoreinfo ELF note.
>>
>> The DMA operation is expected to run synchronously with today qemu,
>> but the specification states that it may become async, so we run
>> "control" field check in a loop for eventual changes.
>>
>> Signed-off-by: Marc-André Lureau 
>> ---
>>  drivers/firmware/qemu_fw_cfg.c | 143 
>> -
>>  include/uapi/linux/fw_cfg.h|  31 +
>>  2 files changed, 171 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
>> index c28bec4b5663..3015e77aebca 100644
>> --- a/drivers/firmware/qemu_fw_cfg.c
>> +++ b/drivers/firmware/qemu_fw_cfg.c
>> @@ -34,11 +34,17 @@
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>> +#include 
>> +#include 
>>
>>  MODULE_AUTHOR("Gabriel L. Somlo ");
>>  MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
>>  MODULE_LICENSE("GPL");
>>
>> +/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
>> +static u32 fw_cfg_rev;
>> +
>>  /* fw_cfg device i/o register addresses */
>>  static bool fw_cfg_is_mmio;
>>  static phys_addr_t fw_cfg_p_base;
>> @@ -60,6 +66,64 @@ static void fw_cfg_sel_endianness(u16 key)
>>   iowrite16(key, fw_cfg_reg_ctrl);
>>  }
>>
>> +static inline bool fw_cfg_dma_enabled(void)
>> +{
>> + return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
>> +}
>> +
>> +/* qemu fw_cfg device is sync today, but spec says it may become async */
>> +static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *d)
>> +{
>> + for (;;) {
>> + u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
>> +
>> + /* do not reorder the read to d->control */
>> + rmb();
>> + if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
>> + return;
>> +
>> + cpu_relax();
>> + }
>> +}
>> +
>> +static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
>> +{
>> + phys_addr_t dma;
>> + struct fw_cfg_dma_access *d = NULL;
>> + ssize_t ret = length;
>> +
>> + d = kmalloc(sizeof(*d), GFP_KERNEL);
>> + if (!d) {
>> + ret = -ENOMEM;
>> + goto end;
>> + }
>> +
>> + /* fw_cfg device does not need IOMMU protection, so use physical 
>> addresses */
>> + *d = (struct fw_cfg_dma_access) {
>> + .address = cpu_to_be64(address ? virt_to_phys(address) : 0),
>> + .length = cpu_to_be32(length),
>> + .control = cpu_to_be32(control)
>> + };
>> +
>> + dma = virt_to_phys(d);
>> +
>> + iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
>> + /* force memory to sync before notifying device via MMIO */
>> + wmb();
>> + iowrite32be(dma, fw_cfg_reg_dma + 4);
>> +
>> + fw_cfg_wait_for_control(d);
>> +
>> + if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
>> + ret = -EIO;
>> + }
>> +
>> +end:
>> + kfree(d);
>> +
>> + return ret;
>> +}
>> +
>>  /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
>>  static ssize_t fw_cfg_read_blob(u16 key,
>>   void *buf, loff_t pos, size_t count)
>> @@ -89,6 +153,47 @@ static ssize_t fw_cfg_read_blob(u16 key,
>>   return count;
>>  }
>>
>> +#ifdef CONFIG_CRASH_CORE
>> +/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
>> +static ssize_t fw_cfg_write_blob(u16 key,
>> +  void *buf, loff_t pos, size_t count)
>> +{
>> + u32 glk = -1U;
>> + acpi_status status;
>> + ssize_t ret = count;
>> +
>> + /* If we have ACPI, ensure mutual exclusion against any potential
>> +  * device access by the firmware, e.g. via AML methods:
>> +  */
>> + status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
>> + if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
>> + /* Should neve

Re: [PATCH v15 02/11] fw_cfg: add a public uapi header

2018-02-28 Thread Marc-André Lureau
On Tue, Feb 27, 2018 at 1:06 AM, Michael S. Tsirkin <m...@redhat.com> wrote:
> On Thu, Feb 15, 2018 at 10:33:03PM +0100, Marc-André Lureau wrote:
>> Create a common header file for well-known values and structures to be
>> shared by the Linux kernel with qemu or other projects.
>>
>> It is based from qemu/docs/specs/fw_cfg.txt which references
>> qemu/include/hw/nvram/fw_cfg_keys.h "for the most up-to-date and
>> authoritative list" & vmcoreinfo.txt. Those files don't have an
>> explicit license, but qemu/hw/nvram/fw_cfg.c is BSD-license, so
>> Michael S. Tsirkin suggested to use the same license.
>>
>> The patch intentionally left out DMA & vmcoreinfo structures &
>> defines, which are added in the commits making usage of it.
>>
>> Suggested-by: Michael S. Tsirkin <m...@redhat.com>
>> Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
>>
>> ---
>>
>> The related qemu patch making use of it, to be submitted:
>> https://github.com/elmarco/qemu/commit/4884fc9e9c4c4467a371e5a40f3181239e1b70f5
>> ---
>>  MAINTAINERS|  1 +
>>  drivers/firmware/qemu_fw_cfg.c | 22 ++
>>  include/uapi/linux/fw_cfg.h| 66 
>> ++
>>  3 files changed, 69 insertions(+), 20 deletions(-)
>>  create mode 100644 include/uapi/linux/fw_cfg.h
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 3bdc260e36b7..a66b65f62811 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -11352,6 +11352,7 @@ M:"Michael S. Tsirkin" <m...@redhat.com>
>>  L:   qemu-de...@nongnu.org
>>  S:   Maintained
>>  F:   drivers/firmware/qemu_fw_cfg.c
>> +F:   include/uapi/linux/fw_cfg.h
>>
>>  QIB DRIVER
>>  M:   Dennis Dalessandro <dennis.dalessan...@intel.com>
>
> Why fw_cfg.h and not qemu_fw_cfg.h ? fw_cfg.h seems too generic.

ok

>
>> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
>> index a41b572eeeb1..42601a3eaed5 100644
>> --- a/drivers/firmware/qemu_fw_cfg.c
>> +++ b/drivers/firmware/qemu_fw_cfg.c
>> @@ -32,30 +32,12 @@
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>>
>>  MODULE_AUTHOR("Gabriel L. Somlo <so...@cmu.edu>");
>>  MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
>>  MODULE_LICENSE("GPL");
>>
>> -/* selector key values for "well-known" fw_cfg entries */
>> -#define FW_CFG_SIGNATURE  0x00
>> -#define FW_CFG_ID 0x01
>> -#define FW_CFG_FILE_DIR   0x19
>> -
>> -/* size in bytes of fw_cfg signature */
>> -#define FW_CFG_SIG_SIZE 4
>> -
>> -/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
>> -#define FW_CFG_MAX_FILE_PATH 56
>> -
>> -/* fw_cfg file directory entry type */
>> -struct fw_cfg_file {
>> - u32 size;
>> - u16 select;
>> - u16 reserved;
>> - char name[FW_CFG_MAX_FILE_PATH];
>> -};
>> -
>>  /* fw_cfg device i/o register addresses */
>>  static bool fw_cfg_is_mmio;
>>  static phys_addr_t fw_cfg_p_base;
>> @@ -597,7 +579,7 @@ MODULE_DEVICE_TABLE(of, fw_cfg_sysfs_mmio_match);
>>
>>  #ifdef CONFIG_ACPI
>>  static const struct acpi_device_id fw_cfg_sysfs_acpi_match[] = {
>> - { "QEMU0002", },
>> + { FW_CFG_ACPI_DEVICE_ID, },
>>   {},
>>  };
>>  MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
>> diff --git a/include/uapi/linux/fw_cfg.h b/include/uapi/linux/fw_cfg.h
>> new file mode 100644
>> index ..c698ac3812f6
>> --- /dev/null
>> +++ b/include/uapi/linux/fw_cfg.h
>> @@ -0,0 +1,66 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause */
>> +#ifndef _LINUX_FW_CFG_H
>> +#define _LINUX_FW_CFG_H
>> +
>> +#include 
>> +
>> +#define FW_CFG_ACPI_DEVICE_ID"QEMU0002"
>> +
>> +/* selector key values for "well-known" fw_cfg entries */
>> +#define FW_CFG_SIGNATURE 0x00
>> +#define FW_CFG_ID0x01
>> +#define FW_CFG_UUID  0x02
>> +#define FW_CFG_RAM_SIZE  0x03
>> +#define FW_CFG_NOGRAPHIC 0x04
>> +#define FW_CFG_NB_CPUS   0x05
>> +#define FW_CFG_MACHINE_ID0x06
>> +#define FW_CFG_KERNEL_ADDR   0x07
>> +#define FW_CFG_KERNEL_SIZE   0x08
>> +#define FW_CFG_KERNEL_CMDLINE0x09
>> +#define FW_CFG_INITRD_ADDR   0x0a
>> +#define FW_CFG_INITRD_SIZE   0x0b
>> +#define FW_CFG_BO

Re: [PATCH v15 02/11] fw_cfg: add a public uapi header

2018-02-28 Thread Marc-André Lureau
On Tue, Feb 27, 2018 at 1:06 AM, Michael S. Tsirkin  wrote:
> On Thu, Feb 15, 2018 at 10:33:03PM +0100, Marc-André Lureau wrote:
>> Create a common header file for well-known values and structures to be
>> shared by the Linux kernel with qemu or other projects.
>>
>> It is based from qemu/docs/specs/fw_cfg.txt which references
>> qemu/include/hw/nvram/fw_cfg_keys.h "for the most up-to-date and
>> authoritative list" & vmcoreinfo.txt. Those files don't have an
>> explicit license, but qemu/hw/nvram/fw_cfg.c is BSD-license, so
>> Michael S. Tsirkin suggested to use the same license.
>>
>> The patch intentionally left out DMA & vmcoreinfo structures &
>> defines, which are added in the commits making usage of it.
>>
>> Suggested-by: Michael S. Tsirkin 
>> Signed-off-by: Marc-André Lureau 
>>
>> ---
>>
>> The related qemu patch making use of it, to be submitted:
>> https://github.com/elmarco/qemu/commit/4884fc9e9c4c4467a371e5a40f3181239e1b70f5
>> ---
>>  MAINTAINERS|  1 +
>>  drivers/firmware/qemu_fw_cfg.c | 22 ++
>>  include/uapi/linux/fw_cfg.h| 66 
>> ++
>>  3 files changed, 69 insertions(+), 20 deletions(-)
>>  create mode 100644 include/uapi/linux/fw_cfg.h
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 3bdc260e36b7..a66b65f62811 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -11352,6 +11352,7 @@ M:"Michael S. Tsirkin" 
>>  L:   qemu-de...@nongnu.org
>>  S:   Maintained
>>  F:   drivers/firmware/qemu_fw_cfg.c
>> +F:   include/uapi/linux/fw_cfg.h
>>
>>  QIB DRIVER
>>  M:   Dennis Dalessandro 
>
> Why fw_cfg.h and not qemu_fw_cfg.h ? fw_cfg.h seems too generic.

ok

>
>> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
>> index a41b572eeeb1..42601a3eaed5 100644
>> --- a/drivers/firmware/qemu_fw_cfg.c
>> +++ b/drivers/firmware/qemu_fw_cfg.c
>> @@ -32,30 +32,12 @@
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>>
>>  MODULE_AUTHOR("Gabriel L. Somlo ");
>>  MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
>>  MODULE_LICENSE("GPL");
>>
>> -/* selector key values for "well-known" fw_cfg entries */
>> -#define FW_CFG_SIGNATURE  0x00
>> -#define FW_CFG_ID 0x01
>> -#define FW_CFG_FILE_DIR   0x19
>> -
>> -/* size in bytes of fw_cfg signature */
>> -#define FW_CFG_SIG_SIZE 4
>> -
>> -/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
>> -#define FW_CFG_MAX_FILE_PATH 56
>> -
>> -/* fw_cfg file directory entry type */
>> -struct fw_cfg_file {
>> - u32 size;
>> - u16 select;
>> - u16 reserved;
>> - char name[FW_CFG_MAX_FILE_PATH];
>> -};
>> -
>>  /* fw_cfg device i/o register addresses */
>>  static bool fw_cfg_is_mmio;
>>  static phys_addr_t fw_cfg_p_base;
>> @@ -597,7 +579,7 @@ MODULE_DEVICE_TABLE(of, fw_cfg_sysfs_mmio_match);
>>
>>  #ifdef CONFIG_ACPI
>>  static const struct acpi_device_id fw_cfg_sysfs_acpi_match[] = {
>> - { "QEMU0002", },
>> + { FW_CFG_ACPI_DEVICE_ID, },
>>   {},
>>  };
>>  MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
>> diff --git a/include/uapi/linux/fw_cfg.h b/include/uapi/linux/fw_cfg.h
>> new file mode 100644
>> index ..c698ac3812f6
>> --- /dev/null
>> +++ b/include/uapi/linux/fw_cfg.h
>> @@ -0,0 +1,66 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause */
>> +#ifndef _LINUX_FW_CFG_H
>> +#define _LINUX_FW_CFG_H
>> +
>> +#include 
>> +
>> +#define FW_CFG_ACPI_DEVICE_ID"QEMU0002"
>> +
>> +/* selector key values for "well-known" fw_cfg entries */
>> +#define FW_CFG_SIGNATURE 0x00
>> +#define FW_CFG_ID0x01
>> +#define FW_CFG_UUID  0x02
>> +#define FW_CFG_RAM_SIZE  0x03
>> +#define FW_CFG_NOGRAPHIC 0x04
>> +#define FW_CFG_NB_CPUS   0x05
>> +#define FW_CFG_MACHINE_ID0x06
>> +#define FW_CFG_KERNEL_ADDR   0x07
>> +#define FW_CFG_KERNEL_SIZE   0x08
>> +#define FW_CFG_KERNEL_CMDLINE0x09
>> +#define FW_CFG_INITRD_ADDR   0x0a
>> +#define FW_CFG_INITRD_SIZE   0x0b
>> +#define FW_CFG_BOOT_DEVICE   0x0c
>> +#define FW_CFG_NUMA  0x0d
>> +#define FW_CFG_BOOT_MENU 0x0e
>> +#define FW_CFG_MAX_CPUS  0x0f
>> +#d

Re: [PATCH v15 08/11] fw_cfg: handle fw_cfg_read_blob() error

2018-02-28 Thread Marc-André Lureau
Hi

On Tue, Feb 27, 2018 at 1:20 AM, Michael S. Tsirkin <m...@redhat.com> wrote:
> On Thu, Feb 15, 2018 at 10:33:09PM +0100, Marc-André Lureau wrote:
>> fw_cfg_read_blob() may fail, but does not return error. This may lead
>> to undefined behaviours, such as a memcmp(sig, "QEMU") on uninitilized
>> memory.
>
> I don't think that's true - there's a memset there that
> will initialize the memory. probe is likely the only
> case where it returns a slightly incorrect data.

Right, I'll update the commit message.

>> Return an error if ACPI locking failed. Also, the following
>> DMA read/write extension will add more error paths that should be
>> handled appropriately.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
>> ---
>>  drivers/firmware/qemu_fw_cfg.c | 32 ++--
>>  1 file changed, 22 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
>> index f6f90bef604c..5e6e5ac71dab 100644
>> --- a/drivers/firmware/qemu_fw_cfg.c
>> +++ b/drivers/firmware/qemu_fw_cfg.c
>> @@ -59,8 +59,8 @@ static void fw_cfg_sel_endianness(u16 key)
>>  }
>>
>>  /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
>> -static void fw_cfg_read_blob(u16 key,
>> - void *buf, loff_t pos, size_t count)
>> +static ssize_t fw_cfg_read_blob(u16 key,
>> + void *buf, loff_t pos, size_t count)
>>  {
>>   u32 glk = -1U;
>>   acpi_status status;
>> @@ -73,7 +73,7 @@ static void fw_cfg_read_blob(u16 key,
>>   /* Should never get here */
>>   WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
>>   memset(buf, 0, count);
>> - return;
>> + return -EINVAL;
>>   }
>>
>>   mutex_lock(_cfg_dev_lock);
>
> Wouldn't something like -EBUSY be more appropriate?

In theory, it would be a general failure right? I don't think we want
the caller to retry. I think in EINVAL fits better, but I don't think
it matters much this or EBUSY.

>> @@ -84,6 +84,7 @@ static void fw_cfg_read_blob(u16 key,
>>   mutex_unlock(_cfg_dev_lock);
>>
>>   acpi_release_global_lock(glk);
>> + return count;
>>  }
>>
>>  /* clean up fw_cfg device i/o */
>> @@ -165,8 +166,9 @@ static int fw_cfg_do_platform_probe(struct 
>> platform_device *pdev)
>>   }
>>
>>   /* verify fw_cfg device signature */
>> - fw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE);
>> - if (memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
>> + if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
>> + 0, FW_CFG_SIG_SIZE) < 0 ||
>> + memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
>>   fw_cfg_io_cleanup();
>>   return -ENODEV;
>>   }
>> @@ -326,8 +328,7 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, 
>> struct kobject *kobj,
>>   if (count > entry->size - pos)
>>   count = entry->size - pos;
>>
>> - fw_cfg_read_blob(entry->select, buf, pos, count);
>> - return count;
>> + return fw_cfg_read_blob(entry->select, buf, pos, count);
>>  }
>>
>>  static struct bin_attribute fw_cfg_sysfs_attr_raw = {
>> @@ -483,7 +484,11 @@ static int fw_cfg_register_dir_entries(void)
>>   struct fw_cfg_file *dir;
>>   size_t dir_size;
>>
>> - fw_cfg_read_blob(FW_CFG_FILE_DIR, _count, 0, 
>> sizeof(files_count));
>> + ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, _count,
>> + 0, sizeof(files_count));
>> + if (ret < 0)
>> + return ret;
>> +
>>   count = be32_to_cpu(files_count);
>>   dir_size = count * sizeof(struct fw_cfg_file);
>>
>> @@ -491,7 +496,10 @@ static int fw_cfg_register_dir_entries(void)
>>   if (!dir)
>>   return -ENOMEM;
>>
>> - fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files_count), dir_size);
>> + ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, dir,
>> + sizeof(files_count), dir_size);
>> + if (ret < 0)
>> + goto end;
>>
>>   for (i = 0; i < count; i++) {
>>   ret = fw_cfg_register_file([i]);
>> @@ -499,6 +507,7 @@ static int fw_cfg_register_dir_entries(void)
>>   break;
>>   }
>>
>> +end:
>>   kfree(dir);
>

Re: [PATCH v15 08/11] fw_cfg: handle fw_cfg_read_blob() error

2018-02-28 Thread Marc-André Lureau
Hi

On Tue, Feb 27, 2018 at 1:20 AM, Michael S. Tsirkin  wrote:
> On Thu, Feb 15, 2018 at 10:33:09PM +0100, Marc-André Lureau wrote:
>> fw_cfg_read_blob() may fail, but does not return error. This may lead
>> to undefined behaviours, such as a memcmp(sig, "QEMU") on uninitilized
>> memory.
>
> I don't think that's true - there's a memset there that
> will initialize the memory. probe is likely the only
> case where it returns a slightly incorrect data.

Right, I'll update the commit message.

>> Return an error if ACPI locking failed. Also, the following
>> DMA read/write extension will add more error paths that should be
>> handled appropriately.
>>
>> Signed-off-by: Marc-André Lureau 
>> ---
>>  drivers/firmware/qemu_fw_cfg.c | 32 ++--
>>  1 file changed, 22 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
>> index f6f90bef604c..5e6e5ac71dab 100644
>> --- a/drivers/firmware/qemu_fw_cfg.c
>> +++ b/drivers/firmware/qemu_fw_cfg.c
>> @@ -59,8 +59,8 @@ static void fw_cfg_sel_endianness(u16 key)
>>  }
>>
>>  /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
>> -static void fw_cfg_read_blob(u16 key,
>> - void *buf, loff_t pos, size_t count)
>> +static ssize_t fw_cfg_read_blob(u16 key,
>> + void *buf, loff_t pos, size_t count)
>>  {
>>   u32 glk = -1U;
>>   acpi_status status;
>> @@ -73,7 +73,7 @@ static void fw_cfg_read_blob(u16 key,
>>   /* Should never get here */
>>   WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
>>   memset(buf, 0, count);
>> - return;
>> + return -EINVAL;
>>   }
>>
>>   mutex_lock(_cfg_dev_lock);
>
> Wouldn't something like -EBUSY be more appropriate?

In theory, it would be a general failure right? I don't think we want
the caller to retry. I think in EINVAL fits better, but I don't think
it matters much this or EBUSY.

>> @@ -84,6 +84,7 @@ static void fw_cfg_read_blob(u16 key,
>>   mutex_unlock(_cfg_dev_lock);
>>
>>   acpi_release_global_lock(glk);
>> + return count;
>>  }
>>
>>  /* clean up fw_cfg device i/o */
>> @@ -165,8 +166,9 @@ static int fw_cfg_do_platform_probe(struct 
>> platform_device *pdev)
>>   }
>>
>>   /* verify fw_cfg device signature */
>> - fw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE);
>> - if (memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
>> + if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
>> + 0, FW_CFG_SIG_SIZE) < 0 ||
>> + memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
>>   fw_cfg_io_cleanup();
>>   return -ENODEV;
>>   }
>> @@ -326,8 +328,7 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, 
>> struct kobject *kobj,
>>   if (count > entry->size - pos)
>>   count = entry->size - pos;
>>
>> - fw_cfg_read_blob(entry->select, buf, pos, count);
>> - return count;
>> + return fw_cfg_read_blob(entry->select, buf, pos, count);
>>  }
>>
>>  static struct bin_attribute fw_cfg_sysfs_attr_raw = {
>> @@ -483,7 +484,11 @@ static int fw_cfg_register_dir_entries(void)
>>   struct fw_cfg_file *dir;
>>   size_t dir_size;
>>
>> - fw_cfg_read_blob(FW_CFG_FILE_DIR, _count, 0, 
>> sizeof(files_count));
>> + ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, _count,
>> + 0, sizeof(files_count));
>> + if (ret < 0)
>> + return ret;
>> +
>>   count = be32_to_cpu(files_count);
>>   dir_size = count * sizeof(struct fw_cfg_file);
>>
>> @@ -491,7 +496,10 @@ static int fw_cfg_register_dir_entries(void)
>>   if (!dir)
>>   return -ENOMEM;
>>
>> - fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files_count), dir_size);
>> + ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, dir,
>> + sizeof(files_count), dir_size);
>> + if (ret < 0)
>> + goto end;
>>
>>   for (i = 0; i < count; i++) {
>>   ret = fw_cfg_register_file([i]);
>> @@ -499,6 +507,7 @@ static int fw_cfg_register_dir_entries(void)
>>   break;
>>   }
>>
>> +end:
>>   kfree(dir);
>>   return ret;
>>  }
>> @@ -539

[PATCH v15 01/11] crash: export paddr_vmcoreinfo_note()

2018-02-15 Thread Marc-André Lureau
The following patch is going to use the symbol from the fw_cfg module,
to call the function and write the note location details in the
vmcoreinfo entry, so qemu can produce dumps with the vmcoreinfo note.

CC: Andrew Morton <a...@linux-foundation.org>
CC: Baoquan He <b...@redhat.com>
CC: Dave Young <dyo...@redhat.com>
CC: Dave Young <dyo...@redhat.com>
CC: Hari Bathini <hbath...@linux.vnet.ibm.com>
CC: Tony Luck <tony.l...@intel.com>
CC: Vivek Goyal <vgo...@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
Acked-by: Gabriel Somlo <so...@cmu.edu>
---
 kernel/crash_core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 4f63597c824d..a93590cdd9e1 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -376,6 +376,7 @@ phys_addr_t __weak paddr_vmcoreinfo_note(void)
 {
return __pa(vmcoreinfo_note);
 }
+EXPORT_SYMBOL(paddr_vmcoreinfo_note);
 
 static int __init crash_save_vmcoreinfo_init(void)
 {
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 02/11] fw_cfg: add a public uapi header

2018-02-15 Thread Marc-André Lureau
Create a common header file for well-known values and structures to be
shared by the Linux kernel with qemu or other projects.

It is based from qemu/docs/specs/fw_cfg.txt which references
qemu/include/hw/nvram/fw_cfg_keys.h "for the most up-to-date and
authoritative list" & vmcoreinfo.txt. Those files don't have an
explicit license, but qemu/hw/nvram/fw_cfg.c is BSD-license, so
Michael S. Tsirkin suggested to use the same license.

The patch intentionally left out DMA & vmcoreinfo structures &
defines, which are added in the commits making usage of it.

Suggested-by: Michael S. Tsirkin <m...@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>

---

The related qemu patch making use of it, to be submitted:
https://github.com/elmarco/qemu/commit/4884fc9e9c4c4467a371e5a40f3181239e1b70f5
---
 MAINTAINERS|  1 +
 drivers/firmware/qemu_fw_cfg.c | 22 ++
 include/uapi/linux/fw_cfg.h| 66 ++
 3 files changed, 69 insertions(+), 20 deletions(-)
 create mode 100644 include/uapi/linux/fw_cfg.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 3bdc260e36b7..a66b65f62811 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11352,6 +11352,7 @@ M:  "Michael S. Tsirkin" <m...@redhat.com>
 L: qemu-de...@nongnu.org
 S: Maintained
 F: drivers/firmware/qemu_fw_cfg.c
+F: include/uapi/linux/fw_cfg.h
 
 QIB DRIVER
 M: Dennis Dalessandro <dennis.dalessan...@intel.com>
diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index a41b572eeeb1..42601a3eaed5 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -32,30 +32,12 @@
 #include 
 #include 
 #include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo <so...@cmu.edu>");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
 MODULE_LICENSE("GPL");
 
-/* selector key values for "well-known" fw_cfg entries */
-#define FW_CFG_SIGNATURE  0x00
-#define FW_CFG_ID 0x01
-#define FW_CFG_FILE_DIR   0x19
-
-/* size in bytes of fw_cfg signature */
-#define FW_CFG_SIG_SIZE 4
-
-/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
-#define FW_CFG_MAX_FILE_PATH 56
-
-/* fw_cfg file directory entry type */
-struct fw_cfg_file {
-   u32 size;
-   u16 select;
-   u16 reserved;
-   char name[FW_CFG_MAX_FILE_PATH];
-};
-
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -597,7 +579,7 @@ MODULE_DEVICE_TABLE(of, fw_cfg_sysfs_mmio_match);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id fw_cfg_sysfs_acpi_match[] = {
-   { "QEMU0002", },
+   { FW_CFG_ACPI_DEVICE_ID, },
{},
 };
 MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
diff --git a/include/uapi/linux/fw_cfg.h b/include/uapi/linux/fw_cfg.h
new file mode 100644
index ..c698ac3812f6
--- /dev/null
+++ b/include/uapi/linux/fw_cfg.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+#ifndef _LINUX_FW_CFG_H
+#define _LINUX_FW_CFG_H
+
+#include 
+
+#define FW_CFG_ACPI_DEVICE_ID  "QEMU0002"
+
+/* selector key values for "well-known" fw_cfg entries */
+#define FW_CFG_SIGNATURE   0x00
+#define FW_CFG_ID  0x01
+#define FW_CFG_UUID0x02
+#define FW_CFG_RAM_SIZE0x03
+#define FW_CFG_NOGRAPHIC   0x04
+#define FW_CFG_NB_CPUS 0x05
+#define FW_CFG_MACHINE_ID  0x06
+#define FW_CFG_KERNEL_ADDR 0x07
+#define FW_CFG_KERNEL_SIZE 0x08
+#define FW_CFG_KERNEL_CMDLINE  0x09
+#define FW_CFG_INITRD_ADDR 0x0a
+#define FW_CFG_INITRD_SIZE 0x0b
+#define FW_CFG_BOOT_DEVICE 0x0c
+#define FW_CFG_NUMA0x0d
+#define FW_CFG_BOOT_MENU   0x0e
+#define FW_CFG_MAX_CPUS0x0f
+#define FW_CFG_KERNEL_ENTRY0x10
+#define FW_CFG_KERNEL_DATA 0x11
+#define FW_CFG_INITRD_DATA 0x12
+#define FW_CFG_CMDLINE_ADDR0x13
+#define FW_CFG_CMDLINE_SIZE0x14
+#define FW_CFG_CMDLINE_DATA0x15
+#define FW_CFG_SETUP_ADDR  0x16
+#define FW_CFG_SETUP_SIZE  0x17
+#define FW_CFG_SETUP_DATA  0x18
+#define FW_CFG_FILE_DIR0x19
+
+#define FW_CFG_FILE_FIRST  0x20
+#define FW_CFG_FILE_SLOTS_MIN  0x10
+
+#define FW_CFG_WRITE_CHANNEL   0x4000
+#define FW_CFG_ARCH_LOCAL  0x8000
+#define FW_CFG_ENTRY_MASK  (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
+
+#define FW_CFG_INVALID 0x
+
+/* width in bytes of fw_cfg control register */
+#define FW_CFG_CTL_SIZE0x02
+
+/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
+#define FW_CFG_MAX_FILE_PATH   56
+
+/* size in bytes of fw_cfg signature */
+#define FW_CFG_SIG_SIZE 4
+
+/* FW_CFG_ID bits */
+#define FW_CFG_VERSION 0x01
+
+/* fw_cfg file directory entry type */
+struct fw_cfg_file {
+   __be32 size;
+   __be16 select;
+   __u16 reserved;
+   char name[FW_CFG_MAX_FILE_PATH];
+};
+
+#endif
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 01/11] crash: export paddr_vmcoreinfo_note()

2018-02-15 Thread Marc-André Lureau
The following patch is going to use the symbol from the fw_cfg module,
to call the function and write the note location details in the
vmcoreinfo entry, so qemu can produce dumps with the vmcoreinfo note.

CC: Andrew Morton 
CC: Baoquan He 
CC: Dave Young 
CC: Dave Young 
CC: Hari Bathini 
CC: Tony Luck 
CC: Vivek Goyal 
Signed-off-by: Marc-André Lureau 
Acked-by: Gabriel Somlo 
---
 kernel/crash_core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 4f63597c824d..a93590cdd9e1 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -376,6 +376,7 @@ phys_addr_t __weak paddr_vmcoreinfo_note(void)
 {
return __pa(vmcoreinfo_note);
 }
+EXPORT_SYMBOL(paddr_vmcoreinfo_note);
 
 static int __init crash_save_vmcoreinfo_init(void)
 {
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 02/11] fw_cfg: add a public uapi header

2018-02-15 Thread Marc-André Lureau
Create a common header file for well-known values and structures to be
shared by the Linux kernel with qemu or other projects.

It is based from qemu/docs/specs/fw_cfg.txt which references
qemu/include/hw/nvram/fw_cfg_keys.h "for the most up-to-date and
authoritative list" & vmcoreinfo.txt. Those files don't have an
explicit license, but qemu/hw/nvram/fw_cfg.c is BSD-license, so
Michael S. Tsirkin suggested to use the same license.

The patch intentionally left out DMA & vmcoreinfo structures &
defines, which are added in the commits making usage of it.

Suggested-by: Michael S. Tsirkin 
Signed-off-by: Marc-André Lureau 

---

The related qemu patch making use of it, to be submitted:
https://github.com/elmarco/qemu/commit/4884fc9e9c4c4467a371e5a40f3181239e1b70f5
---
 MAINTAINERS|  1 +
 drivers/firmware/qemu_fw_cfg.c | 22 ++
 include/uapi/linux/fw_cfg.h| 66 ++
 3 files changed, 69 insertions(+), 20 deletions(-)
 create mode 100644 include/uapi/linux/fw_cfg.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 3bdc260e36b7..a66b65f62811 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11352,6 +11352,7 @@ M:  "Michael S. Tsirkin" 
 L: qemu-de...@nongnu.org
 S: Maintained
 F: drivers/firmware/qemu_fw_cfg.c
+F: include/uapi/linux/fw_cfg.h
 
 QIB DRIVER
 M: Dennis Dalessandro 
diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index a41b572eeeb1..42601a3eaed5 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -32,30 +32,12 @@
 #include 
 #include 
 #include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo ");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
 MODULE_LICENSE("GPL");
 
-/* selector key values for "well-known" fw_cfg entries */
-#define FW_CFG_SIGNATURE  0x00
-#define FW_CFG_ID 0x01
-#define FW_CFG_FILE_DIR   0x19
-
-/* size in bytes of fw_cfg signature */
-#define FW_CFG_SIG_SIZE 4
-
-/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
-#define FW_CFG_MAX_FILE_PATH 56
-
-/* fw_cfg file directory entry type */
-struct fw_cfg_file {
-   u32 size;
-   u16 select;
-   u16 reserved;
-   char name[FW_CFG_MAX_FILE_PATH];
-};
-
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -597,7 +579,7 @@ MODULE_DEVICE_TABLE(of, fw_cfg_sysfs_mmio_match);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id fw_cfg_sysfs_acpi_match[] = {
-   { "QEMU0002", },
+   { FW_CFG_ACPI_DEVICE_ID, },
{},
 };
 MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
diff --git a/include/uapi/linux/fw_cfg.h b/include/uapi/linux/fw_cfg.h
new file mode 100644
index ..c698ac3812f6
--- /dev/null
+++ b/include/uapi/linux/fw_cfg.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+#ifndef _LINUX_FW_CFG_H
+#define _LINUX_FW_CFG_H
+
+#include 
+
+#define FW_CFG_ACPI_DEVICE_ID  "QEMU0002"
+
+/* selector key values for "well-known" fw_cfg entries */
+#define FW_CFG_SIGNATURE   0x00
+#define FW_CFG_ID  0x01
+#define FW_CFG_UUID0x02
+#define FW_CFG_RAM_SIZE0x03
+#define FW_CFG_NOGRAPHIC   0x04
+#define FW_CFG_NB_CPUS 0x05
+#define FW_CFG_MACHINE_ID  0x06
+#define FW_CFG_KERNEL_ADDR 0x07
+#define FW_CFG_KERNEL_SIZE 0x08
+#define FW_CFG_KERNEL_CMDLINE  0x09
+#define FW_CFG_INITRD_ADDR 0x0a
+#define FW_CFG_INITRD_SIZE 0x0b
+#define FW_CFG_BOOT_DEVICE 0x0c
+#define FW_CFG_NUMA0x0d
+#define FW_CFG_BOOT_MENU   0x0e
+#define FW_CFG_MAX_CPUS0x0f
+#define FW_CFG_KERNEL_ENTRY0x10
+#define FW_CFG_KERNEL_DATA 0x11
+#define FW_CFG_INITRD_DATA 0x12
+#define FW_CFG_CMDLINE_ADDR0x13
+#define FW_CFG_CMDLINE_SIZE0x14
+#define FW_CFG_CMDLINE_DATA0x15
+#define FW_CFG_SETUP_ADDR  0x16
+#define FW_CFG_SETUP_SIZE  0x17
+#define FW_CFG_SETUP_DATA  0x18
+#define FW_CFG_FILE_DIR0x19
+
+#define FW_CFG_FILE_FIRST  0x20
+#define FW_CFG_FILE_SLOTS_MIN  0x10
+
+#define FW_CFG_WRITE_CHANNEL   0x4000
+#define FW_CFG_ARCH_LOCAL  0x8000
+#define FW_CFG_ENTRY_MASK  (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
+
+#define FW_CFG_INVALID 0x
+
+/* width in bytes of fw_cfg control register */
+#define FW_CFG_CTL_SIZE0x02
+
+/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
+#define FW_CFG_MAX_FILE_PATH   56
+
+/* size in bytes of fw_cfg signature */
+#define FW_CFG_SIG_SIZE 4
+
+/* FW_CFG_ID bits */
+#define FW_CFG_VERSION 0x01
+
+/* fw_cfg file directory entry type */
+struct fw_cfg_file {
+   __be32 size;
+   __be16 select;
+   __u16 reserved;
+   char name[FW_CFG_MAX_FILE_PATH];
+};
+
+#endif
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 05/11] fw_cfg: fix sparse warning reading FW_CFG_ID

2018-02-15 Thread Marc-André Lureau
Use a restricted type for reading FW_CFG_ID, fixing sparse warning:

drivers/firmware/qemu_fw_cfg.c:540:22: warning: cast to restricted __le32

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 6ee12c9e079a..71672cb8c427 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -512,6 +512,7 @@ static inline void fw_cfg_kobj_cleanup(struct kobject *kobj)
 static int fw_cfg_sysfs_probe(struct platform_device *pdev)
 {
int err;
+   __le32 rev;
 
/* NOTE: If we supported multiple fw_cfg devices, we'd first create
 * a subdirectory named after e.g. pdev->id, then hang per-device
@@ -537,8 +538,8 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)
goto err_probe;
 
/* get revision number, add matching top-level attribute */
-   fw_cfg_read_blob(FW_CFG_ID, _cfg_rev, 0, sizeof(fw_cfg_rev));
-   fw_cfg_rev = le32_to_cpu(fw_cfg_rev);
+   fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   fw_cfg_rev = le32_to_cpu(rev);
err = sysfs_create_file(fw_cfg_top_ko, _cfg_rev_attr.attr);
if (err)
goto err_rev;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 05/11] fw_cfg: fix sparse warning reading FW_CFG_ID

2018-02-15 Thread Marc-André Lureau
Use a restricted type for reading FW_CFG_ID, fixing sparse warning:

drivers/firmware/qemu_fw_cfg.c:540:22: warning: cast to restricted __le32

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 6ee12c9e079a..71672cb8c427 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -512,6 +512,7 @@ static inline void fw_cfg_kobj_cleanup(struct kobject *kobj)
 static int fw_cfg_sysfs_probe(struct platform_device *pdev)
 {
int err;
+   __le32 rev;
 
/* NOTE: If we supported multiple fw_cfg devices, we'd first create
 * a subdirectory named after e.g. pdev->id, then hang per-device
@@ -537,8 +538,8 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)
goto err_probe;
 
/* get revision number, add matching top-level attribute */
-   fw_cfg_read_blob(FW_CFG_ID, _cfg_rev, 0, sizeof(fw_cfg_rev));
-   fw_cfg_rev = le32_to_cpu(fw_cfg_rev);
+   fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   fw_cfg_rev = le32_to_cpu(rev);
err = sysfs_create_file(fw_cfg_top_ko, _cfg_rev_attr.attr);
if (err)
goto err_rev;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 04/11] fw_cfg: fix sparse warnings with fw_cfg_file

2018-02-15 Thread Marc-André Lureau
Modify fw_cfg_sysfs_entry to store entry values, instead of reusing
the restricted types.

Fixes warnings such as:

$ make C=1 CF=-D__CHECK_ENDIAN__ drivers/firmware/qemu_fw_cfg.o

drivers/firmware/qemu_fw_cfg.c:491:29: warning: incorrect type in assignment 
(different base types)
drivers/firmware/qemu_fw_cfg.c:491:29:expected restricted __be32 [usertype] 
size
drivers/firmware/qemu_fw_cfg.c:491:29:got unsigned int
drivers/firmware/qemu_fw_cfg.c:492:31: warning: incorrect type in assignment 
(different base types)
drivers/firmware/qemu_fw_cfg.c:492:31:expected restricted __be16 [usertype] 
select
drivers/firmware/qemu_fw_cfg.c:492:31:got int

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 28 +++-
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 6164731a3c35..6ee12c9e079a 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -193,7 +193,9 @@ static const struct {
 /* fw_cfg_sysfs_entry type */
 struct fw_cfg_sysfs_entry {
struct kobject kobj;
-   struct fw_cfg_file f;
+   u32 size;
+   u16 select;
+   char name[FW_CFG_MAX_FILE_PATH];
struct list_head list;
 };
 
@@ -257,17 +259,17 @@ struct fw_cfg_sysfs_attribute fw_cfg_sysfs_attr_##_attr = 
{ \
 
 static ssize_t fw_cfg_sysfs_show_size(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%u\n", e->f.size);
+   return sprintf(buf, "%u\n", e->size);
 }
 
 static ssize_t fw_cfg_sysfs_show_key(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%u\n", e->f.select);
+   return sprintf(buf, "%u\n", e->select);
 }
 
 static ssize_t fw_cfg_sysfs_show_name(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%s\n", e->f.name);
+   return sprintf(buf, "%s\n", e->name);
 }
 
 static FW_CFG_SYSFS_ATTR(size);
@@ -318,13 +320,13 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, 
struct kobject *kobj,
 {
struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
 
-   if (pos > entry->f.size)
+   if (pos > entry->size)
return -EINVAL;
 
-   if (count > entry->f.size - pos)
-   count = entry->f.size - pos;
+   if (count > entry->size - pos)
+   count = entry->size - pos;
 
-   fw_cfg_read_blob(entry->f.select, buf, pos, count);
+   fw_cfg_read_blob(entry->select, buf, pos, count);
return count;
 }
 
@@ -443,11 +445,13 @@ static int fw_cfg_register_file(const struct fw_cfg_file 
*f)
return -ENOMEM;
 
/* set file entry information */
-   memcpy(>f, f, sizeof(struct fw_cfg_file));
+   entry->size = be32_to_cpu(f->size);
+   entry->select = be16_to_cpu(f->select);
+   memcpy(entry->name, f->name, FW_CFG_MAX_FILE_PATH);
 
/* register entry under "/sys/firmware/qemu_fw_cfg/by_key/" */
err = kobject_init_and_add(>kobj, _cfg_sysfs_entry_ktype,
-  fw_cfg_sel_ko, "%d", entry->f.select);
+  fw_cfg_sel_ko, "%d", entry->select);
if (err)
goto err_register;
 
@@ -457,7 +461,7 @@ static int fw_cfg_register_file(const struct fw_cfg_file *f)
goto err_add_raw;
 
/* try adding "/sys/firmware/qemu_fw_cfg/by_name/" symlink */
-   fw_cfg_build_symlink(fw_cfg_fname_kset, >kobj, entry->f.name);
+   fw_cfg_build_symlink(fw_cfg_fname_kset, >kobj, entry->name);
 
/* success, add entry to global cache */
fw_cfg_sysfs_cache_enlist(entry);
@@ -489,8 +493,6 @@ static int fw_cfg_register_dir_entries(void)
fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
 
for (i = 0; i < count; i++) {
-   dir[i].size = be32_to_cpu(dir[i].size);
-   dir[i].select = be16_to_cpu(dir[i].select);
ret = fw_cfg_register_file([i]);
if (ret)
break;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 06/11] fw_cfg: fix sparse warnings around FW_CFG_FILE_DIR read

2018-02-15 Thread Marc-André Lureau
Use struct fw_cfg_files to read the directory size, fixing the sparse
warnings:

drivers/firmware/qemu_fw_cfg.c:485:17: warning: cast to restricted __be32

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 71672cb8c427..805372e8e50d 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -478,19 +478,20 @@ static int fw_cfg_register_file(const struct fw_cfg_file 
*f)
 static int fw_cfg_register_dir_entries(void)
 {
int ret = 0;
+   __be32 files_count;
u32 count, i;
struct fw_cfg_file *dir;
size_t dir_size;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, , 0, sizeof(count));
-   count = be32_to_cpu(count);
+   fw_cfg_read_blob(FW_CFG_FILE_DIR, _count, 0, sizeof(files_count));
+   count = be32_to_cpu(files_count);
dir_size = count * sizeof(struct fw_cfg_file);
 
dir = kmalloc(dir_size, GFP_KERNEL);
if (!dir)
return -ENOMEM;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
+   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files_count), dir_size);
 
for (i = 0; i < count; i++) {
ret = fw_cfg_register_file([i]);
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 04/11] fw_cfg: fix sparse warnings with fw_cfg_file

2018-02-15 Thread Marc-André Lureau
Modify fw_cfg_sysfs_entry to store entry values, instead of reusing
the restricted types.

Fixes warnings such as:

$ make C=1 CF=-D__CHECK_ENDIAN__ drivers/firmware/qemu_fw_cfg.o

drivers/firmware/qemu_fw_cfg.c:491:29: warning: incorrect type in assignment 
(different base types)
drivers/firmware/qemu_fw_cfg.c:491:29:expected restricted __be32 [usertype] 
size
drivers/firmware/qemu_fw_cfg.c:491:29:got unsigned int
drivers/firmware/qemu_fw_cfg.c:492:31: warning: incorrect type in assignment 
(different base types)
drivers/firmware/qemu_fw_cfg.c:492:31:expected restricted __be16 [usertype] 
select
drivers/firmware/qemu_fw_cfg.c:492:31:got int

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 28 +++-
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 6164731a3c35..6ee12c9e079a 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -193,7 +193,9 @@ static const struct {
 /* fw_cfg_sysfs_entry type */
 struct fw_cfg_sysfs_entry {
struct kobject kobj;
-   struct fw_cfg_file f;
+   u32 size;
+   u16 select;
+   char name[FW_CFG_MAX_FILE_PATH];
struct list_head list;
 };
 
@@ -257,17 +259,17 @@ struct fw_cfg_sysfs_attribute fw_cfg_sysfs_attr_##_attr = 
{ \
 
 static ssize_t fw_cfg_sysfs_show_size(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%u\n", e->f.size);
+   return sprintf(buf, "%u\n", e->size);
 }
 
 static ssize_t fw_cfg_sysfs_show_key(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%u\n", e->f.select);
+   return sprintf(buf, "%u\n", e->select);
 }
 
 static ssize_t fw_cfg_sysfs_show_name(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%s\n", e->f.name);
+   return sprintf(buf, "%s\n", e->name);
 }
 
 static FW_CFG_SYSFS_ATTR(size);
@@ -318,13 +320,13 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, 
struct kobject *kobj,
 {
struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
 
-   if (pos > entry->f.size)
+   if (pos > entry->size)
return -EINVAL;
 
-   if (count > entry->f.size - pos)
-   count = entry->f.size - pos;
+   if (count > entry->size - pos)
+   count = entry->size - pos;
 
-   fw_cfg_read_blob(entry->f.select, buf, pos, count);
+   fw_cfg_read_blob(entry->select, buf, pos, count);
return count;
 }
 
@@ -443,11 +445,13 @@ static int fw_cfg_register_file(const struct fw_cfg_file 
*f)
return -ENOMEM;
 
/* set file entry information */
-   memcpy(>f, f, sizeof(struct fw_cfg_file));
+   entry->size = be32_to_cpu(f->size);
+   entry->select = be16_to_cpu(f->select);
+   memcpy(entry->name, f->name, FW_CFG_MAX_FILE_PATH);
 
/* register entry under "/sys/firmware/qemu_fw_cfg/by_key/" */
err = kobject_init_and_add(>kobj, _cfg_sysfs_entry_ktype,
-  fw_cfg_sel_ko, "%d", entry->f.select);
+  fw_cfg_sel_ko, "%d", entry->select);
if (err)
goto err_register;
 
@@ -457,7 +461,7 @@ static int fw_cfg_register_file(const struct fw_cfg_file *f)
goto err_add_raw;
 
/* try adding "/sys/firmware/qemu_fw_cfg/by_name/" symlink */
-   fw_cfg_build_symlink(fw_cfg_fname_kset, >kobj, entry->f.name);
+   fw_cfg_build_symlink(fw_cfg_fname_kset, >kobj, entry->name);
 
/* success, add entry to global cache */
fw_cfg_sysfs_cache_enlist(entry);
@@ -489,8 +493,6 @@ static int fw_cfg_register_dir_entries(void)
fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
 
for (i = 0; i < count; i++) {
-   dir[i].size = be32_to_cpu(dir[i].size);
-   dir[i].select = be16_to_cpu(dir[i].select);
ret = fw_cfg_register_file([i]);
if (ret)
break;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 06/11] fw_cfg: fix sparse warnings around FW_CFG_FILE_DIR read

2018-02-15 Thread Marc-André Lureau
Use struct fw_cfg_files to read the directory size, fixing the sparse
warnings:

drivers/firmware/qemu_fw_cfg.c:485:17: warning: cast to restricted __be32

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 71672cb8c427..805372e8e50d 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -478,19 +478,20 @@ static int fw_cfg_register_file(const struct fw_cfg_file 
*f)
 static int fw_cfg_register_dir_entries(void)
 {
int ret = 0;
+   __be32 files_count;
u32 count, i;
struct fw_cfg_file *dir;
size_t dir_size;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, , 0, sizeof(count));
-   count = be32_to_cpu(count);
+   fw_cfg_read_blob(FW_CFG_FILE_DIR, _count, 0, sizeof(files_count));
+   count = be32_to_cpu(files_count);
dir_size = count * sizeof(struct fw_cfg_file);
 
dir = kmalloc(dir_size, GFP_KERNEL);
if (!dir)
return -ENOMEM;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
+   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files_count), dir_size);
 
for (i = 0; i < count; i++) {
ret = fw_cfg_register_file([i]);
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 08/11] fw_cfg: handle fw_cfg_read_blob() error

2018-02-15 Thread Marc-André Lureau
fw_cfg_read_blob() may fail, but does not return error. This may lead
to undefined behaviours, such as a memcmp(sig, "QEMU") on uninitilized
memory. Return an error if ACPI locking failed. Also, the following
DMA read/write extension will add more error paths that should be
handled appropriately.

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 32 ++--
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index f6f90bef604c..5e6e5ac71dab 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -59,8 +59,8 @@ static void fw_cfg_sel_endianness(u16 key)
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
-static void fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+static ssize_t fw_cfg_read_blob(u16 key,
+   void *buf, loff_t pos, size_t count)
 {
u32 glk = -1U;
acpi_status status;
@@ -73,7 +73,7 @@ static void fw_cfg_read_blob(u16 key,
/* Should never get here */
WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
memset(buf, 0, count);
-   return;
+   return -EINVAL;
}
 
mutex_lock(_cfg_dev_lock);
@@ -84,6 +84,7 @@ static void fw_cfg_read_blob(u16 key,
mutex_unlock(_cfg_dev_lock);
 
acpi_release_global_lock(glk);
+   return count;
 }
 
 /* clean up fw_cfg device i/o */
@@ -165,8 +166,9 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
}
 
/* verify fw_cfg device signature */
-   fw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE);
-   if (memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
+   if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
+   0, FW_CFG_SIG_SIZE) < 0 ||
+   memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
fw_cfg_io_cleanup();
return -ENODEV;
}
@@ -326,8 +328,7 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, 
struct kobject *kobj,
if (count > entry->size - pos)
count = entry->size - pos;
 
-   fw_cfg_read_blob(entry->select, buf, pos, count);
-   return count;
+   return fw_cfg_read_blob(entry->select, buf, pos, count);
 }
 
 static struct bin_attribute fw_cfg_sysfs_attr_raw = {
@@ -483,7 +484,11 @@ static int fw_cfg_register_dir_entries(void)
struct fw_cfg_file *dir;
size_t dir_size;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, _count, 0, sizeof(files_count));
+   ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, _count,
+   0, sizeof(files_count));
+   if (ret < 0)
+   return ret;
+
count = be32_to_cpu(files_count);
dir_size = count * sizeof(struct fw_cfg_file);
 
@@ -491,7 +496,10 @@ static int fw_cfg_register_dir_entries(void)
if (!dir)
return -ENOMEM;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files_count), dir_size);
+   ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, dir,
+   sizeof(files_count), dir_size);
+   if (ret < 0)
+   goto end;
 
for (i = 0; i < count; i++) {
ret = fw_cfg_register_file([i]);
@@ -499,6 +507,7 @@ static int fw_cfg_register_dir_entries(void)
break;
}
 
+end:
kfree(dir);
return ret;
 }
@@ -539,7 +548,10 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)
goto err_probe;
 
/* get revision number, add matching top-level attribute */
-   fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   err = fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   if (err < 0)
+   goto err_probe;
+
fw_cfg_rev = le32_to_cpu(rev);
err = sysfs_create_file(fw_cfg_top_ko, _cfg_rev_attr.attr);
if (err)
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 08/11] fw_cfg: handle fw_cfg_read_blob() error

2018-02-15 Thread Marc-André Lureau
fw_cfg_read_blob() may fail, but does not return error. This may lead
to undefined behaviours, such as a memcmp(sig, "QEMU") on uninitilized
memory. Return an error if ACPI locking failed. Also, the following
DMA read/write extension will add more error paths that should be
handled appropriately.

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 32 ++--
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index f6f90bef604c..5e6e5ac71dab 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -59,8 +59,8 @@ static void fw_cfg_sel_endianness(u16 key)
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
-static void fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+static ssize_t fw_cfg_read_blob(u16 key,
+   void *buf, loff_t pos, size_t count)
 {
u32 glk = -1U;
acpi_status status;
@@ -73,7 +73,7 @@ static void fw_cfg_read_blob(u16 key,
/* Should never get here */
WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
memset(buf, 0, count);
-   return;
+   return -EINVAL;
}
 
mutex_lock(_cfg_dev_lock);
@@ -84,6 +84,7 @@ static void fw_cfg_read_blob(u16 key,
mutex_unlock(_cfg_dev_lock);
 
acpi_release_global_lock(glk);
+   return count;
 }
 
 /* clean up fw_cfg device i/o */
@@ -165,8 +166,9 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
}
 
/* verify fw_cfg device signature */
-   fw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE);
-   if (memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
+   if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
+   0, FW_CFG_SIG_SIZE) < 0 ||
+   memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
fw_cfg_io_cleanup();
return -ENODEV;
}
@@ -326,8 +328,7 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, 
struct kobject *kobj,
if (count > entry->size - pos)
count = entry->size - pos;
 
-   fw_cfg_read_blob(entry->select, buf, pos, count);
-   return count;
+   return fw_cfg_read_blob(entry->select, buf, pos, count);
 }
 
 static struct bin_attribute fw_cfg_sysfs_attr_raw = {
@@ -483,7 +484,11 @@ static int fw_cfg_register_dir_entries(void)
struct fw_cfg_file *dir;
size_t dir_size;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, _count, 0, sizeof(files_count));
+   ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, _count,
+   0, sizeof(files_count));
+   if (ret < 0)
+   return ret;
+
count = be32_to_cpu(files_count);
dir_size = count * sizeof(struct fw_cfg_file);
 
@@ -491,7 +496,10 @@ static int fw_cfg_register_dir_entries(void)
if (!dir)
return -ENOMEM;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files_count), dir_size);
+   ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, dir,
+   sizeof(files_count), dir_size);
+   if (ret < 0)
+   goto end;
 
for (i = 0; i < count; i++) {
ret = fw_cfg_register_file([i]);
@@ -499,6 +507,7 @@ static int fw_cfg_register_dir_entries(void)
break;
}
 
+end:
kfree(dir);
return ret;
 }
@@ -539,7 +548,10 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)
goto err_probe;
 
/* get revision number, add matching top-level attribute */
-   fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   err = fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   if (err < 0)
+   goto err_probe;
+
fw_cfg_rev = le32_to_cpu(rev);
err = sysfs_create_file(fw_cfg_top_ko, _cfg_rev_attr.attr);
if (err)
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 10/11] fw_cfg: write vmcoreinfo details

2018-02-15 Thread Marc-André Lureau
If the "etc/vmcoreinfo" fw_cfg file is present and we are not running
the kdump kernel, write the addr/size of the vmcoreinfo ELF note.

The DMA operation is expected to run synchronously with today qemu,
but the specification states that it may become async, so we run
"control" field check in a loop for eventual changes.

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 143 -
 include/uapi/linux/fw_cfg.h|  31 +
 2 files changed, 171 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index c28bec4b5663..3015e77aebca 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -34,11 +34,17 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo <so...@cmu.edu>");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
 MODULE_LICENSE("GPL");
 
+/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
+static u32 fw_cfg_rev;
+
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -60,6 +66,64 @@ static void fw_cfg_sel_endianness(u16 key)
iowrite16(key, fw_cfg_reg_ctrl);
 }
 
+static inline bool fw_cfg_dma_enabled(void)
+{
+   return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
+}
+
+/* qemu fw_cfg device is sync today, but spec says it may become async */
+static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *d)
+{
+   for (;;) {
+   u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
+
+   /* do not reorder the read to d->control */
+   rmb();
+   if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
+   return;
+
+   cpu_relax();
+   }
+}
+
+static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
+{
+   phys_addr_t dma;
+   struct fw_cfg_dma_access *d = NULL;
+   ssize_t ret = length;
+
+   d = kmalloc(sizeof(*d), GFP_KERNEL);
+   if (!d) {
+   ret = -ENOMEM;
+   goto end;
+   }
+
+   /* fw_cfg device does not need IOMMU protection, so use physical 
addresses */
+   *d = (struct fw_cfg_dma_access) {
+   .address = cpu_to_be64(address ? virt_to_phys(address) : 0),
+   .length = cpu_to_be32(length),
+   .control = cpu_to_be32(control)
+   };
+
+   dma = virt_to_phys(d);
+
+   iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
+   /* force memory to sync before notifying device via MMIO */
+   wmb();
+   iowrite32be(dma, fw_cfg_reg_dma + 4);
+
+   fw_cfg_wait_for_control(d);
+
+   if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
+   ret = -EIO;
+   }
+
+end:
+   kfree(d);
+
+   return ret;
+}
+
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
 static ssize_t fw_cfg_read_blob(u16 key,
void *buf, loff_t pos, size_t count)
@@ -89,6 +153,47 @@ static ssize_t fw_cfg_read_blob(u16 key,
return count;
 }
 
+#ifdef CONFIG_CRASH_CORE
+/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
+static ssize_t fw_cfg_write_blob(u16 key,
+void *buf, loff_t pos, size_t count)
+{
+   u32 glk = -1U;
+   acpi_status status;
+   ssize_t ret = count;
+
+   /* If we have ACPI, ensure mutual exclusion against any potential
+* device access by the firmware, e.g. via AML methods:
+*/
+   status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
+   if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
+   /* Should never get here */
+   WARN(1, "%s: Failed to lock ACPI!\n", __func__);
+   return -EINVAL;
+   }
+
+   mutex_lock(_cfg_dev_lock);
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+ | FW_CFG_DMA_CTL_SELECT
+ | FW_CFG_DMA_CTL_WRITE);
+   } else {
+   fw_cfg_sel_endianness(key);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (ret < 0)
+   goto end;
+   ret = fw_cfg_dma_transfer(buf, count, FW_CFG_DMA_CTL_WRITE);
+   }
+
+end:
+   mutex_unlock(_cfg_dev_lock);
+
+   acpi_release_global_lock(glk);
+
+   return ret;
+}
+#endif /* CONFIG_CRASH_CORE */
+
 /* clean up fw_cfg device i/o */
 static void fw_cfg_io_cleanup(void)
 {
@@ -188,9 +293,6 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
return 0;
 }
 
-/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg t

[PATCH v15 10/11] fw_cfg: write vmcoreinfo details

2018-02-15 Thread Marc-André Lureau
If the "etc/vmcoreinfo" fw_cfg file is present and we are not running
the kdump kernel, write the addr/size of the vmcoreinfo ELF note.

The DMA operation is expected to run synchronously with today qemu,
but the specification states that it may become async, so we run
"control" field check in a loop for eventual changes.

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 143 -
 include/uapi/linux/fw_cfg.h|  31 +
 2 files changed, 171 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index c28bec4b5663..3015e77aebca 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -34,11 +34,17 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo ");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
 MODULE_LICENSE("GPL");
 
+/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
+static u32 fw_cfg_rev;
+
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -60,6 +66,64 @@ static void fw_cfg_sel_endianness(u16 key)
iowrite16(key, fw_cfg_reg_ctrl);
 }
 
+static inline bool fw_cfg_dma_enabled(void)
+{
+   return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
+}
+
+/* qemu fw_cfg device is sync today, but spec says it may become async */
+static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *d)
+{
+   for (;;) {
+   u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
+
+   /* do not reorder the read to d->control */
+   rmb();
+   if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
+   return;
+
+   cpu_relax();
+   }
+}
+
+static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
+{
+   phys_addr_t dma;
+   struct fw_cfg_dma_access *d = NULL;
+   ssize_t ret = length;
+
+   d = kmalloc(sizeof(*d), GFP_KERNEL);
+   if (!d) {
+   ret = -ENOMEM;
+   goto end;
+   }
+
+   /* fw_cfg device does not need IOMMU protection, so use physical 
addresses */
+   *d = (struct fw_cfg_dma_access) {
+   .address = cpu_to_be64(address ? virt_to_phys(address) : 0),
+   .length = cpu_to_be32(length),
+   .control = cpu_to_be32(control)
+   };
+
+   dma = virt_to_phys(d);
+
+   iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
+   /* force memory to sync before notifying device via MMIO */
+   wmb();
+   iowrite32be(dma, fw_cfg_reg_dma + 4);
+
+   fw_cfg_wait_for_control(d);
+
+   if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
+   ret = -EIO;
+   }
+
+end:
+   kfree(d);
+
+   return ret;
+}
+
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
 static ssize_t fw_cfg_read_blob(u16 key,
void *buf, loff_t pos, size_t count)
@@ -89,6 +153,47 @@ static ssize_t fw_cfg_read_blob(u16 key,
return count;
 }
 
+#ifdef CONFIG_CRASH_CORE
+/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
+static ssize_t fw_cfg_write_blob(u16 key,
+void *buf, loff_t pos, size_t count)
+{
+   u32 glk = -1U;
+   acpi_status status;
+   ssize_t ret = count;
+
+   /* If we have ACPI, ensure mutual exclusion against any potential
+* device access by the firmware, e.g. via AML methods:
+*/
+   status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
+   if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
+   /* Should never get here */
+   WARN(1, "%s: Failed to lock ACPI!\n", __func__);
+   return -EINVAL;
+   }
+
+   mutex_lock(_cfg_dev_lock);
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+ | FW_CFG_DMA_CTL_SELECT
+ | FW_CFG_DMA_CTL_WRITE);
+   } else {
+   fw_cfg_sel_endianness(key);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (ret < 0)
+   goto end;
+   ret = fw_cfg_dma_transfer(buf, count, FW_CFG_DMA_CTL_WRITE);
+   }
+
+end:
+   mutex_unlock(_cfg_dev_lock);
+
+   acpi_release_global_lock(glk);
+
+   return ret;
+}
+#endif /* CONFIG_CRASH_CORE */
+
 /* clean up fw_cfg device i/o */
 static void fw_cfg_io_cleanup(void)
 {
@@ -188,9 +293,6 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
return 0;
 }
 
-/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
-static u32 fw_cfg_rev;
-
 static ssize_t fw_c

[PATCH v15 07/11] fw_cfg: remove inline from fw_cfg_read_blob()

2018-02-15 Thread Marc-André Lureau
The function is not small and getting bigger.

Let the compiler decide instead. No profiling done, hopefully
unnecessary.

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 805372e8e50d..f6f90bef604c 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -59,8 +59,8 @@ static void fw_cfg_sel_endianness(u16 key)
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
-static inline void fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+static void fw_cfg_read_blob(u16 key,
+   void *buf, loff_t pos, size_t count)
 {
u32 glk = -1U;
acpi_status status;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 07/11] fw_cfg: remove inline from fw_cfg_read_blob()

2018-02-15 Thread Marc-André Lureau
The function is not small and getting bigger.

Let the compiler decide instead. No profiling done, hopefully
unnecessary.

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 805372e8e50d..f6f90bef604c 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -59,8 +59,8 @@ static void fw_cfg_sel_endianness(u16 key)
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
-static inline void fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+static void fw_cfg_read_blob(u16 key,
+   void *buf, loff_t pos, size_t count)
 {
u32 glk = -1U;
acpi_status status;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 03/11] fw_cfg: fix sparse warnings in fw_cfg_sel_endianness()

2018-02-15 Thread Marc-André Lureau
Dispatch to the appropriate iowrite() instead of casting restricted
type to u16.

- if fw_cfg_is_mmio:
  before: iowrite16(cpu_to_be16(key))
  after: iowrite16be(key)
- if !fw_cfg_is_mmio:
  before: iowrite16(cpu_to_le16(key))
  after: iowrite16(key)
  which is equivalent on little-endian systems, where fw_cfg IO is supported.

Fixes:
$ make C=1 CF=-D__CHECK_ENDIAN__ drivers/firmware/qemu_fw_cfg.o

drivers/firmware/qemu_fw_cfg.c:55:33: warning: restricted __be16 degrades to 
integer
drivers/firmware/qemu_fw_cfg.c:55:52: warning: restricted __le16 degrades to 
integer

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 42601a3eaed5..6164731a3c35 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -50,9 +50,12 @@ static void __iomem *fw_cfg_reg_data;
 static DEFINE_MUTEX(fw_cfg_dev_lock);
 
 /* pick appropriate endianness for selector key */
-static inline u16 fw_cfg_sel_endianness(u16 key)
+static void fw_cfg_sel_endianness(u16 key)
 {
-   return fw_cfg_is_mmio ? cpu_to_be16(key) : cpu_to_le16(key);
+   if (fw_cfg_is_mmio)
+   iowrite16be(key, fw_cfg_reg_ctrl);
+   else
+   iowrite16(key, fw_cfg_reg_ctrl);
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
@@ -74,7 +77,7 @@ static inline void fw_cfg_read_blob(u16 key,
}
 
mutex_lock(_cfg_dev_lock);
-   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+   fw_cfg_sel_endianness(key);
while (pos-- > 0)
ioread8(fw_cfg_reg_data);
ioread8_rep(fw_cfg_reg_data, buf, count);
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 03/11] fw_cfg: fix sparse warnings in fw_cfg_sel_endianness()

2018-02-15 Thread Marc-André Lureau
Dispatch to the appropriate iowrite() instead of casting restricted
type to u16.

- if fw_cfg_is_mmio:
  before: iowrite16(cpu_to_be16(key))
  after: iowrite16be(key)
- if !fw_cfg_is_mmio:
  before: iowrite16(cpu_to_le16(key))
  after: iowrite16(key)
  which is equivalent on little-endian systems, where fw_cfg IO is supported.

Fixes:
$ make C=1 CF=-D__CHECK_ENDIAN__ drivers/firmware/qemu_fw_cfg.o

drivers/firmware/qemu_fw_cfg.c:55:33: warning: restricted __be16 degrades to 
integer
drivers/firmware/qemu_fw_cfg.c:55:52: warning: restricted __le16 degrades to 
integer

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 42601a3eaed5..6164731a3c35 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -50,9 +50,12 @@ static void __iomem *fw_cfg_reg_data;
 static DEFINE_MUTEX(fw_cfg_dev_lock);
 
 /* pick appropriate endianness for selector key */
-static inline u16 fw_cfg_sel_endianness(u16 key)
+static void fw_cfg_sel_endianness(u16 key)
 {
-   return fw_cfg_is_mmio ? cpu_to_be16(key) : cpu_to_le16(key);
+   if (fw_cfg_is_mmio)
+   iowrite16be(key, fw_cfg_reg_ctrl);
+   else
+   iowrite16(key, fw_cfg_reg_ctrl);
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
@@ -74,7 +77,7 @@ static inline void fw_cfg_read_blob(u16 key,
}
 
mutex_lock(_cfg_dev_lock);
-   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+   fw_cfg_sel_endianness(key);
while (pos-- > 0)
ioread8(fw_cfg_reg_data);
ioread8_rep(fw_cfg_reg_data, buf, count);
-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 00/11] fw_cfg: add DMA operations & etc/vmcoreinfo support

2018-02-15 Thread Marc-André Lureau
Hi,

This series adds DMA operations support to the qemu fw_cfg kernel
module and populates "etc/vmcoreinfo" with vmcoreinfo location
details (entry added since qemu 2.11 with -device vmcoreinfo).

v15:
- fix fw_cfg.h uapi header #include
- use BSD license for fw_cfg.h uapi header
- move the uapi defines/structs for DMA & vmcoreinfo in the
  corresponding patch
- use cpu_relax() instead of usleep_range(50, 100);
- replace do { } while(true) by for (;;)
- fix the rmb() call location
- add a preliminary patch to handle error from fw_cfg_write_blob()
- rewrite fw_cfg_sel_endianness() to wrap iowrite() calls

v14:
- add "fw_cfg: add a public uapi header"
- fix sparse warnings & don't introduce new warnings
- add memory barriers to force IO ordering
- split fw_cfg_read_blob() in fw_cfg_read_blob_io() and
  fw_cfg_read_blob_dma()
- add error handling to fw_cfg_read_blob() callers
- minor stylistic changes

v13:
- reorder patch series, introduce DMA write before DMA read
- do some measurements of DMA read speed-ups

v12:
- fix virt_to_phys(NULL) panic with CONFIG_DEBUG_VIRTUAL=y
- do not use DMA read, except for kmalloc() memory we allocated
  ourself (only fw_cfg_register_dir_entries() so far)

v11:
- add #include  in last patch,
  fixing kbuild .config test

Marc-André Lureau (11):
  crash: export paddr_vmcoreinfo_note()
  fw_cfg: add a public uapi header
  fw_cfg: fix sparse warnings in fw_cfg_sel_endianness()
  fw_cfg: fix sparse warnings with fw_cfg_file
  fw_cfg: fix sparse warning reading FW_CFG_ID
  fw_cfg: fix sparse warnings around FW_CFG_FILE_DIR read
  fw_cfg: remove inline from fw_cfg_read_blob()
  fw_cfg: handle fw_cfg_read_blob() error
  fw_cfg: add DMA register
  fw_cfg: write vmcoreinfo details
  RFC: fw_cfg: do DMA read operation

 MAINTAINERS|   1 +
 drivers/firmware/qemu_fw_cfg.c | 334 +
 include/uapi/linux/fw_cfg.h|  97 
 kernel/crash_core.c|   1 +
 4 files changed, 369 insertions(+), 64 deletions(-)
 create mode 100644 include/uapi/linux/fw_cfg.h

-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 00/11] fw_cfg: add DMA operations & etc/vmcoreinfo support

2018-02-15 Thread Marc-André Lureau
Hi,

This series adds DMA operations support to the qemu fw_cfg kernel
module and populates "etc/vmcoreinfo" with vmcoreinfo location
details (entry added since qemu 2.11 with -device vmcoreinfo).

v15:
- fix fw_cfg.h uapi header #include
- use BSD license for fw_cfg.h uapi header
- move the uapi defines/structs for DMA & vmcoreinfo in the
  corresponding patch
- use cpu_relax() instead of usleep_range(50, 100);
- replace do { } while(true) by for (;;)
- fix the rmb() call location
- add a preliminary patch to handle error from fw_cfg_write_blob()
- rewrite fw_cfg_sel_endianness() to wrap iowrite() calls

v14:
- add "fw_cfg: add a public uapi header"
- fix sparse warnings & don't introduce new warnings
- add memory barriers to force IO ordering
- split fw_cfg_read_blob() in fw_cfg_read_blob_io() and
  fw_cfg_read_blob_dma()
- add error handling to fw_cfg_read_blob() callers
- minor stylistic changes

v13:
- reorder patch series, introduce DMA write before DMA read
- do some measurements of DMA read speed-ups

v12:
- fix virt_to_phys(NULL) panic with CONFIG_DEBUG_VIRTUAL=y
- do not use DMA read, except for kmalloc() memory we allocated
  ourself (only fw_cfg_register_dir_entries() so far)

v11:
- add #include  in last patch,
  fixing kbuild .config test

Marc-André Lureau (11):
  crash: export paddr_vmcoreinfo_note()
  fw_cfg: add a public uapi header
  fw_cfg: fix sparse warnings in fw_cfg_sel_endianness()
  fw_cfg: fix sparse warnings with fw_cfg_file
  fw_cfg: fix sparse warning reading FW_CFG_ID
  fw_cfg: fix sparse warnings around FW_CFG_FILE_DIR read
  fw_cfg: remove inline from fw_cfg_read_blob()
  fw_cfg: handle fw_cfg_read_blob() error
  fw_cfg: add DMA register
  fw_cfg: write vmcoreinfo details
  RFC: fw_cfg: do DMA read operation

 MAINTAINERS|   1 +
 drivers/firmware/qemu_fw_cfg.c | 334 +
 include/uapi/linux/fw_cfg.h|  97 
 kernel/crash_core.c|   1 +
 4 files changed, 369 insertions(+), 64 deletions(-)
 create mode 100644 include/uapi/linux/fw_cfg.h

-- 
2.16.1.73.g5832b7e9f2



[PATCH v15 09/11] fw_cfg: add DMA register

2018-02-15 Thread Marc-André Lureau
Add an optional  kernel module (or command line) parameter
using the following syntax:

  [qemu_fw_cfg.]ioport=@[::[:]]
 or
  [qemu_fw_cfg.]mmio=@[::[:]]

and initializes the register address using given or default offset.

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
Reviewed-by: Gabriel Somlo <so...@cmu.edu>
---
 drivers/firmware/qemu_fw_cfg.c | 53 --
 1 file changed, 41 insertions(+), 12 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 5e6e5ac71dab..c28bec4b5663 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -10,20 +10,21 @@
  * and select subsets of aarch64), a Device Tree node (on arm), or using
  * a kernel module (or command line) parameter with the following syntax:
  *
- *  [qemu_fw_cfg.]ioport=@[::]
+ *  [qemu_fw_cfg.]ioport=@[::[:]]
  * or
- *  [qemu_fw_cfg.]mmio=@[::]
+ *  [qemu_fw_cfg.]mmio=@[::[:]]
  *
  * where:
  *   := size of ioport or mmio range
  *   := physical base address of ioport or mmio range
  *   := (optional) offset of control register
  *   := (optional) offset of data register
+ *   := (optional) offset of dma register
  *
  * e.g.:
- *  qemu_fw_cfg.ioport=2@0x510:0:1 (the default on x86)
+ *  qemu_fw_cfg.ioport=12@0x510:0:1:4  (the default on x86)
  * or
- *  qemu_fw_cfg.mmio=0xA@0x902:8:0 (the default on arm)
+ *  qemu_fw_cfg.mmio=16@0x902:8:0:16   (the default on arm)
  */
 
 #include 
@@ -45,6 +46,7 @@ static resource_size_t fw_cfg_p_size;
 static void __iomem *fw_cfg_dev_base;
 static void __iomem *fw_cfg_reg_ctrl;
 static void __iomem *fw_cfg_reg_data;
+static void __iomem *fw_cfg_reg_dma;
 
 /* atomic access to fw_cfg device (potentially slow i/o, so using mutex) */
 static DEFINE_MUTEX(fw_cfg_dev_lock);
@@ -104,12 +106,14 @@ static void fw_cfg_io_cleanup(void)
 # if (defined(CONFIG_ARM) || defined(CONFIG_ARM64))
 #  define FW_CFG_CTRL_OFF 0x08
 #  define FW_CFG_DATA_OFF 0x00
+#  define FW_CFG_DMA_OFF 0x10
 # elif (defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC32)) /* ppc/mac,sun4m 
*/
 #  define FW_CFG_CTRL_OFF 0x00
 #  define FW_CFG_DATA_OFF 0x02
 # elif (defined(CONFIG_X86) || defined(CONFIG_SPARC64)) /* x86, sun4u */
 #  define FW_CFG_CTRL_OFF 0x00
 #  define FW_CFG_DATA_OFF 0x01
+#  define FW_CFG_DMA_OFF 0x04
 # else
 #  error "QEMU FW_CFG not available on this architecture!"
 # endif
@@ -119,7 +123,7 @@ static void fw_cfg_io_cleanup(void)
 static int fw_cfg_do_platform_probe(struct platform_device *pdev)
 {
char sig[FW_CFG_SIG_SIZE];
-   struct resource *range, *ctrl, *data;
+   struct resource *range, *ctrl, *data, *dma;
 
/* acquire i/o range details */
fw_cfg_is_mmio = false;
@@ -156,6 +160,7 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
/* were custom register offsets provided (e.g. on the command line)? */
ctrl = platform_get_resource_byname(pdev, IORESOURCE_REG, "ctrl");
data = platform_get_resource_byname(pdev, IORESOURCE_REG, "data");
+   dma = platform_get_resource_byname(pdev, IORESOURCE_REG, "dma");
if (ctrl && data) {
fw_cfg_reg_ctrl = fw_cfg_dev_base + ctrl->start;
fw_cfg_reg_data = fw_cfg_dev_base + data->start;
@@ -165,6 +170,13 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
fw_cfg_reg_data = fw_cfg_dev_base + FW_CFG_DATA_OFF;
}
 
+   if (dma)
+   fw_cfg_reg_dma = fw_cfg_dev_base + dma->start;
+#ifdef FW_CFG_DMA_OFF
+   else
+   fw_cfg_reg_dma = fw_cfg_dev_base + FW_CFG_DMA_OFF;
+#endif
+
/* verify fw_cfg device signature */
if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
0, FW_CFG_SIG_SIZE) < 0 ||
@@ -630,6 +642,7 @@ static struct platform_device *fw_cfg_cmdline_dev;
 /* use special scanf/printf modifier for phys_addr_t, resource_size_t */
 #define PH_ADDR_SCAN_FMT "@%" __PHYS_ADDR_PREFIX "i%n" \
 ":%" __PHYS_ADDR_PREFIX "i" \
+":%" __PHYS_ADDR_PREFIX "i%n" \
 ":%" __PHYS_ADDR_PREFIX "i%n"
 
 #define PH_ADDR_PR_1_FMT "0x%" __PHYS_ADDR_PREFIX "x@" \
@@ -639,12 +652,15 @@ static struct platform_device *fw_cfg_cmdline_dev;
 ":%" __PHYS_ADDR_PREFIX "u" \
 ":%" __PHYS_ADDR_PREFIX "u"
 
+#define PH_ADDR_PR_4_FMT PH_ADDR_PR_3_FMT \
+":%" __PHYS_ADDR_PREFIX "u"
+
 static int fw_cfg_cmdline_set(const char *arg, const struct kernel_param *kp)
 {
-   struct resource res[3] = {};
+   struct resource res[4] 

[PATCH v15 11/11] RFC: fw_cfg: do DMA read operation

2018-02-15 Thread Marc-André Lureau
Modify fw_cfg_read_blob() to use DMA if the device supports it.
Return errors, because the operation may fail.

So far, only one call in fw_cfg_register_dir_entries() is using
kmalloc'ed buf and is thus clearly eligible to DMA read.

Initially, I didn't implement DMA read to speed up boot time, but as a
first step before introducing DMA write (since read operations were
already presents). Even more, I didn't realize fw-cfg entries were
being read by the kernel during boot by default. But actally fw-cfg
entries are being populated during module probe. I knew DMA improved a
lot bios boot time (the main reason the DMA interface was added
afaik). Let see the time it would take to read the whole ACPI
tables (128kb allocated)

 # time cat /sys/firmware/qemu_fw_cfg/by_name/etc/acpi/tables/raw
  - with DMA: sys 0m0.003s
  - without DMA (-global fw_cfg.dma_enabled=off): sys 0m7.674s

FW_CFG_FILE_DIR (0x19) is the only "file" that is read during kernel
boot to populate sysfs qemu_fw_cfg directory, and it is quite
small (1-2kb). Since it does not expose itself, in order to measure
the time it takes to read such small file, I took a comparable sized
file of 2048 bytes and exposed it (-fw_cfg test,file=file with a
modified read_raw enabling DMA)

 # perf stat -r 100 cat /sys/firmware/qemu_fw_cfg/by_name/test/raw >/dev/null
  - with DMA:
  0.636037  task-clock (msec) #0.141 CPUs utilized  
  ( +-  1.19% )
  - without DMA:
  6.430128  task-clock (msec) #0.622 CPUs utilized  
  ( +-  0.22% )

That's a few msec saved during boot by enabling DMA read (the gain
would be more substantial if other & bigger fw-cfg entries are read by
others from sysfs, unfortunately, it's not clear if we can always
enable DMA there)

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 61 ++
 1 file changed, 50 insertions(+), 11 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 3015e77aebca..94df57e9be66 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -124,12 +124,47 @@ static ssize_t fw_cfg_dma_transfer(void *address, u32 
length, u32 control)
return ret;
 }
 
+/* with acpi & dev locks taken */
+static ssize_t fw_cfg_read_blob_dma(u16 key,
+   void *buf, loff_t pos, size_t count)
+{
+   ssize_t ret;
+
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+   | FW_CFG_DMA_CTL_SELECT
+   | FW_CFG_DMA_CTL_READ);
+   } else {
+   fw_cfg_sel_endianness(key);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (ret < 0)
+   return ret;
+   ret = fw_cfg_dma_transfer(buf, count,
+   FW_CFG_DMA_CTL_READ);
+   }
+
+   return ret;
+}
+
+/* with acpi & dev locks taken */
+static ssize_t fw_cfg_read_blob_io(u16 key,
+   void *buf, loff_t pos, size_t count)
+{
+   fw_cfg_sel_endianness(key);
+   while (pos-- > 0)
+   ioread8(fw_cfg_reg_data);
+   ioread8_rep(fw_cfg_reg_data, buf, count);
+   return count;
+}
+
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
 static ssize_t fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+   void *buf, loff_t pos, size_t count,
+   bool dma)
 {
u32 glk = -1U;
acpi_status status;
+   ssize_t ret;
 
/* If we have ACPI, ensure mutual exclusion against any potential
 * device access by the firmware, e.g. via AML methods:
@@ -143,14 +178,17 @@ static ssize_t fw_cfg_read_blob(u16 key,
}
 
mutex_lock(_cfg_dev_lock);
-   fw_cfg_sel_endianness(key);
-   while (pos-- > 0)
-   ioread8(fw_cfg_reg_data);
-   ioread8_rep(fw_cfg_reg_data, buf, count);
+   if (dma && fw_cfg_dma_enabled()) {
+   ret = fw_cfg_read_blob_dma(key, buf, pos, count);
+   } else {
+   ret = fw_cfg_read_blob_io(key, buf, pos, count);
+   }
+
mutex_unlock(_cfg_dev_lock);
 
acpi_release_global_lock(glk);
-   return count;
+
+   return ret;
 }
 
 #ifdef CONFIG_CRASH_CORE
@@ -284,7 +322,7 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
 
/* verify fw_cfg device signature */
if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
-   0, FW_CFG_SIG_SIZE) < 0 ||
+   0, FW_CFG_SIG_SIZE, false) < 0 ||
memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
fw_cfg_io_cleanup

[PATCH v15 11/11] RFC: fw_cfg: do DMA read operation

2018-02-15 Thread Marc-André Lureau
Modify fw_cfg_read_blob() to use DMA if the device supports it.
Return errors, because the operation may fail.

So far, only one call in fw_cfg_register_dir_entries() is using
kmalloc'ed buf and is thus clearly eligible to DMA read.

Initially, I didn't implement DMA read to speed up boot time, but as a
first step before introducing DMA write (since read operations were
already presents). Even more, I didn't realize fw-cfg entries were
being read by the kernel during boot by default. But actally fw-cfg
entries are being populated during module probe. I knew DMA improved a
lot bios boot time (the main reason the DMA interface was added
afaik). Let see the time it would take to read the whole ACPI
tables (128kb allocated)

 # time cat /sys/firmware/qemu_fw_cfg/by_name/etc/acpi/tables/raw
  - with DMA: sys 0m0.003s
  - without DMA (-global fw_cfg.dma_enabled=off): sys 0m7.674s

FW_CFG_FILE_DIR (0x19) is the only "file" that is read during kernel
boot to populate sysfs qemu_fw_cfg directory, and it is quite
small (1-2kb). Since it does not expose itself, in order to measure
the time it takes to read such small file, I took a comparable sized
file of 2048 bytes and exposed it (-fw_cfg test,file=file with a
modified read_raw enabling DMA)

 # perf stat -r 100 cat /sys/firmware/qemu_fw_cfg/by_name/test/raw >/dev/null
  - with DMA:
  0.636037  task-clock (msec) #0.141 CPUs utilized  
  ( +-  1.19% )
  - without DMA:
  6.430128  task-clock (msec) #0.622 CPUs utilized  
  ( +-  0.22% )

That's a few msec saved during boot by enabling DMA read (the gain
would be more substantial if other & bigger fw-cfg entries are read by
others from sysfs, unfortunately, it's not clear if we can always
enable DMA there)

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 61 ++
 1 file changed, 50 insertions(+), 11 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 3015e77aebca..94df57e9be66 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -124,12 +124,47 @@ static ssize_t fw_cfg_dma_transfer(void *address, u32 
length, u32 control)
return ret;
 }
 
+/* with acpi & dev locks taken */
+static ssize_t fw_cfg_read_blob_dma(u16 key,
+   void *buf, loff_t pos, size_t count)
+{
+   ssize_t ret;
+
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+   | FW_CFG_DMA_CTL_SELECT
+   | FW_CFG_DMA_CTL_READ);
+   } else {
+   fw_cfg_sel_endianness(key);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (ret < 0)
+   return ret;
+   ret = fw_cfg_dma_transfer(buf, count,
+   FW_CFG_DMA_CTL_READ);
+   }
+
+   return ret;
+}
+
+/* with acpi & dev locks taken */
+static ssize_t fw_cfg_read_blob_io(u16 key,
+   void *buf, loff_t pos, size_t count)
+{
+   fw_cfg_sel_endianness(key);
+   while (pos-- > 0)
+   ioread8(fw_cfg_reg_data);
+   ioread8_rep(fw_cfg_reg_data, buf, count);
+   return count;
+}
+
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
 static ssize_t fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+   void *buf, loff_t pos, size_t count,
+   bool dma)
 {
u32 glk = -1U;
acpi_status status;
+   ssize_t ret;
 
/* If we have ACPI, ensure mutual exclusion against any potential
 * device access by the firmware, e.g. via AML methods:
@@ -143,14 +178,17 @@ static ssize_t fw_cfg_read_blob(u16 key,
}
 
mutex_lock(_cfg_dev_lock);
-   fw_cfg_sel_endianness(key);
-   while (pos-- > 0)
-   ioread8(fw_cfg_reg_data);
-   ioread8_rep(fw_cfg_reg_data, buf, count);
+   if (dma && fw_cfg_dma_enabled()) {
+   ret = fw_cfg_read_blob_dma(key, buf, pos, count);
+   } else {
+   ret = fw_cfg_read_blob_io(key, buf, pos, count);
+   }
+
mutex_unlock(_cfg_dev_lock);
 
acpi_release_global_lock(glk);
-   return count;
+
+   return ret;
 }
 
 #ifdef CONFIG_CRASH_CORE
@@ -284,7 +322,7 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
 
/* verify fw_cfg device signature */
if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
-   0, FW_CFG_SIG_SIZE) < 0 ||
+   0, FW_CFG_SIG_SIZE, false) < 0 ||
memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
fw_cfg_io_cleanup();
return -ENODEV;
@@ -

[PATCH v15 09/11] fw_cfg: add DMA register

2018-02-15 Thread Marc-André Lureau
Add an optional  kernel module (or command line) parameter
using the following syntax:

  [qemu_fw_cfg.]ioport=@[::[:]]
 or
  [qemu_fw_cfg.]mmio=@[::[:]]

and initializes the register address using given or default offset.

Signed-off-by: Marc-André Lureau 
Reviewed-by: Gabriel Somlo 
---
 drivers/firmware/qemu_fw_cfg.c | 53 --
 1 file changed, 41 insertions(+), 12 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 5e6e5ac71dab..c28bec4b5663 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -10,20 +10,21 @@
  * and select subsets of aarch64), a Device Tree node (on arm), or using
  * a kernel module (or command line) parameter with the following syntax:
  *
- *  [qemu_fw_cfg.]ioport=@[::]
+ *  [qemu_fw_cfg.]ioport=@[::[:]]
  * or
- *  [qemu_fw_cfg.]mmio=@[::]
+ *  [qemu_fw_cfg.]mmio=@[::[:]]
  *
  * where:
  *   := size of ioport or mmio range
  *   := physical base address of ioport or mmio range
  *   := (optional) offset of control register
  *   := (optional) offset of data register
+ *   := (optional) offset of dma register
  *
  * e.g.:
- *  qemu_fw_cfg.ioport=2@0x510:0:1 (the default on x86)
+ *  qemu_fw_cfg.ioport=12@0x510:0:1:4  (the default on x86)
  * or
- *  qemu_fw_cfg.mmio=0xA@0x902:8:0 (the default on arm)
+ *  qemu_fw_cfg.mmio=16@0x902:8:0:16   (the default on arm)
  */
 
 #include 
@@ -45,6 +46,7 @@ static resource_size_t fw_cfg_p_size;
 static void __iomem *fw_cfg_dev_base;
 static void __iomem *fw_cfg_reg_ctrl;
 static void __iomem *fw_cfg_reg_data;
+static void __iomem *fw_cfg_reg_dma;
 
 /* atomic access to fw_cfg device (potentially slow i/o, so using mutex) */
 static DEFINE_MUTEX(fw_cfg_dev_lock);
@@ -104,12 +106,14 @@ static void fw_cfg_io_cleanup(void)
 # if (defined(CONFIG_ARM) || defined(CONFIG_ARM64))
 #  define FW_CFG_CTRL_OFF 0x08
 #  define FW_CFG_DATA_OFF 0x00
+#  define FW_CFG_DMA_OFF 0x10
 # elif (defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC32)) /* ppc/mac,sun4m 
*/
 #  define FW_CFG_CTRL_OFF 0x00
 #  define FW_CFG_DATA_OFF 0x02
 # elif (defined(CONFIG_X86) || defined(CONFIG_SPARC64)) /* x86, sun4u */
 #  define FW_CFG_CTRL_OFF 0x00
 #  define FW_CFG_DATA_OFF 0x01
+#  define FW_CFG_DMA_OFF 0x04
 # else
 #  error "QEMU FW_CFG not available on this architecture!"
 # endif
@@ -119,7 +123,7 @@ static void fw_cfg_io_cleanup(void)
 static int fw_cfg_do_platform_probe(struct platform_device *pdev)
 {
char sig[FW_CFG_SIG_SIZE];
-   struct resource *range, *ctrl, *data;
+   struct resource *range, *ctrl, *data, *dma;
 
/* acquire i/o range details */
fw_cfg_is_mmio = false;
@@ -156,6 +160,7 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
/* were custom register offsets provided (e.g. on the command line)? */
ctrl = platform_get_resource_byname(pdev, IORESOURCE_REG, "ctrl");
data = platform_get_resource_byname(pdev, IORESOURCE_REG, "data");
+   dma = platform_get_resource_byname(pdev, IORESOURCE_REG, "dma");
if (ctrl && data) {
fw_cfg_reg_ctrl = fw_cfg_dev_base + ctrl->start;
fw_cfg_reg_data = fw_cfg_dev_base + data->start;
@@ -165,6 +170,13 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
fw_cfg_reg_data = fw_cfg_dev_base + FW_CFG_DATA_OFF;
}
 
+   if (dma)
+   fw_cfg_reg_dma = fw_cfg_dev_base + dma->start;
+#ifdef FW_CFG_DMA_OFF
+   else
+   fw_cfg_reg_dma = fw_cfg_dev_base + FW_CFG_DMA_OFF;
+#endif
+
/* verify fw_cfg device signature */
if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
0, FW_CFG_SIG_SIZE) < 0 ||
@@ -630,6 +642,7 @@ static struct platform_device *fw_cfg_cmdline_dev;
 /* use special scanf/printf modifier for phys_addr_t, resource_size_t */
 #define PH_ADDR_SCAN_FMT "@%" __PHYS_ADDR_PREFIX "i%n" \
 ":%" __PHYS_ADDR_PREFIX "i" \
+":%" __PHYS_ADDR_PREFIX "i%n" \
 ":%" __PHYS_ADDR_PREFIX "i%n"
 
 #define PH_ADDR_PR_1_FMT "0x%" __PHYS_ADDR_PREFIX "x@" \
@@ -639,12 +652,15 @@ static struct platform_device *fw_cfg_cmdline_dev;
 ":%" __PHYS_ADDR_PREFIX "u" \
 ":%" __PHYS_ADDR_PREFIX "u"
 
+#define PH_ADDR_PR_4_FMT PH_ADDR_PR_3_FMT \
+":%" __PHYS_ADDR_PREFIX "u"
+
 static int fw_cfg_cmdline_set(const char *arg, const struct kernel_param *kp)
 {
-   struct resource res[3] = {};
+   struct resource res[4] = {};
char *str;
phys_addr_t base;
-

Re: [PATCH v14 2/9] fw_cfg: add a public uapi header

2018-02-15 Thread Marc-André Lureau
Hi

On Thu, Feb 15, 2018 at 7:20 PM, Michael S. Tsirkin <m...@redhat.com> wrote:
> On Thu, Feb 15, 2018 at 10:25:27AM +0100, Marc-Andre Lureau wrote:
>> Hi
>>
>> On Wed, Feb 14, 2018 at 9:41 PM, Michael S. Tsirkin <m...@redhat.com> wrote:
>> > On Wed, Feb 14, 2018 at 03:18:43PM +0100, Marc-André Lureau wrote:
>> >> Create a common header file for well-known values and structures to be
>> >> shared by the Linux kernel with qemu or other projects.
>> >>
>> >> Suggested-by: Michael S. Tsirkin <m...@redhat.com>
>> >> Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
>> >>
>> >> ---
>> >>
>> >> The related qemu patch making use of it, to be submitted:
>> >> https://github.com/elmarco/qemu/commit/4884fc9e9c4c4467a371e5a40f3181239e1b70f5
>> >> ---
>> >>  MAINTAINERS|   1 +
>> >>  drivers/firmware/qemu_fw_cfg.c |  22 +
>> >>  include/uapi/linux/fw_cfg.h| 102 
>> >> +
>> >>  3 files changed, 105 insertions(+), 20 deletions(-)
>> >>  create mode 100644 include/uapi/linux/fw_cfg.h
>> >>
>> >> diff --git a/MAINTAINERS b/MAINTAINERS
>> >> index 3bdc260e36b7..a66b65f62811 100644
>> >> --- a/MAINTAINERS
>> >> +++ b/MAINTAINERS
>> >> @@ -11352,6 +11352,7 @@ M:"Michael S. Tsirkin" <m...@redhat.com>
>> >>  L:   qemu-de...@nongnu.org
>> >>  S:   Maintained
>> >>  F:   drivers/firmware/qemu_fw_cfg.c
>> >> +F:   include/uapi/linux/fw_cfg.h
>> >>
>> >>  QIB DRIVER
>> >>  M:   Dennis Dalessandro <dennis.dalessan...@intel.com>
>> >> diff --git a/drivers/firmware/qemu_fw_cfg.c 
>> >> b/drivers/firmware/qemu_fw_cfg.c
>> >> index a41b572eeeb1..90f467232777 100644
>> >> --- a/drivers/firmware/qemu_fw_cfg.c
>> >> +++ b/drivers/firmware/qemu_fw_cfg.c
>> >> @@ -32,30 +32,12 @@
>> >>  #include 
>> >>  #include 
>> >>  #include 
>> >> +#include 
>> >>
>> >>  MODULE_AUTHOR("Gabriel L. Somlo <so...@cmu.edu>");
>> >>  MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
>> >>  MODULE_LICENSE("GPL");
>> >>
>> >> -/* selector key values for "well-known" fw_cfg entries */
>> >> -#define FW_CFG_SIGNATURE  0x00
>> >> -#define FW_CFG_ID 0x01
>> >> -#define FW_CFG_FILE_DIR   0x19
>> >> -
>> >> -/* size in bytes of fw_cfg signature */
>> >> -#define FW_CFG_SIG_SIZE 4
>> >> -
>> >> -/* fw_cfg "file name" is up to 56 characters (including terminating nul) 
>> >> */
>> >> -#define FW_CFG_MAX_FILE_PATH 56
>> >> -
>> >> -/* fw_cfg file directory entry type */
>> >> -struct fw_cfg_file {
>> >> - u32 size;
>> >> - u16 select;
>> >> - u16 reserved;
>> >> - char name[FW_CFG_MAX_FILE_PATH];
>> >> -};
>> >> -
>> >>  /* fw_cfg device i/o register addresses */
>> >>  static bool fw_cfg_is_mmio;
>> >>  static phys_addr_t fw_cfg_p_base;
>> >> @@ -597,7 +579,7 @@ MODULE_DEVICE_TABLE(of, fw_cfg_sysfs_mmio_match);
>> >>
>> >>  #ifdef CONFIG_ACPI
>> >>  static const struct acpi_device_id fw_cfg_sysfs_acpi_match[] = {
>> >> - { "QEMU0002", },
>> >> + { FW_CFG_ACPI_DEVICE_ID, },
>> >>   {},
>> >>  };
>> >>  MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
>> >> diff --git a/include/uapi/linux/fw_cfg.h b/include/uapi/linux/fw_cfg.h
>> >> new file mode 100644
>> >> index ..5b8136ce46ee
>> >> --- /dev/null
>> >> +++ b/include/uapi/linux/fw_cfg.h
>> >> @@ -0,0 +1,102 @@
>> >> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>> >> +#ifndef _LINUX_FW_CFG_H
>> >> +#define _LINUX_FW_CFG_H
>> >> +
>> >> +#include 
>> >> +
>> >> +#define FW_CFG_ACPI_DEVICE_ID"QEMU0002"
>> >> +
>> >> +/* selector key values for "well-known" fw_cfg entries */
>> >> +#define FW_CFG_SIGNATURE 0x00
>> >> +#define FW_CFG_ID0x01
>> >> +#define FW_CFG_UUI

Re: [PATCH v14 2/9] fw_cfg: add a public uapi header

2018-02-15 Thread Marc-André Lureau
Hi

On Thu, Feb 15, 2018 at 7:20 PM, Michael S. Tsirkin  wrote:
> On Thu, Feb 15, 2018 at 10:25:27AM +0100, Marc-Andre Lureau wrote:
>> Hi
>>
>> On Wed, Feb 14, 2018 at 9:41 PM, Michael S. Tsirkin  wrote:
>> > On Wed, Feb 14, 2018 at 03:18:43PM +0100, Marc-André Lureau wrote:
>> >> Create a common header file for well-known values and structures to be
>> >> shared by the Linux kernel with qemu or other projects.
>> >>
>> >> Suggested-by: Michael S. Tsirkin 
>> >> Signed-off-by: Marc-André Lureau 
>> >>
>> >> ---
>> >>
>> >> The related qemu patch making use of it, to be submitted:
>> >> https://github.com/elmarco/qemu/commit/4884fc9e9c4c4467a371e5a40f3181239e1b70f5
>> >> ---
>> >>  MAINTAINERS|   1 +
>> >>  drivers/firmware/qemu_fw_cfg.c |  22 +
>> >>  include/uapi/linux/fw_cfg.h| 102 
>> >> +
>> >>  3 files changed, 105 insertions(+), 20 deletions(-)
>> >>  create mode 100644 include/uapi/linux/fw_cfg.h
>> >>
>> >> diff --git a/MAINTAINERS b/MAINTAINERS
>> >> index 3bdc260e36b7..a66b65f62811 100644
>> >> --- a/MAINTAINERS
>> >> +++ b/MAINTAINERS
>> >> @@ -11352,6 +11352,7 @@ M:"Michael S. Tsirkin" 
>> >>  L:   qemu-de...@nongnu.org
>> >>  S:   Maintained
>> >>  F:   drivers/firmware/qemu_fw_cfg.c
>> >> +F:   include/uapi/linux/fw_cfg.h
>> >>
>> >>  QIB DRIVER
>> >>  M:   Dennis Dalessandro 
>> >> diff --git a/drivers/firmware/qemu_fw_cfg.c 
>> >> b/drivers/firmware/qemu_fw_cfg.c
>> >> index a41b572eeeb1..90f467232777 100644
>> >> --- a/drivers/firmware/qemu_fw_cfg.c
>> >> +++ b/drivers/firmware/qemu_fw_cfg.c
>> >> @@ -32,30 +32,12 @@
>> >>  #include 
>> >>  #include 
>> >>  #include 
>> >> +#include 
>> >>
>> >>  MODULE_AUTHOR("Gabriel L. Somlo ");
>> >>  MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
>> >>  MODULE_LICENSE("GPL");
>> >>
>> >> -/* selector key values for "well-known" fw_cfg entries */
>> >> -#define FW_CFG_SIGNATURE  0x00
>> >> -#define FW_CFG_ID 0x01
>> >> -#define FW_CFG_FILE_DIR   0x19
>> >> -
>> >> -/* size in bytes of fw_cfg signature */
>> >> -#define FW_CFG_SIG_SIZE 4
>> >> -
>> >> -/* fw_cfg "file name" is up to 56 characters (including terminating nul) 
>> >> */
>> >> -#define FW_CFG_MAX_FILE_PATH 56
>> >> -
>> >> -/* fw_cfg file directory entry type */
>> >> -struct fw_cfg_file {
>> >> - u32 size;
>> >> - u16 select;
>> >> - u16 reserved;
>> >> - char name[FW_CFG_MAX_FILE_PATH];
>> >> -};
>> >> -
>> >>  /* fw_cfg device i/o register addresses */
>> >>  static bool fw_cfg_is_mmio;
>> >>  static phys_addr_t fw_cfg_p_base;
>> >> @@ -597,7 +579,7 @@ MODULE_DEVICE_TABLE(of, fw_cfg_sysfs_mmio_match);
>> >>
>> >>  #ifdef CONFIG_ACPI
>> >>  static const struct acpi_device_id fw_cfg_sysfs_acpi_match[] = {
>> >> - { "QEMU0002", },
>> >> + { FW_CFG_ACPI_DEVICE_ID, },
>> >>   {},
>> >>  };
>> >>  MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
>> >> diff --git a/include/uapi/linux/fw_cfg.h b/include/uapi/linux/fw_cfg.h
>> >> new file mode 100644
>> >> index ..5b8136ce46ee
>> >> --- /dev/null
>> >> +++ b/include/uapi/linux/fw_cfg.h
>> >> @@ -0,0 +1,102 @@
>> >> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>> >> +#ifndef _LINUX_FW_CFG_H
>> >> +#define _LINUX_FW_CFG_H
>> >> +
>> >> +#include 
>> >> +
>> >> +#define FW_CFG_ACPI_DEVICE_ID"QEMU0002"
>> >> +
>> >> +/* selector key values for "well-known" fw_cfg entries */
>> >> +#define FW_CFG_SIGNATURE 0x00
>> >> +#define FW_CFG_ID0x01
>> >> +#define FW_CFG_UUID  0x02
>> >> +#define FW_CFG_RAM_SIZE  0x03
>> >> +#define FW_CFG_NOGRAPHIC 0x04
>> >> +#define FW_CFG_NB_CPUS 

Re: [PATCH v14 8/9] fw_cfg: write vmcoreinfo details

2018-02-15 Thread Marc-André Lureau
Hi

On Thu, Feb 15, 2018 at 7:09 PM, Michael S. Tsirkin <m...@redhat.com> wrote:
> On Wed, Feb 14, 2018 at 03:18:49PM +0100, Marc-André Lureau wrote:
>> If the "etc/vmcoreinfo" fw_cfg file is present and we are not running
>> the kdump kernel, write the addr/size of the vmcoreinfo ELF note.
>>
>> The DMA operation is expected to run synchronously with today qemu,
>> but the specification states that it may become async, so we run
>> "control" field check in a loop for eventual changes.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
>> ---
>>  drivers/firmware/qemu_fw_cfg.c | 144 
>> -
>>  1 file changed, 141 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
>> index 37638b95cb45..69939e2529f2 100644
>> --- a/drivers/firmware/qemu_fw_cfg.c
>> +++ b/drivers/firmware/qemu_fw_cfg.c
>> @@ -34,11 +34,17 @@
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>> +#include 
>> +#include 
>>
>>  MODULE_AUTHOR("Gabriel L. Somlo <so...@cmu.edu>");
>>  MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
>>  MODULE_LICENSE("GPL");
>>
>> +/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
>> +static u32 fw_cfg_rev;
>> +
>>  /* fw_cfg device i/o register addresses */
>>  static bool fw_cfg_is_mmio;
>>  static phys_addr_t fw_cfg_p_base;
>> @@ -59,6 +65,65 @@ static inline u16 fw_cfg_sel_endianness(u16 key)
>>   (u16 __force)cpu_to_le16(key);
>>  }
>>
>> +static inline bool fw_cfg_dma_enabled(void)
>> +{
>> + return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
>> +}
>> +
>> +/* qemu fw_cfg device is sync today, but spec says it may become async */
>> +static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *d)
>> +{
>> + do {
>> + u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
>> +
>> + if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
>> + return;
>> +
>> + usleep_range(50, 100);
>
> I would just do cpu_relax() here.

ok, I didn't know that one.

>
>> + } while (true);
>> +
>> + /* do not reorder the read to d->control */
>> + rmb();
>
> Hmm. I don't really understand the comment.
> Is this code ever reacheable? How does it help?

I thought that's what you suggested in v13 review, but true, I should
replace the return with a break to reach it. Is that what you expect
too? (my understanding is to make sure the READ_ONCE(control) in
wait_for_control happens before READ_ONCE(control) after in
dma_transfer)

>
>> +}
>> +
>> +static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
>> +{
>> + phys_addr_t dma;
>> + struct fw_cfg_dma_access *d = NULL;
>> + ssize_t ret = length;
>> +
>> + d = kmalloc(sizeof(*d), GFP_KERNEL);
>> + if (!d) {
>> + ret = -ENOMEM;
>> + goto end;
>> + }
>> +
>> + /* fw_cfg device does not need IOMMU protection, so use physical 
>> addresses */
>> + *d = (struct fw_cfg_dma_access) {
>> + .address = cpu_to_be64(address ? virt_to_phys(address) : 0),
>> + .length = cpu_to_be32(length),
>> + .control = cpu_to_be32(control)
>> + };
>> +
>> + dma = virt_to_phys(d);
>> +
>> + iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
>> + /* force memory to sync before notifying device via MMIO */
>> + wmb();
>> + iowrite32be(dma, fw_cfg_reg_dma + 4);
>> +
>> + fw_cfg_wait_for_control(d);
>> +
>> + if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
>> + ret = -EIO;
>> + }
>> +
>> +end:
>> + kfree(d);
>> +
>> + return ret;
>> +}
>> +
>>  /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
>>  static inline void fw_cfg_read_blob(u16 key,
>>   void *buf, loff_t pos, size_t count)
>> @@ -87,6 +152,47 @@ static inline void fw_cfg_read_blob(u16 key,
>>   acpi_release_global_lock(glk);
>>  }
>>
>> +#ifdef CONFIG_CRASH_CORE
>> +/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
>> +static ssize_t fw_cfg_write_blob(u16 key,
>> +

Re: [PATCH v14 8/9] fw_cfg: write vmcoreinfo details

2018-02-15 Thread Marc-André Lureau
Hi

On Thu, Feb 15, 2018 at 7:09 PM, Michael S. Tsirkin  wrote:
> On Wed, Feb 14, 2018 at 03:18:49PM +0100, Marc-André Lureau wrote:
>> If the "etc/vmcoreinfo" fw_cfg file is present and we are not running
>> the kdump kernel, write the addr/size of the vmcoreinfo ELF note.
>>
>> The DMA operation is expected to run synchronously with today qemu,
>> but the specification states that it may become async, so we run
>> "control" field check in a loop for eventual changes.
>>
>> Signed-off-by: Marc-André Lureau 
>> ---
>>  drivers/firmware/qemu_fw_cfg.c | 144 
>> -
>>  1 file changed, 141 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
>> index 37638b95cb45..69939e2529f2 100644
>> --- a/drivers/firmware/qemu_fw_cfg.c
>> +++ b/drivers/firmware/qemu_fw_cfg.c
>> @@ -34,11 +34,17 @@
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>> +#include 
>> +#include 
>>
>>  MODULE_AUTHOR("Gabriel L. Somlo ");
>>  MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
>>  MODULE_LICENSE("GPL");
>>
>> +/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
>> +static u32 fw_cfg_rev;
>> +
>>  /* fw_cfg device i/o register addresses */
>>  static bool fw_cfg_is_mmio;
>>  static phys_addr_t fw_cfg_p_base;
>> @@ -59,6 +65,65 @@ static inline u16 fw_cfg_sel_endianness(u16 key)
>>   (u16 __force)cpu_to_le16(key);
>>  }
>>
>> +static inline bool fw_cfg_dma_enabled(void)
>> +{
>> + return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
>> +}
>> +
>> +/* qemu fw_cfg device is sync today, but spec says it may become async */
>> +static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *d)
>> +{
>> + do {
>> + u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
>> +
>> + if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
>> + return;
>> +
>> + usleep_range(50, 100);
>
> I would just do cpu_relax() here.

ok, I didn't know that one.

>
>> + } while (true);
>> +
>> + /* do not reorder the read to d->control */
>> + rmb();
>
> Hmm. I don't really understand the comment.
> Is this code ever reacheable? How does it help?

I thought that's what you suggested in v13 review, but true, I should
replace the return with a break to reach it. Is that what you expect
too? (my understanding is to make sure the READ_ONCE(control) in
wait_for_control happens before READ_ONCE(control) after in
dma_transfer)

>
>> +}
>> +
>> +static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
>> +{
>> + phys_addr_t dma;
>> + struct fw_cfg_dma_access *d = NULL;
>> + ssize_t ret = length;
>> +
>> + d = kmalloc(sizeof(*d), GFP_KERNEL);
>> + if (!d) {
>> + ret = -ENOMEM;
>> + goto end;
>> + }
>> +
>> + /* fw_cfg device does not need IOMMU protection, so use physical 
>> addresses */
>> + *d = (struct fw_cfg_dma_access) {
>> + .address = cpu_to_be64(address ? virt_to_phys(address) : 0),
>> + .length = cpu_to_be32(length),
>> + .control = cpu_to_be32(control)
>> + };
>> +
>> + dma = virt_to_phys(d);
>> +
>> + iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
>> + /* force memory to sync before notifying device via MMIO */
>> + wmb();
>> + iowrite32be(dma, fw_cfg_reg_dma + 4);
>> +
>> + fw_cfg_wait_for_control(d);
>> +
>> + if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
>> + ret = -EIO;
>> + }
>> +
>> +end:
>> + kfree(d);
>> +
>> + return ret;
>> +}
>> +
>>  /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
>>  static inline void fw_cfg_read_blob(u16 key,
>>   void *buf, loff_t pos, size_t count)
>> @@ -87,6 +152,47 @@ static inline void fw_cfg_read_blob(u16 key,
>>   acpi_release_global_lock(glk);
>>  }
>>
>> +#ifdef CONFIG_CRASH_CORE
>> +/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
>> +static ssize_t fw_cfg_write_blob(u16 key,
>> +  void *buf, loff_t pos, size_t count)
>> +{
>> + u3

[PATCH v14 1/9] crash: export paddr_vmcoreinfo_note()

2018-02-14 Thread Marc-André Lureau
The following patch is going to use the symbol from the fw_cfg module,
to call the function and write the note location details in the
vmcoreinfo entry, so qemu can produce dumps with the vmcoreinfo note.

CC: Andrew Morton <a...@linux-foundation.org>
CC: Baoquan He <b...@redhat.com>
CC: Dave Young <dyo...@redhat.com>
CC: Dave Young <dyo...@redhat.com>
CC: Hari Bathini <hbath...@linux.vnet.ibm.com>
CC: Tony Luck <tony.l...@intel.com>
CC: Vivek Goyal <vgo...@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
Acked-by: Gabriel Somlo <so...@cmu.edu>
---
 kernel/crash_core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 4f63597c824d..a93590cdd9e1 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -376,6 +376,7 @@ phys_addr_t __weak paddr_vmcoreinfo_note(void)
 {
return __pa(vmcoreinfo_note);
 }
+EXPORT_SYMBOL(paddr_vmcoreinfo_note);
 
 static int __init crash_save_vmcoreinfo_init(void)
 {
-- 
2.16.1.73.g5832b7e9f2



[PATCH v14 1/9] crash: export paddr_vmcoreinfo_note()

2018-02-14 Thread Marc-André Lureau
The following patch is going to use the symbol from the fw_cfg module,
to call the function and write the note location details in the
vmcoreinfo entry, so qemu can produce dumps with the vmcoreinfo note.

CC: Andrew Morton 
CC: Baoquan He 
CC: Dave Young 
CC: Dave Young 
CC: Hari Bathini 
CC: Tony Luck 
CC: Vivek Goyal 
Signed-off-by: Marc-André Lureau 
Acked-by: Gabriel Somlo 
---
 kernel/crash_core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 4f63597c824d..a93590cdd9e1 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -376,6 +376,7 @@ phys_addr_t __weak paddr_vmcoreinfo_note(void)
 {
return __pa(vmcoreinfo_note);
 }
+EXPORT_SYMBOL(paddr_vmcoreinfo_note);
 
 static int __init crash_save_vmcoreinfo_init(void)
 {
-- 
2.16.1.73.g5832b7e9f2



[PATCH v14 3/9] fw_cfg: fix sparse warnings in fw_cfg_sel_endianness()

2018-02-14 Thread Marc-André Lureau
The function is used for both LE & BE target type, use __force casting.

Fixes:
$ make C=1 CF=-D__CHECK_ENDIAN__ drivers/firmware/qemu_fw_cfg.o

drivers/firmware/qemu_fw_cfg.c:55:33: warning: restricted __be16 degrades to 
integer
drivers/firmware/qemu_fw_cfg.c:55:52: warning: restricted __le16 degrades to 
integer

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 90f467232777..85e693287d87 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -52,7 +52,9 @@ static DEFINE_MUTEX(fw_cfg_dev_lock);
 /* pick appropriate endianness for selector key */
 static inline u16 fw_cfg_sel_endianness(u16 key)
 {
-   return fw_cfg_is_mmio ? cpu_to_be16(key) : cpu_to_le16(key);
+   return fw_cfg_is_mmio ?
+   (u16 __force)cpu_to_be16(key) :
+   (u16 __force)cpu_to_le16(key);
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
-- 
2.16.1.73.g5832b7e9f2



[PATCH v14 3/9] fw_cfg: fix sparse warnings in fw_cfg_sel_endianness()

2018-02-14 Thread Marc-André Lureau
The function is used for both LE & BE target type, use __force casting.

Fixes:
$ make C=1 CF=-D__CHECK_ENDIAN__ drivers/firmware/qemu_fw_cfg.o

drivers/firmware/qemu_fw_cfg.c:55:33: warning: restricted __be16 degrades to 
integer
drivers/firmware/qemu_fw_cfg.c:55:52: warning: restricted __le16 degrades to 
integer

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 90f467232777..85e693287d87 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -52,7 +52,9 @@ static DEFINE_MUTEX(fw_cfg_dev_lock);
 /* pick appropriate endianness for selector key */
 static inline u16 fw_cfg_sel_endianness(u16 key)
 {
-   return fw_cfg_is_mmio ? cpu_to_be16(key) : cpu_to_le16(key);
+   return fw_cfg_is_mmio ?
+   (u16 __force)cpu_to_be16(key) :
+   (u16 __force)cpu_to_le16(key);
 }
 
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
-- 
2.16.1.73.g5832b7e9f2



[PATCH v14 6/9] fw_cfg: fix sparse warnings around FW_CFG_FILE_DIR read

2018-02-14 Thread Marc-André Lureau
Use struct fw_cfg_files to read the directory size, fixing the sparse
warnings:

drivers/firmware/qemu_fw_cfg.c:485:17: warning: cast to restricted __be32

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 4c4813409447..c4c726841ba7 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -478,18 +478,19 @@ static int fw_cfg_register_dir_entries(void)
 {
int ret = 0;
u32 count, i;
+   struct fw_cfg_files files;
struct fw_cfg_file *dir;
size_t dir_size;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, , 0, sizeof(count));
-   count = be32_to_cpu(count);
+   fw_cfg_read_blob(FW_CFG_FILE_DIR, , 0, sizeof(files.count));
+   count = be32_to_cpu(files.count);
dir_size = count * sizeof(struct fw_cfg_file);
 
dir = kmalloc(dir_size, GFP_KERNEL);
if (!dir)
return -ENOMEM;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
+   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files.count), dir_size);
 
for (i = 0; i < count; i++) {
ret = fw_cfg_register_file([i]);
-- 
2.16.1.73.g5832b7e9f2



[PATCH v14 6/9] fw_cfg: fix sparse warnings around FW_CFG_FILE_DIR read

2018-02-14 Thread Marc-André Lureau
Use struct fw_cfg_files to read the directory size, fixing the sparse
warnings:

drivers/firmware/qemu_fw_cfg.c:485:17: warning: cast to restricted __be32

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 4c4813409447..c4c726841ba7 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -478,18 +478,19 @@ static int fw_cfg_register_dir_entries(void)
 {
int ret = 0;
u32 count, i;
+   struct fw_cfg_files files;
struct fw_cfg_file *dir;
size_t dir_size;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, , 0, sizeof(count));
-   count = be32_to_cpu(count);
+   fw_cfg_read_blob(FW_CFG_FILE_DIR, , 0, sizeof(files.count));
+   count = be32_to_cpu(files.count);
dir_size = count * sizeof(struct fw_cfg_file);
 
dir = kmalloc(dir_size, GFP_KERNEL);
if (!dir)
return -ENOMEM;
 
-   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
+   fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files.count), dir_size);
 
for (i = 0; i < count; i++) {
ret = fw_cfg_register_file([i]);
-- 
2.16.1.73.g5832b7e9f2



[PATCH v14 9/9] RFC: fw_cfg: do DMA read operation

2018-02-14 Thread Marc-André Lureau
Modify fw_cfg_read_blob() to use DMA if the device supports it.
Return errors, because the operation may fail.

So far, only one call in fw_cfg_register_dir_entries() is using
kmalloc'ed buf and is thus clearly eligible to DMA read.

Initially, I didn't implement DMA read to speed up boot time, but as a
first step before introducing DMA write (since read operations were
already presents). Even more, I didn't realize fw-cfg entries were
being read by the kernel during boot by default. But actally fw-cfg
entries are being populated during module probe. I knew DMA improved a
lot bios boot time (the main reason the DMA interface was added
afaik). Let see the time it would take to read the whole ACPI
tables (128kb allocated)

 # time cat /sys/firmware/qemu_fw_cfg/by_name/etc/acpi/tables/raw
  - with DMA: sys 0m0.003s
  - without DMA (-global fw_cfg.dma_enabled=off): sys 0m7.674s

FW_CFG_FILE_DIR (0x19) is the only "file" that is read during kernel
boot to populate sysfs qemu_fw_cfg directory, and it is quite
small (1-2kb). Since it does not expose itself, in order to measure
the time it takes to read such small file, I took a comparable sized
file of 2048 bytes and exposed it (-fw_cfg test,file=file with a
modified read_raw enabling DMA)

 # perf stat -r 100 cat /sys/firmware/qemu_fw_cfg/by_name/test/raw >/dev/null
  - with DMA:
  0.636037  task-clock (msec) #0.141 CPUs utilized  
  ( +-  1.19% )
  - without DMA:
  6.430128  task-clock (msec) #0.622 CPUs utilized  
  ( +-  0.22% )

That's a few msec saved during boot by enabling DMA read (the gain
would be more substantial if other & bigger fw-cfg entries are read by
others from sysfs, unfortunately, it's not clear if we can always
enable DMA there)

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 80 ++
 1 file changed, 66 insertions(+), 14 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 69939e2529f2..ba9b907a4399 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -124,12 +124,46 @@ static ssize_t fw_cfg_dma_transfer(void *address, u32 
length, u32 control)
return ret;
 }
 
+/* with acpi & dev locks taken */
+static ssize_t fw_cfg_read_blob_dma(u16 key,
+   void *buf, loff_t pos, size_t count)
+{
+   ssize_t ret;
+
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+   | FW_CFG_DMA_CTL_SELECT
+   | FW_CFG_DMA_CTL_READ);
+   } else {
+   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (ret < 0)
+   return ret;
+   ret = fw_cfg_dma_transfer(buf, count,
+   FW_CFG_DMA_CTL_READ);
+   }
+
+   return ret;
+}
+
+/* with acpi & dev locks taken */
+static void fw_cfg_read_blob_io(u16 key,
+   void *buf, loff_t pos, size_t count)
+{
+   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+   while (pos-- > 0)
+   ioread8(fw_cfg_reg_data);
+   ioread8_rep(fw_cfg_reg_data, buf, count);
+}
+
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
-static inline void fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+static ssize_t fw_cfg_read_blob(u16 key,
+   void *buf, loff_t pos, size_t count,
+   bool dma)
 {
u32 glk = -1U;
acpi_status status;
+   ssize_t ret = count;
 
/* If we have ACPI, ensure mutual exclusion against any potential
 * device access by the firmware, e.g. via AML methods:
@@ -139,17 +173,21 @@ static inline void fw_cfg_read_blob(u16 key,
/* Should never get here */
WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
memset(buf, 0, count);
-   return;
+   return -EINVAL;
}
 
mutex_lock(_cfg_dev_lock);
-   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
-   while (pos-- > 0)
-   ioread8(fw_cfg_reg_data);
-   ioread8_rep(fw_cfg_reg_data, buf, count);
+   if (dma && fw_cfg_dma_enabled()) {
+   ret = fw_cfg_read_blob_dma(key, buf, pos, count);
+   } else {
+   fw_cfg_read_blob_io(key, buf, pos, count);
+   }
+
mutex_unlock(_cfg_dev_lock);
 
acpi_release_global_lock(glk);
+
+   return ret;
 }
 
 #ifdef CONFIG_CRASH_CORE
@@ -282,8 +320,9 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
 #endif
 
 

[PATCH v14 8/9] fw_cfg: write vmcoreinfo details

2018-02-14 Thread Marc-André Lureau
If the "etc/vmcoreinfo" fw_cfg file is present and we are not running
the kdump kernel, write the addr/size of the vmcoreinfo ELF note.

The DMA operation is expected to run synchronously with today qemu,
but the specification states that it may become async, so we run
"control" field check in a loop for eventual changes.

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 144 -
 1 file changed, 141 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 37638b95cb45..69939e2529f2 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -34,11 +34,17 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo <so...@cmu.edu>");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
 MODULE_LICENSE("GPL");
 
+/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
+static u32 fw_cfg_rev;
+
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -59,6 +65,65 @@ static inline u16 fw_cfg_sel_endianness(u16 key)
(u16 __force)cpu_to_le16(key);
 }
 
+static inline bool fw_cfg_dma_enabled(void)
+{
+   return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
+}
+
+/* qemu fw_cfg device is sync today, but spec says it may become async */
+static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *d)
+{
+   do {
+   u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
+
+   if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
+   return;
+
+   usleep_range(50, 100);
+   } while (true);
+
+   /* do not reorder the read to d->control */
+   rmb();
+}
+
+static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
+{
+   phys_addr_t dma;
+   struct fw_cfg_dma_access *d = NULL;
+   ssize_t ret = length;
+
+   d = kmalloc(sizeof(*d), GFP_KERNEL);
+   if (!d) {
+   ret = -ENOMEM;
+   goto end;
+   }
+
+   /* fw_cfg device does not need IOMMU protection, so use physical 
addresses */
+   *d = (struct fw_cfg_dma_access) {
+   .address = cpu_to_be64(address ? virt_to_phys(address) : 0),
+   .length = cpu_to_be32(length),
+   .control = cpu_to_be32(control)
+   };
+
+   dma = virt_to_phys(d);
+
+   iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
+   /* force memory to sync before notifying device via MMIO */
+   wmb();
+   iowrite32be(dma, fw_cfg_reg_dma + 4);
+
+   fw_cfg_wait_for_control(d);
+
+   if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
+   ret = -EIO;
+   }
+
+end:
+   kfree(d);
+
+   return ret;
+}
+
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
 static inline void fw_cfg_read_blob(u16 key,
void *buf, loff_t pos, size_t count)
@@ -87,6 +152,47 @@ static inline void fw_cfg_read_blob(u16 key,
acpi_release_global_lock(glk);
 }
 
+#ifdef CONFIG_CRASH_CORE
+/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
+static ssize_t fw_cfg_write_blob(u16 key,
+void *buf, loff_t pos, size_t count)
+{
+   u32 glk = -1U;
+   acpi_status status;
+   ssize_t ret = count;
+
+   /* If we have ACPI, ensure mutual exclusion against any potential
+* device access by the firmware, e.g. via AML methods:
+*/
+   status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
+   if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
+   /* Should never get here */
+   WARN(1, "%s: Failed to lock ACPI!\n", __func__);
+   return -EINVAL;
+   }
+
+   mutex_lock(_cfg_dev_lock);
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+ | FW_CFG_DMA_CTL_SELECT
+ | FW_CFG_DMA_CTL_WRITE);
+   } else {
+   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (ret < 0)
+   goto end;
+   ret = fw_cfg_dma_transfer(buf, count, FW_CFG_DMA_CTL_WRITE);
+   }
+
+end:
+   mutex_unlock(_cfg_dev_lock);
+
+   acpi_release_global_lock(glk);
+
+   return ret;
+}
+#endif /* CONFIG_CRASH_CORE */
+
 /* clean up fw_cfg device i/o */
 static void fw_cfg_io_cleanup(void)
 {
@@ -185,9 +291,6 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
return 0;
 }
 
-/* fw_cfg revision attribute, in /sys/firmware/qemu_fw

[PATCH v14 8/9] fw_cfg: write vmcoreinfo details

2018-02-14 Thread Marc-André Lureau
If the "etc/vmcoreinfo" fw_cfg file is present and we are not running
the kdump kernel, write the addr/size of the vmcoreinfo ELF note.

The DMA operation is expected to run synchronously with today qemu,
but the specification states that it may become async, so we run
"control" field check in a loop for eventual changes.

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 144 -
 1 file changed, 141 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 37638b95cb45..69939e2529f2 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -34,11 +34,17 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo ");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
 MODULE_LICENSE("GPL");
 
+/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
+static u32 fw_cfg_rev;
+
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -59,6 +65,65 @@ static inline u16 fw_cfg_sel_endianness(u16 key)
(u16 __force)cpu_to_le16(key);
 }
 
+static inline bool fw_cfg_dma_enabled(void)
+{
+   return (fw_cfg_rev & FW_CFG_VERSION_DMA) && fw_cfg_reg_dma;
+}
+
+/* qemu fw_cfg device is sync today, but spec says it may become async */
+static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *d)
+{
+   do {
+   u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
+
+   if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
+   return;
+
+   usleep_range(50, 100);
+   } while (true);
+
+   /* do not reorder the read to d->control */
+   rmb();
+}
+
+static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
+{
+   phys_addr_t dma;
+   struct fw_cfg_dma_access *d = NULL;
+   ssize_t ret = length;
+
+   d = kmalloc(sizeof(*d), GFP_KERNEL);
+   if (!d) {
+   ret = -ENOMEM;
+   goto end;
+   }
+
+   /* fw_cfg device does not need IOMMU protection, so use physical 
addresses */
+   *d = (struct fw_cfg_dma_access) {
+   .address = cpu_to_be64(address ? virt_to_phys(address) : 0),
+   .length = cpu_to_be32(length),
+   .control = cpu_to_be32(control)
+   };
+
+   dma = virt_to_phys(d);
+
+   iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
+   /* force memory to sync before notifying device via MMIO */
+   wmb();
+   iowrite32be(dma, fw_cfg_reg_dma + 4);
+
+   fw_cfg_wait_for_control(d);
+
+   if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
+   ret = -EIO;
+   }
+
+end:
+   kfree(d);
+
+   return ret;
+}
+
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
 static inline void fw_cfg_read_blob(u16 key,
void *buf, loff_t pos, size_t count)
@@ -87,6 +152,47 @@ static inline void fw_cfg_read_blob(u16 key,
acpi_release_global_lock(glk);
 }
 
+#ifdef CONFIG_CRASH_CORE
+/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
+static ssize_t fw_cfg_write_blob(u16 key,
+void *buf, loff_t pos, size_t count)
+{
+   u32 glk = -1U;
+   acpi_status status;
+   ssize_t ret = count;
+
+   /* If we have ACPI, ensure mutual exclusion against any potential
+* device access by the firmware, e.g. via AML methods:
+*/
+   status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
+   if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
+   /* Should never get here */
+   WARN(1, "%s: Failed to lock ACPI!\n", __func__);
+   return -EINVAL;
+   }
+
+   mutex_lock(_cfg_dev_lock);
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+ | FW_CFG_DMA_CTL_SELECT
+ | FW_CFG_DMA_CTL_WRITE);
+   } else {
+   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (ret < 0)
+   goto end;
+   ret = fw_cfg_dma_transfer(buf, count, FW_CFG_DMA_CTL_WRITE);
+   }
+
+end:
+   mutex_unlock(_cfg_dev_lock);
+
+   acpi_release_global_lock(glk);
+
+   return ret;
+}
+#endif /* CONFIG_CRASH_CORE */
+
 /* clean up fw_cfg device i/o */
 static void fw_cfg_io_cleanup(void)
 {
@@ -185,9 +291,6 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
return 0;
 }
 
-/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
-static u32 fw_cfg_rev;
-
 static

[PATCH v14 9/9] RFC: fw_cfg: do DMA read operation

2018-02-14 Thread Marc-André Lureau
Modify fw_cfg_read_blob() to use DMA if the device supports it.
Return errors, because the operation may fail.

So far, only one call in fw_cfg_register_dir_entries() is using
kmalloc'ed buf and is thus clearly eligible to DMA read.

Initially, I didn't implement DMA read to speed up boot time, but as a
first step before introducing DMA write (since read operations were
already presents). Even more, I didn't realize fw-cfg entries were
being read by the kernel during boot by default. But actally fw-cfg
entries are being populated during module probe. I knew DMA improved a
lot bios boot time (the main reason the DMA interface was added
afaik). Let see the time it would take to read the whole ACPI
tables (128kb allocated)

 # time cat /sys/firmware/qemu_fw_cfg/by_name/etc/acpi/tables/raw
  - with DMA: sys 0m0.003s
  - without DMA (-global fw_cfg.dma_enabled=off): sys 0m7.674s

FW_CFG_FILE_DIR (0x19) is the only "file" that is read during kernel
boot to populate sysfs qemu_fw_cfg directory, and it is quite
small (1-2kb). Since it does not expose itself, in order to measure
the time it takes to read such small file, I took a comparable sized
file of 2048 bytes and exposed it (-fw_cfg test,file=file with a
modified read_raw enabling DMA)

 # perf stat -r 100 cat /sys/firmware/qemu_fw_cfg/by_name/test/raw >/dev/null
  - with DMA:
  0.636037  task-clock (msec) #0.141 CPUs utilized  
  ( +-  1.19% )
  - without DMA:
  6.430128  task-clock (msec) #0.622 CPUs utilized  
  ( +-  0.22% )

That's a few msec saved during boot by enabling DMA read (the gain
would be more substantial if other & bigger fw-cfg entries are read by
others from sysfs, unfortunately, it's not clear if we can always
enable DMA there)

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 80 ++
 1 file changed, 66 insertions(+), 14 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 69939e2529f2..ba9b907a4399 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -124,12 +124,46 @@ static ssize_t fw_cfg_dma_transfer(void *address, u32 
length, u32 control)
return ret;
 }
 
+/* with acpi & dev locks taken */
+static ssize_t fw_cfg_read_blob_dma(u16 key,
+   void *buf, loff_t pos, size_t count)
+{
+   ssize_t ret;
+
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+   | FW_CFG_DMA_CTL_SELECT
+   | FW_CFG_DMA_CTL_READ);
+   } else {
+   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (ret < 0)
+   return ret;
+   ret = fw_cfg_dma_transfer(buf, count,
+   FW_CFG_DMA_CTL_READ);
+   }
+
+   return ret;
+}
+
+/* with acpi & dev locks taken */
+static void fw_cfg_read_blob_io(u16 key,
+   void *buf, loff_t pos, size_t count)
+{
+   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+   while (pos-- > 0)
+   ioread8(fw_cfg_reg_data);
+   ioread8_rep(fw_cfg_reg_data, buf, count);
+}
+
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
-static inline void fw_cfg_read_blob(u16 key,
-   void *buf, loff_t pos, size_t count)
+static ssize_t fw_cfg_read_blob(u16 key,
+   void *buf, loff_t pos, size_t count,
+   bool dma)
 {
u32 glk = -1U;
acpi_status status;
+   ssize_t ret = count;
 
/* If we have ACPI, ensure mutual exclusion against any potential
 * device access by the firmware, e.g. via AML methods:
@@ -139,17 +173,21 @@ static inline void fw_cfg_read_blob(u16 key,
/* Should never get here */
WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
memset(buf, 0, count);
-   return;
+   return -EINVAL;
}
 
mutex_lock(_cfg_dev_lock);
-   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
-   while (pos-- > 0)
-   ioread8(fw_cfg_reg_data);
-   ioread8_rep(fw_cfg_reg_data, buf, count);
+   if (dma && fw_cfg_dma_enabled()) {
+   ret = fw_cfg_read_blob_dma(key, buf, pos, count);
+   } else {
+   fw_cfg_read_blob_io(key, buf, pos, count);
+   }
+
mutex_unlock(_cfg_dev_lock);
 
acpi_release_global_lock(glk);
+
+   return ret;
 }
 
 #ifdef CONFIG_CRASH_CORE
@@ -282,8 +320,9 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
 #endif
 
/* verify fw_cfg device signature */
-   

[PATCH v14 7/9] fw_cfg: add DMA register

2018-02-14 Thread Marc-André Lureau
Add an optional  kernel module (or command line) parameter
using the following syntax:

  [qemu_fw_cfg.]ioport=@[::[:]]
 or
  [qemu_fw_cfg.]mmio=@[::[:]]

and initializes the register address using given or default offset.

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
Reviewed-by: Gabriel Somlo <so...@cmu.edu>
---
 drivers/firmware/qemu_fw_cfg.c | 53 --
 1 file changed, 41 insertions(+), 12 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index c4c726841ba7..37638b95cb45 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -10,20 +10,21 @@
  * and select subsets of aarch64), a Device Tree node (on arm), or using
  * a kernel module (or command line) parameter with the following syntax:
  *
- *  [qemu_fw_cfg.]ioport=@[::]
+ *  [qemu_fw_cfg.]ioport=@[::[:]]
  * or
- *  [qemu_fw_cfg.]mmio=@[::]
+ *  [qemu_fw_cfg.]mmio=@[::[:]]
  *
  * where:
  *   := size of ioport or mmio range
  *   := physical base address of ioport or mmio range
  *   := (optional) offset of control register
  *   := (optional) offset of data register
+ *   := (optional) offset of dma register
  *
  * e.g.:
- *  qemu_fw_cfg.ioport=2@0x510:0:1 (the default on x86)
+ *  qemu_fw_cfg.ioport=12@0x510:0:1:4  (the default on x86)
  * or
- *  qemu_fw_cfg.mmio=0xA@0x902:8:0 (the default on arm)
+ *  qemu_fw_cfg.mmio=16@0x902:8:0:16   (the default on arm)
  */
 
 #include 
@@ -45,6 +46,7 @@ static resource_size_t fw_cfg_p_size;
 static void __iomem *fw_cfg_dev_base;
 static void __iomem *fw_cfg_reg_ctrl;
 static void __iomem *fw_cfg_reg_data;
+static void __iomem *fw_cfg_reg_dma;
 
 /* atomic access to fw_cfg device (potentially slow i/o, so using mutex) */
 static DEFINE_MUTEX(fw_cfg_dev_lock);
@@ -102,12 +104,14 @@ static void fw_cfg_io_cleanup(void)
 # if (defined(CONFIG_ARM) || defined(CONFIG_ARM64))
 #  define FW_CFG_CTRL_OFF 0x08
 #  define FW_CFG_DATA_OFF 0x00
+#  define FW_CFG_DMA_OFF 0x10
 # elif (defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC32)) /* ppc/mac,sun4m 
*/
 #  define FW_CFG_CTRL_OFF 0x00
 #  define FW_CFG_DATA_OFF 0x02
 # elif (defined(CONFIG_X86) || defined(CONFIG_SPARC64)) /* x86, sun4u */
 #  define FW_CFG_CTRL_OFF 0x00
 #  define FW_CFG_DATA_OFF 0x01
+#  define FW_CFG_DMA_OFF 0x04
 # else
 #  error "QEMU FW_CFG not available on this architecture!"
 # endif
@@ -117,7 +121,7 @@ static void fw_cfg_io_cleanup(void)
 static int fw_cfg_do_platform_probe(struct platform_device *pdev)
 {
char sig[FW_CFG_SIG_SIZE];
-   struct resource *range, *ctrl, *data;
+   struct resource *range, *ctrl, *data, *dma;
 
/* acquire i/o range details */
fw_cfg_is_mmio = false;
@@ -154,6 +158,7 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
/* were custom register offsets provided (e.g. on the command line)? */
ctrl = platform_get_resource_byname(pdev, IORESOURCE_REG, "ctrl");
data = platform_get_resource_byname(pdev, IORESOURCE_REG, "data");
+   dma = platform_get_resource_byname(pdev, IORESOURCE_REG, "dma");
if (ctrl && data) {
fw_cfg_reg_ctrl = fw_cfg_dev_base + ctrl->start;
fw_cfg_reg_data = fw_cfg_dev_base + data->start;
@@ -163,6 +168,13 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
fw_cfg_reg_data = fw_cfg_dev_base + FW_CFG_DATA_OFF;
}
 
+   if (dma)
+   fw_cfg_reg_dma = fw_cfg_dev_base + dma->start;
+#ifdef FW_CFG_DMA_OFF
+   else
+   fw_cfg_reg_dma = fw_cfg_dev_base + FW_CFG_DMA_OFF;
+#endif
+
/* verify fw_cfg device signature */
fw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE);
if (memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
@@ -617,6 +629,7 @@ static struct platform_device *fw_cfg_cmdline_dev;
 /* use special scanf/printf modifier for phys_addr_t, resource_size_t */
 #define PH_ADDR_SCAN_FMT "@%" __PHYS_ADDR_PREFIX "i%n" \
 ":%" __PHYS_ADDR_PREFIX "i" \
+":%" __PHYS_ADDR_PREFIX "i%n" \
 ":%" __PHYS_ADDR_PREFIX "i%n"
 
 #define PH_ADDR_PR_1_FMT "0x%" __PHYS_ADDR_PREFIX "x@" \
@@ -626,12 +639,15 @@ static struct platform_device *fw_cfg_cmdline_dev;
 ":%" __PHYS_ADDR_PREFIX "u" \
 ":%" __PHYS_ADDR_PREFIX "u"
 
+#define PH_ADDR_PR_4_FMT PH_ADDR_PR_3_FMT \
+":%" __PHYS_ADDR_PREFIX "u"
+
 static int fw_cfg_cmdline_set(const char *arg, const struct kernel_param *kp)
 {
-   struct resource res[3] = {};
+ 

[PATCH v14 5/9] fw_cfg: fix sparse warning reading FW_CFG_ID

2018-02-14 Thread Marc-André Lureau
Use a restricted type for reading FW_CFG_ID, fixing sparse warning:

drivers/firmware/qemu_fw_cfg.c:540:22: warning: cast to restricted __le32

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 8ad19086e5c5..4c4813409447 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -511,6 +511,7 @@ static inline void fw_cfg_kobj_cleanup(struct kobject *kobj)
 static int fw_cfg_sysfs_probe(struct platform_device *pdev)
 {
int err;
+   __le32 rev;
 
/* NOTE: If we supported multiple fw_cfg devices, we'd first create
 * a subdirectory named after e.g. pdev->id, then hang per-device
@@ -536,8 +537,8 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)
goto err_probe;
 
/* get revision number, add matching top-level attribute */
-   fw_cfg_read_blob(FW_CFG_ID, _cfg_rev, 0, sizeof(fw_cfg_rev));
-   fw_cfg_rev = le32_to_cpu(fw_cfg_rev);
+   fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   fw_cfg_rev = le32_to_cpu(rev);
err = sysfs_create_file(fw_cfg_top_ko, _cfg_rev_attr.attr);
if (err)
goto err_rev;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v14 7/9] fw_cfg: add DMA register

2018-02-14 Thread Marc-André Lureau
Add an optional  kernel module (or command line) parameter
using the following syntax:

  [qemu_fw_cfg.]ioport=@[::[:]]
 or
  [qemu_fw_cfg.]mmio=@[::[:]]

and initializes the register address using given or default offset.

Signed-off-by: Marc-André Lureau 
Reviewed-by: Gabriel Somlo 
---
 drivers/firmware/qemu_fw_cfg.c | 53 --
 1 file changed, 41 insertions(+), 12 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index c4c726841ba7..37638b95cb45 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -10,20 +10,21 @@
  * and select subsets of aarch64), a Device Tree node (on arm), or using
  * a kernel module (or command line) parameter with the following syntax:
  *
- *  [qemu_fw_cfg.]ioport=@[::]
+ *  [qemu_fw_cfg.]ioport=@[::[:]]
  * or
- *  [qemu_fw_cfg.]mmio=@[::]
+ *  [qemu_fw_cfg.]mmio=@[::[:]]
  *
  * where:
  *   := size of ioport or mmio range
  *   := physical base address of ioport or mmio range
  *   := (optional) offset of control register
  *   := (optional) offset of data register
+ *   := (optional) offset of dma register
  *
  * e.g.:
- *  qemu_fw_cfg.ioport=2@0x510:0:1 (the default on x86)
+ *  qemu_fw_cfg.ioport=12@0x510:0:1:4  (the default on x86)
  * or
- *  qemu_fw_cfg.mmio=0xA@0x902:8:0 (the default on arm)
+ *  qemu_fw_cfg.mmio=16@0x902:8:0:16   (the default on arm)
  */
 
 #include 
@@ -45,6 +46,7 @@ static resource_size_t fw_cfg_p_size;
 static void __iomem *fw_cfg_dev_base;
 static void __iomem *fw_cfg_reg_ctrl;
 static void __iomem *fw_cfg_reg_data;
+static void __iomem *fw_cfg_reg_dma;
 
 /* atomic access to fw_cfg device (potentially slow i/o, so using mutex) */
 static DEFINE_MUTEX(fw_cfg_dev_lock);
@@ -102,12 +104,14 @@ static void fw_cfg_io_cleanup(void)
 # if (defined(CONFIG_ARM) || defined(CONFIG_ARM64))
 #  define FW_CFG_CTRL_OFF 0x08
 #  define FW_CFG_DATA_OFF 0x00
+#  define FW_CFG_DMA_OFF 0x10
 # elif (defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC32)) /* ppc/mac,sun4m 
*/
 #  define FW_CFG_CTRL_OFF 0x00
 #  define FW_CFG_DATA_OFF 0x02
 # elif (defined(CONFIG_X86) || defined(CONFIG_SPARC64)) /* x86, sun4u */
 #  define FW_CFG_CTRL_OFF 0x00
 #  define FW_CFG_DATA_OFF 0x01
+#  define FW_CFG_DMA_OFF 0x04
 # else
 #  error "QEMU FW_CFG not available on this architecture!"
 # endif
@@ -117,7 +121,7 @@ static void fw_cfg_io_cleanup(void)
 static int fw_cfg_do_platform_probe(struct platform_device *pdev)
 {
char sig[FW_CFG_SIG_SIZE];
-   struct resource *range, *ctrl, *data;
+   struct resource *range, *ctrl, *data, *dma;
 
/* acquire i/o range details */
fw_cfg_is_mmio = false;
@@ -154,6 +158,7 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
/* were custom register offsets provided (e.g. on the command line)? */
ctrl = platform_get_resource_byname(pdev, IORESOURCE_REG, "ctrl");
data = platform_get_resource_byname(pdev, IORESOURCE_REG, "data");
+   dma = platform_get_resource_byname(pdev, IORESOURCE_REG, "dma");
if (ctrl && data) {
fw_cfg_reg_ctrl = fw_cfg_dev_base + ctrl->start;
fw_cfg_reg_data = fw_cfg_dev_base + data->start;
@@ -163,6 +168,13 @@ static int fw_cfg_do_platform_probe(struct platform_device 
*pdev)
fw_cfg_reg_data = fw_cfg_dev_base + FW_CFG_DATA_OFF;
}
 
+   if (dma)
+   fw_cfg_reg_dma = fw_cfg_dev_base + dma->start;
+#ifdef FW_CFG_DMA_OFF
+   else
+   fw_cfg_reg_dma = fw_cfg_dev_base + FW_CFG_DMA_OFF;
+#endif
+
/* verify fw_cfg device signature */
fw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE);
if (memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
@@ -617,6 +629,7 @@ static struct platform_device *fw_cfg_cmdline_dev;
 /* use special scanf/printf modifier for phys_addr_t, resource_size_t */
 #define PH_ADDR_SCAN_FMT "@%" __PHYS_ADDR_PREFIX "i%n" \
 ":%" __PHYS_ADDR_PREFIX "i" \
+":%" __PHYS_ADDR_PREFIX "i%n" \
 ":%" __PHYS_ADDR_PREFIX "i%n"
 
 #define PH_ADDR_PR_1_FMT "0x%" __PHYS_ADDR_PREFIX "x@" \
@@ -626,12 +639,15 @@ static struct platform_device *fw_cfg_cmdline_dev;
 ":%" __PHYS_ADDR_PREFIX "u" \
 ":%" __PHYS_ADDR_PREFIX "u"
 
+#define PH_ADDR_PR_4_FMT PH_ADDR_PR_3_FMT \
+":%" __PHYS_ADDR_PREFIX "u"
+
 static int fw_cfg_cmdline_set(const char *arg, const struct kernel_param *kp)
 {
-   struct resource res[3] = {};
+   struct resource res[4] = {};
char *str;
  

[PATCH v14 5/9] fw_cfg: fix sparse warning reading FW_CFG_ID

2018-02-14 Thread Marc-André Lureau
Use a restricted type for reading FW_CFG_ID, fixing sparse warning:

drivers/firmware/qemu_fw_cfg.c:540:22: warning: cast to restricted __le32

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 8ad19086e5c5..4c4813409447 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -511,6 +511,7 @@ static inline void fw_cfg_kobj_cleanup(struct kobject *kobj)
 static int fw_cfg_sysfs_probe(struct platform_device *pdev)
 {
int err;
+   __le32 rev;
 
/* NOTE: If we supported multiple fw_cfg devices, we'd first create
 * a subdirectory named after e.g. pdev->id, then hang per-device
@@ -536,8 +537,8 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)
goto err_probe;
 
/* get revision number, add matching top-level attribute */
-   fw_cfg_read_blob(FW_CFG_ID, _cfg_rev, 0, sizeof(fw_cfg_rev));
-   fw_cfg_rev = le32_to_cpu(fw_cfg_rev);
+   fw_cfg_read_blob(FW_CFG_ID, , 0, sizeof(rev));
+   fw_cfg_rev = le32_to_cpu(rev);
err = sysfs_create_file(fw_cfg_top_ko, _cfg_rev_attr.attr);
if (err)
goto err_rev;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v14 0/9] fw_cfg: add DMA operations & etc/vmcoreinfo support

2018-02-14 Thread Marc-André Lureau
Hi,

This series adds DMA operations support to the qemu fw_cfg kernel
module and populates "etc/vmcoreinfo" with vmcoreinfo location
details (entry added since qemu 2.11 with -device vmcoreinfo).

v14:
- add "fw_cfg: add a public uapi header"
- fix sparse warnings & don't introduce new warnings
- add memory barriers to force IO ordering
- split fw_cfg_read_blob() in fw_cfg_read_blob_io() and
  fw_cfg_read_blob_dma()
- add error handling to fw_cfg_read_blob() callers
- minor stylistic changes

v13:
- reorder patch series, introduce DMA write before DMA read
- do some measurements of DMA read speed-ups

v12:
- fix virt_to_phys(NULL) panic with CONFIG_DEBUG_VIRTUAL=y
- do not use DMA read, except for kmalloc() memory we allocated
  ourself (only fw_cfg_register_dir_entries() so far)

v11:
- add #include  in last patch,
  fixing kbuild .config test

Marc-André Lureau (9):
  crash: export paddr_vmcoreinfo_note()
  fw_cfg: add a public uapi header
  fw_cfg: fix sparse warnings in fw_cfg_sel_endianness()
  fw_cfg: fix sparse warnings with fw_cfg_file
  fw_cfg: fix sparse warning reading FW_CFG_ID
  fw_cfg: fix sparse warnings around FW_CFG_FILE_DIR read
  fw_cfg: add DMA register
  fw_cfg: write vmcoreinfo details
  RFC: fw_cfg: do DMA read operation

 MAINTAINERS|   1 +
 drivers/firmware/qemu_fw_cfg.c | 333 +
 include/uapi/linux/fw_cfg.h| 102 +
 kernel/crash_core.c|   1 +
 4 files changed, 374 insertions(+), 63 deletions(-)
 create mode 100644 include/uapi/linux/fw_cfg.h

-- 
2.16.1.73.g5832b7e9f2



[PATCH v14 4/9] fw_cfg: fix sparse warnings with fw_cfg_file

2018-02-14 Thread Marc-André Lureau
Modify fw_cfg_sysfs_entry to store entry values, instead of reusing
the restricted types.

Fixes warnings such as:

$ make C=1 CF=-D__CHECK_ENDIAN__ drivers/firmware/qemu_fw_cfg.o

drivers/firmware/qemu_fw_cfg.c:491:29: warning: incorrect type in assignment 
(different base types)
drivers/firmware/qemu_fw_cfg.c:491:29:expected restricted __be32 [usertype] 
size
drivers/firmware/qemu_fw_cfg.c:491:29:got unsigned int
drivers/firmware/qemu_fw_cfg.c:492:31: warning: incorrect type in assignment 
(different base types)
drivers/firmware/qemu_fw_cfg.c:492:31:expected restricted __be16 [usertype] 
select
drivers/firmware/qemu_fw_cfg.c:492:31:got int

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 28 +++-
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 85e693287d87..8ad19086e5c5 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -192,7 +192,9 @@ static const struct {
 /* fw_cfg_sysfs_entry type */
 struct fw_cfg_sysfs_entry {
struct kobject kobj;
-   struct fw_cfg_file f;
+   u32 size;
+   u16 select;
+   char name[FW_CFG_MAX_FILE_PATH];
struct list_head list;
 };
 
@@ -256,17 +258,17 @@ struct fw_cfg_sysfs_attribute fw_cfg_sysfs_attr_##_attr = 
{ \
 
 static ssize_t fw_cfg_sysfs_show_size(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%u\n", e->f.size);
+   return sprintf(buf, "%u\n", e->size);
 }
 
 static ssize_t fw_cfg_sysfs_show_key(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%u\n", e->f.select);
+   return sprintf(buf, "%u\n", e->select);
 }
 
 static ssize_t fw_cfg_sysfs_show_name(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%s\n", e->f.name);
+   return sprintf(buf, "%s\n", e->name);
 }
 
 static FW_CFG_SYSFS_ATTR(size);
@@ -317,13 +319,13 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, 
struct kobject *kobj,
 {
struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
 
-   if (pos > entry->f.size)
+   if (pos > entry->size)
return -EINVAL;
 
-   if (count > entry->f.size - pos)
-   count = entry->f.size - pos;
+   if (count > entry->size - pos)
+   count = entry->size - pos;
 
-   fw_cfg_read_blob(entry->f.select, buf, pos, count);
+   fw_cfg_read_blob(entry->select, buf, pos, count);
return count;
 }
 
@@ -442,11 +444,13 @@ static int fw_cfg_register_file(const struct fw_cfg_file 
*f)
return -ENOMEM;
 
/* set file entry information */
-   memcpy(>f, f, sizeof(struct fw_cfg_file));
+   entry->size = be32_to_cpu(f->size);
+   entry->select = be16_to_cpu(f->select);
+   memcpy(entry->name, f->name, FW_CFG_MAX_FILE_PATH);
 
/* register entry under "/sys/firmware/qemu_fw_cfg/by_key/" */
err = kobject_init_and_add(>kobj, _cfg_sysfs_entry_ktype,
-  fw_cfg_sel_ko, "%d", entry->f.select);
+  fw_cfg_sel_ko, "%d", entry->select);
if (err)
goto err_register;
 
@@ -456,7 +460,7 @@ static int fw_cfg_register_file(const struct fw_cfg_file *f)
goto err_add_raw;
 
/* try adding "/sys/firmware/qemu_fw_cfg/by_name/" symlink */
-   fw_cfg_build_symlink(fw_cfg_fname_kset, >kobj, entry->f.name);
+   fw_cfg_build_symlink(fw_cfg_fname_kset, >kobj, entry->name);
 
/* success, add entry to global cache */
fw_cfg_sysfs_cache_enlist(entry);
@@ -488,8 +492,6 @@ static int fw_cfg_register_dir_entries(void)
fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
 
for (i = 0; i < count; i++) {
-   dir[i].size = be32_to_cpu(dir[i].size);
-   dir[i].select = be16_to_cpu(dir[i].select);
ret = fw_cfg_register_file([i]);
if (ret)
break;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v14 0/9] fw_cfg: add DMA operations & etc/vmcoreinfo support

2018-02-14 Thread Marc-André Lureau
Hi,

This series adds DMA operations support to the qemu fw_cfg kernel
module and populates "etc/vmcoreinfo" with vmcoreinfo location
details (entry added since qemu 2.11 with -device vmcoreinfo).

v14:
- add "fw_cfg: add a public uapi header"
- fix sparse warnings & don't introduce new warnings
- add memory barriers to force IO ordering
- split fw_cfg_read_blob() in fw_cfg_read_blob_io() and
  fw_cfg_read_blob_dma()
- add error handling to fw_cfg_read_blob() callers
- minor stylistic changes

v13:
- reorder patch series, introduce DMA write before DMA read
- do some measurements of DMA read speed-ups

v12:
- fix virt_to_phys(NULL) panic with CONFIG_DEBUG_VIRTUAL=y
- do not use DMA read, except for kmalloc() memory we allocated
  ourself (only fw_cfg_register_dir_entries() so far)

v11:
- add #include  in last patch,
  fixing kbuild .config test

Marc-André Lureau (9):
  crash: export paddr_vmcoreinfo_note()
  fw_cfg: add a public uapi header
  fw_cfg: fix sparse warnings in fw_cfg_sel_endianness()
  fw_cfg: fix sparse warnings with fw_cfg_file
  fw_cfg: fix sparse warning reading FW_CFG_ID
  fw_cfg: fix sparse warnings around FW_CFG_FILE_DIR read
  fw_cfg: add DMA register
  fw_cfg: write vmcoreinfo details
  RFC: fw_cfg: do DMA read operation

 MAINTAINERS|   1 +
 drivers/firmware/qemu_fw_cfg.c | 333 +
 include/uapi/linux/fw_cfg.h| 102 +
 kernel/crash_core.c|   1 +
 4 files changed, 374 insertions(+), 63 deletions(-)
 create mode 100644 include/uapi/linux/fw_cfg.h

-- 
2.16.1.73.g5832b7e9f2



[PATCH v14 4/9] fw_cfg: fix sparse warnings with fw_cfg_file

2018-02-14 Thread Marc-André Lureau
Modify fw_cfg_sysfs_entry to store entry values, instead of reusing
the restricted types.

Fixes warnings such as:

$ make C=1 CF=-D__CHECK_ENDIAN__ drivers/firmware/qemu_fw_cfg.o

drivers/firmware/qemu_fw_cfg.c:491:29: warning: incorrect type in assignment 
(different base types)
drivers/firmware/qemu_fw_cfg.c:491:29:expected restricted __be32 [usertype] 
size
drivers/firmware/qemu_fw_cfg.c:491:29:got unsigned int
drivers/firmware/qemu_fw_cfg.c:492:31: warning: incorrect type in assignment 
(different base types)
drivers/firmware/qemu_fw_cfg.c:492:31:expected restricted __be16 [usertype] 
select
drivers/firmware/qemu_fw_cfg.c:492:31:got int

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 28 +++-
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 85e693287d87..8ad19086e5c5 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -192,7 +192,9 @@ static const struct {
 /* fw_cfg_sysfs_entry type */
 struct fw_cfg_sysfs_entry {
struct kobject kobj;
-   struct fw_cfg_file f;
+   u32 size;
+   u16 select;
+   char name[FW_CFG_MAX_FILE_PATH];
struct list_head list;
 };
 
@@ -256,17 +258,17 @@ struct fw_cfg_sysfs_attribute fw_cfg_sysfs_attr_##_attr = 
{ \
 
 static ssize_t fw_cfg_sysfs_show_size(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%u\n", e->f.size);
+   return sprintf(buf, "%u\n", e->size);
 }
 
 static ssize_t fw_cfg_sysfs_show_key(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%u\n", e->f.select);
+   return sprintf(buf, "%u\n", e->select);
 }
 
 static ssize_t fw_cfg_sysfs_show_name(struct fw_cfg_sysfs_entry *e, char *buf)
 {
-   return sprintf(buf, "%s\n", e->f.name);
+   return sprintf(buf, "%s\n", e->name);
 }
 
 static FW_CFG_SYSFS_ATTR(size);
@@ -317,13 +319,13 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, 
struct kobject *kobj,
 {
struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
 
-   if (pos > entry->f.size)
+   if (pos > entry->size)
return -EINVAL;
 
-   if (count > entry->f.size - pos)
-   count = entry->f.size - pos;
+   if (count > entry->size - pos)
+   count = entry->size - pos;
 
-   fw_cfg_read_blob(entry->f.select, buf, pos, count);
+   fw_cfg_read_blob(entry->select, buf, pos, count);
return count;
 }
 
@@ -442,11 +444,13 @@ static int fw_cfg_register_file(const struct fw_cfg_file 
*f)
return -ENOMEM;
 
/* set file entry information */
-   memcpy(>f, f, sizeof(struct fw_cfg_file));
+   entry->size = be32_to_cpu(f->size);
+   entry->select = be16_to_cpu(f->select);
+   memcpy(entry->name, f->name, FW_CFG_MAX_FILE_PATH);
 
/* register entry under "/sys/firmware/qemu_fw_cfg/by_key/" */
err = kobject_init_and_add(>kobj, _cfg_sysfs_entry_ktype,
-  fw_cfg_sel_ko, "%d", entry->f.select);
+  fw_cfg_sel_ko, "%d", entry->select);
if (err)
goto err_register;
 
@@ -456,7 +460,7 @@ static int fw_cfg_register_file(const struct fw_cfg_file *f)
goto err_add_raw;
 
/* try adding "/sys/firmware/qemu_fw_cfg/by_name/" symlink */
-   fw_cfg_build_symlink(fw_cfg_fname_kset, >kobj, entry->f.name);
+   fw_cfg_build_symlink(fw_cfg_fname_kset, >kobj, entry->name);
 
/* success, add entry to global cache */
fw_cfg_sysfs_cache_enlist(entry);
@@ -488,8 +492,6 @@ static int fw_cfg_register_dir_entries(void)
fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(count), dir_size);
 
for (i = 0; i < count; i++) {
-   dir[i].size = be32_to_cpu(dir[i].size);
-   dir[i].select = be16_to_cpu(dir[i].select);
ret = fw_cfg_register_file([i]);
if (ret)
break;
-- 
2.16.1.73.g5832b7e9f2



[PATCH v14 2/9] fw_cfg: add a public uapi header

2018-02-14 Thread Marc-André Lureau
Create a common header file for well-known values and structures to be
shared by the Linux kernel with qemu or other projects.

Suggested-by: Michael S. Tsirkin <m...@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>

---

The related qemu patch making use of it, to be submitted:
https://github.com/elmarco/qemu/commit/4884fc9e9c4c4467a371e5a40f3181239e1b70f5
---
 MAINTAINERS|   1 +
 drivers/firmware/qemu_fw_cfg.c |  22 +
 include/uapi/linux/fw_cfg.h| 102 +
 3 files changed, 105 insertions(+), 20 deletions(-)
 create mode 100644 include/uapi/linux/fw_cfg.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 3bdc260e36b7..a66b65f62811 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11352,6 +11352,7 @@ M:  "Michael S. Tsirkin" <m...@redhat.com>
 L: qemu-de...@nongnu.org
 S: Maintained
 F: drivers/firmware/qemu_fw_cfg.c
+F: include/uapi/linux/fw_cfg.h
 
 QIB DRIVER
 M: Dennis Dalessandro <dennis.dalessan...@intel.com>
diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index a41b572eeeb1..90f467232777 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -32,30 +32,12 @@
 #include 
 #include 
 #include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo <so...@cmu.edu>");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
 MODULE_LICENSE("GPL");
 
-/* selector key values for "well-known" fw_cfg entries */
-#define FW_CFG_SIGNATURE  0x00
-#define FW_CFG_ID 0x01
-#define FW_CFG_FILE_DIR   0x19
-
-/* size in bytes of fw_cfg signature */
-#define FW_CFG_SIG_SIZE 4
-
-/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
-#define FW_CFG_MAX_FILE_PATH 56
-
-/* fw_cfg file directory entry type */
-struct fw_cfg_file {
-   u32 size;
-   u16 select;
-   u16 reserved;
-   char name[FW_CFG_MAX_FILE_PATH];
-};
-
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -597,7 +579,7 @@ MODULE_DEVICE_TABLE(of, fw_cfg_sysfs_mmio_match);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id fw_cfg_sysfs_acpi_match[] = {
-   { "QEMU0002", },
+   { FW_CFG_ACPI_DEVICE_ID, },
{},
 };
 MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
diff --git a/include/uapi/linux/fw_cfg.h b/include/uapi/linux/fw_cfg.h
new file mode 100644
index ..5b8136ce46ee
--- /dev/null
+++ b/include/uapi/linux/fw_cfg.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_FW_CFG_H
+#define _LINUX_FW_CFG_H
+
+#include 
+
+#define FW_CFG_ACPI_DEVICE_ID  "QEMU0002"
+
+/* selector key values for "well-known" fw_cfg entries */
+#define FW_CFG_SIGNATURE   0x00
+#define FW_CFG_ID  0x01
+#define FW_CFG_UUID0x02
+#define FW_CFG_RAM_SIZE0x03
+#define FW_CFG_NOGRAPHIC   0x04
+#define FW_CFG_NB_CPUS 0x05
+#define FW_CFG_MACHINE_ID  0x06
+#define FW_CFG_KERNEL_ADDR 0x07
+#define FW_CFG_KERNEL_SIZE 0x08
+#define FW_CFG_KERNEL_CMDLINE  0x09
+#define FW_CFG_INITRD_ADDR 0x0a
+#define FW_CFG_INITRD_SIZE 0x0b
+#define FW_CFG_BOOT_DEVICE 0x0c
+#define FW_CFG_NUMA0x0d
+#define FW_CFG_BOOT_MENU   0x0e
+#define FW_CFG_MAX_CPUS0x0f
+#define FW_CFG_KERNEL_ENTRY0x10
+#define FW_CFG_KERNEL_DATA 0x11
+#define FW_CFG_INITRD_DATA 0x12
+#define FW_CFG_CMDLINE_ADDR0x13
+#define FW_CFG_CMDLINE_SIZE0x14
+#define FW_CFG_CMDLINE_DATA0x15
+#define FW_CFG_SETUP_ADDR  0x16
+#define FW_CFG_SETUP_SIZE  0x17
+#define FW_CFG_SETUP_DATA  0x18
+#define FW_CFG_FILE_DIR0x19
+
+#define FW_CFG_FILE_FIRST  0x20
+#define FW_CFG_FILE_SLOTS_MIN  0x10
+
+#define FW_CFG_WRITE_CHANNEL   0x4000
+#define FW_CFG_ARCH_LOCAL  0x8000
+#define FW_CFG_ENTRY_MASK  (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
+
+#define FW_CFG_INVALID 0x
+
+/* width in bytes of fw_cfg control register */
+#define FW_CFG_CTL_SIZE0x02
+
+/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
+#define FW_CFG_MAX_FILE_PATH   56
+
+/* size in bytes of fw_cfg signature */
+#define FW_CFG_SIG_SIZE 4
+
+/* FW_CFG_ID bits */
+#define FW_CFG_VERSION 0x01
+#define FW_CFG_VERSION_DMA 0x02
+
+/* fw_cfg file directory entry type */
+struct fw_cfg_file {
+   __be32 size;/* file size */
+   __be16 select;  /* write this to 0x510 to read it */
+   __u16 reserved;
+   char name[FW_CFG_MAX_FILE_PATH];
+};
+
+struct fw_cfg_files {
+   __be32 count; /* number of entries */
+   struct fw_cfg_file f[];
+};
+
+/* FW_CFG_DMA_CONTROL bits */
+#define FW_CFG_DMA_CTL_ERROR   0x01
+#define FW_CFG_DMA_CTL_READ

[PATCH v14 2/9] fw_cfg: add a public uapi header

2018-02-14 Thread Marc-André Lureau
Create a common header file for well-known values and structures to be
shared by the Linux kernel with qemu or other projects.

Suggested-by: Michael S. Tsirkin 
Signed-off-by: Marc-André Lureau 

---

The related qemu patch making use of it, to be submitted:
https://github.com/elmarco/qemu/commit/4884fc9e9c4c4467a371e5a40f3181239e1b70f5
---
 MAINTAINERS|   1 +
 drivers/firmware/qemu_fw_cfg.c |  22 +
 include/uapi/linux/fw_cfg.h| 102 +
 3 files changed, 105 insertions(+), 20 deletions(-)
 create mode 100644 include/uapi/linux/fw_cfg.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 3bdc260e36b7..a66b65f62811 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11352,6 +11352,7 @@ M:  "Michael S. Tsirkin" 
 L: qemu-de...@nongnu.org
 S: Maintained
 F: drivers/firmware/qemu_fw_cfg.c
+F: include/uapi/linux/fw_cfg.h
 
 QIB DRIVER
 M: Dennis Dalessandro 
diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index a41b572eeeb1..90f467232777 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -32,30 +32,12 @@
 #include 
 #include 
 #include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo ");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
 MODULE_LICENSE("GPL");
 
-/* selector key values for "well-known" fw_cfg entries */
-#define FW_CFG_SIGNATURE  0x00
-#define FW_CFG_ID 0x01
-#define FW_CFG_FILE_DIR   0x19
-
-/* size in bytes of fw_cfg signature */
-#define FW_CFG_SIG_SIZE 4
-
-/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
-#define FW_CFG_MAX_FILE_PATH 56
-
-/* fw_cfg file directory entry type */
-struct fw_cfg_file {
-   u32 size;
-   u16 select;
-   u16 reserved;
-   char name[FW_CFG_MAX_FILE_PATH];
-};
-
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -597,7 +579,7 @@ MODULE_DEVICE_TABLE(of, fw_cfg_sysfs_mmio_match);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id fw_cfg_sysfs_acpi_match[] = {
-   { "QEMU0002", },
+   { FW_CFG_ACPI_DEVICE_ID, },
{},
 };
 MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
diff --git a/include/uapi/linux/fw_cfg.h b/include/uapi/linux/fw_cfg.h
new file mode 100644
index ..5b8136ce46ee
--- /dev/null
+++ b/include/uapi/linux/fw_cfg.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_FW_CFG_H
+#define _LINUX_FW_CFG_H
+
+#include 
+
+#define FW_CFG_ACPI_DEVICE_ID  "QEMU0002"
+
+/* selector key values for "well-known" fw_cfg entries */
+#define FW_CFG_SIGNATURE   0x00
+#define FW_CFG_ID  0x01
+#define FW_CFG_UUID0x02
+#define FW_CFG_RAM_SIZE0x03
+#define FW_CFG_NOGRAPHIC   0x04
+#define FW_CFG_NB_CPUS 0x05
+#define FW_CFG_MACHINE_ID  0x06
+#define FW_CFG_KERNEL_ADDR 0x07
+#define FW_CFG_KERNEL_SIZE 0x08
+#define FW_CFG_KERNEL_CMDLINE  0x09
+#define FW_CFG_INITRD_ADDR 0x0a
+#define FW_CFG_INITRD_SIZE 0x0b
+#define FW_CFG_BOOT_DEVICE 0x0c
+#define FW_CFG_NUMA0x0d
+#define FW_CFG_BOOT_MENU   0x0e
+#define FW_CFG_MAX_CPUS0x0f
+#define FW_CFG_KERNEL_ENTRY0x10
+#define FW_CFG_KERNEL_DATA 0x11
+#define FW_CFG_INITRD_DATA 0x12
+#define FW_CFG_CMDLINE_ADDR0x13
+#define FW_CFG_CMDLINE_SIZE0x14
+#define FW_CFG_CMDLINE_DATA0x15
+#define FW_CFG_SETUP_ADDR  0x16
+#define FW_CFG_SETUP_SIZE  0x17
+#define FW_CFG_SETUP_DATA  0x18
+#define FW_CFG_FILE_DIR0x19
+
+#define FW_CFG_FILE_FIRST  0x20
+#define FW_CFG_FILE_SLOTS_MIN  0x10
+
+#define FW_CFG_WRITE_CHANNEL   0x4000
+#define FW_CFG_ARCH_LOCAL  0x8000
+#define FW_CFG_ENTRY_MASK  (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
+
+#define FW_CFG_INVALID 0x
+
+/* width in bytes of fw_cfg control register */
+#define FW_CFG_CTL_SIZE0x02
+
+/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
+#define FW_CFG_MAX_FILE_PATH   56
+
+/* size in bytes of fw_cfg signature */
+#define FW_CFG_SIG_SIZE 4
+
+/* FW_CFG_ID bits */
+#define FW_CFG_VERSION 0x01
+#define FW_CFG_VERSION_DMA 0x02
+
+/* fw_cfg file directory entry type */
+struct fw_cfg_file {
+   __be32 size;/* file size */
+   __be16 select;  /* write this to 0x510 to read it */
+   __u16 reserved;
+   char name[FW_CFG_MAX_FILE_PATH];
+};
+
+struct fw_cfg_files {
+   __be32 count; /* number of entries */
+   struct fw_cfg_file f[];
+};
+
+/* FW_CFG_DMA_CONTROL bits */
+#define FW_CFG_DMA_CTL_ERROR   0x01
+#define FW_CFG_DMA_CTL_READ0x02
+#define FW_CFG_DMA_CTL_SKIP0x04
+#define FW_CFG_DMA_CTL_SELECT  0x08
+#define FW_CFG_DMA_CTL_WRITE   0x10
+
+#defin

[PATCH v13 0/4] fw_cfg: add DMA operations & etc/vmcoreinfo support

2018-02-06 Thread Marc-André Lureau
Hi,

This series adds DMA operations support to the qemu fw_cfg kernel
module and populates "etc/vmcoreinfo" with vmcoreinfo location
details (entry added since qemu 2.11 with -device vmcoreinfo).

v13:
- reorder patch series, introduce DMA write before DMA read
- do some measurements of DMA read speed-ups

v12:
- fix virt_to_phys(NULL) panic with CONFIG_DEBUG_VIRTUAL=y
- do not use DMA read, except for kmalloc() memory we allocated
  ourself (only fw_cfg_register_dir_entries() so far)

v11:
- add #include  in last patch,
  fixing kbuild .config test

Marc-André Lureau (4):
  crash: export paddr_vmcoreinfo_note()
  fw_cfg: add DMA register
  fw_cfg: write vmcoreinfo details
  RFC: fw_cfg: do DMA read operation

 drivers/firmware/qemu_fw_cfg.c | 257 -
 kernel/crash_core.c|   1 +
 2 files changed, 230 insertions(+), 28 deletions(-)

-- 
2.16.1.73.g5832b7e9f2



[PATCH v13 0/4] fw_cfg: add DMA operations & etc/vmcoreinfo support

2018-02-06 Thread Marc-André Lureau
Hi,

This series adds DMA operations support to the qemu fw_cfg kernel
module and populates "etc/vmcoreinfo" with vmcoreinfo location
details (entry added since qemu 2.11 with -device vmcoreinfo).

v13:
- reorder patch series, introduce DMA write before DMA read
- do some measurements of DMA read speed-ups

v12:
- fix virt_to_phys(NULL) panic with CONFIG_DEBUG_VIRTUAL=y
- do not use DMA read, except for kmalloc() memory we allocated
  ourself (only fw_cfg_register_dir_entries() so far)

v11:
- add #include  in last patch,
  fixing kbuild .config test

Marc-André Lureau (4):
  crash: export paddr_vmcoreinfo_note()
  fw_cfg: add DMA register
  fw_cfg: write vmcoreinfo details
  RFC: fw_cfg: do DMA read operation

 drivers/firmware/qemu_fw_cfg.c | 257 -
 kernel/crash_core.c|   1 +
 2 files changed, 230 insertions(+), 28 deletions(-)

-- 
2.16.1.73.g5832b7e9f2



[PATCH v13 3/4] fw_cfg: write vmcoreinfo details

2018-02-06 Thread Marc-André Lureau
If the "etc/vmcoreinfo" fw_cfg file is present and we are not running
the kdump kernel, write the addr/size of the vmcoreinfo ELF note.

The DMA operation is expected to run synchronously with today qemu,
but the specification states that it may become async, so we run
"control" field check in a loop for eventual changes.

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 drivers/firmware/qemu_fw_cfg.c | 157 -
 1 file changed, 154 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 740df0df2260..fd576ba7b337 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -33,6 +33,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo <so...@cmu.edu>");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
@@ -43,12 +46,24 @@ MODULE_LICENSE("GPL");
 #define FW_CFG_ID 0x01
 #define FW_CFG_FILE_DIR   0x19
 
+#define FW_CFG_VERSION_DMA 0x02
+#define FW_CFG_DMA_CTL_ERROR   0x01
+#define FW_CFG_DMA_CTL_READ0x02
+#define FW_CFG_DMA_CTL_SKIP0x04
+#define FW_CFG_DMA_CTL_SELECT  0x08
+#define FW_CFG_DMA_CTL_WRITE   0x10
+
 /* size in bytes of fw_cfg signature */
 #define FW_CFG_SIG_SIZE 4
 
 /* fw_cfg "file name" is up to 56 characters (including terminating nul) */
 #define FW_CFG_MAX_FILE_PATH 56
 
+#define VMCOREINFO_FORMAT_ELF 0x1
+
+/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
+static u32 fw_cfg_rev;
+
 /* fw_cfg file directory entry type */
 struct fw_cfg_file {
u32 size;
@@ -57,6 +72,12 @@ struct fw_cfg_file {
char name[FW_CFG_MAX_FILE_PATH];
 };
 
+struct fw_cfg_dma {
+   u32 control;
+   u32 length;
+   u64 address;
+} __packed;
+
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -75,6 +96,59 @@ static inline u16 fw_cfg_sel_endianness(u16 key)
return fw_cfg_is_mmio ? cpu_to_be16(key) : cpu_to_le16(key);
 }
 
+static inline bool fw_cfg_dma_enabled(void)
+{
+   return fw_cfg_rev & FW_CFG_VERSION_DMA && fw_cfg_reg_dma;
+}
+
+/* qemu fw_cfg device is sync today, but spec says it may become async */
+static void fw_cfg_wait_for_control(struct fw_cfg_dma *d)
+{
+   do {
+   u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
+
+   if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
+   return;
+
+   usleep_range(50, 100);
+   } while (true);
+}
+
+static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
+{
+   phys_addr_t dma;
+   struct fw_cfg_dma *d = NULL;
+   ssize_t ret = length;
+
+   d = kmalloc(sizeof(*d), GFP_KERNEL);
+   if (!d) {
+   ret = -ENOMEM;
+   goto end;
+   }
+
+   *d = (struct fw_cfg_dma) {
+   .address = address ? cpu_to_be64(virt_to_phys(address)) : 0,
+   .length = cpu_to_be32(length),
+   .control = cpu_to_be32(control)
+   };
+
+   dma = virt_to_phys(d);
+
+   iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
+   iowrite32be(dma, fw_cfg_reg_dma + 4);
+
+   fw_cfg_wait_for_control(d);
+
+   if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
+   ret = -EIO;
+   }
+
+end:
+   kfree(d);
+
+   return ret;
+}
+
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
 static inline void fw_cfg_read_blob(u16 key,
void *buf, loff_t pos, size_t count)
@@ -103,6 +177,47 @@ static inline void fw_cfg_read_blob(u16 key,
acpi_release_global_lock(glk);
 }
 
+#ifdef CONFIG_CRASH_CORE
+/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
+static ssize_t fw_cfg_write_blob(u16 key,
+void *buf, loff_t pos, size_t count)
+{
+   u32 glk = -1U;
+   acpi_status status;
+   ssize_t ret = count;
+
+   /* If we have ACPI, ensure mutual exclusion against any potential
+* device access by the firmware, e.g. via AML methods:
+*/
+   status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
+   if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
+   /* Should never get here */
+   WARN(1, "%s: Failed to lock ACPI!\n", __func__);
+   return -EINVAL;
+   }
+
+   mutex_lock(_cfg_dev_lock);
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+ | FW_CFG_DMA_CTL_SELECT
+ | FW_CFG_DMA_CTL_WRITE);
+   } else {
+   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW

[PATCH v13 3/4] fw_cfg: write vmcoreinfo details

2018-02-06 Thread Marc-André Lureau
If the "etc/vmcoreinfo" fw_cfg file is present and we are not running
the kdump kernel, write the addr/size of the vmcoreinfo ELF note.

The DMA operation is expected to run synchronously with today qemu,
but the specification states that it may become async, so we run
"control" field check in a loop for eventual changes.

Signed-off-by: Marc-André Lureau 
---
 drivers/firmware/qemu_fw_cfg.c | 157 -
 1 file changed, 154 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 740df0df2260..fd576ba7b337 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -33,6 +33,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 MODULE_AUTHOR("Gabriel L. Somlo ");
 MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
@@ -43,12 +46,24 @@ MODULE_LICENSE("GPL");
 #define FW_CFG_ID 0x01
 #define FW_CFG_FILE_DIR   0x19
 
+#define FW_CFG_VERSION_DMA 0x02
+#define FW_CFG_DMA_CTL_ERROR   0x01
+#define FW_CFG_DMA_CTL_READ0x02
+#define FW_CFG_DMA_CTL_SKIP0x04
+#define FW_CFG_DMA_CTL_SELECT  0x08
+#define FW_CFG_DMA_CTL_WRITE   0x10
+
 /* size in bytes of fw_cfg signature */
 #define FW_CFG_SIG_SIZE 4
 
 /* fw_cfg "file name" is up to 56 characters (including terminating nul) */
 #define FW_CFG_MAX_FILE_PATH 56
 
+#define VMCOREINFO_FORMAT_ELF 0x1
+
+/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
+static u32 fw_cfg_rev;
+
 /* fw_cfg file directory entry type */
 struct fw_cfg_file {
u32 size;
@@ -57,6 +72,12 @@ struct fw_cfg_file {
char name[FW_CFG_MAX_FILE_PATH];
 };
 
+struct fw_cfg_dma {
+   u32 control;
+   u32 length;
+   u64 address;
+} __packed;
+
 /* fw_cfg device i/o register addresses */
 static bool fw_cfg_is_mmio;
 static phys_addr_t fw_cfg_p_base;
@@ -75,6 +96,59 @@ static inline u16 fw_cfg_sel_endianness(u16 key)
return fw_cfg_is_mmio ? cpu_to_be16(key) : cpu_to_le16(key);
 }
 
+static inline bool fw_cfg_dma_enabled(void)
+{
+   return fw_cfg_rev & FW_CFG_VERSION_DMA && fw_cfg_reg_dma;
+}
+
+/* qemu fw_cfg device is sync today, but spec says it may become async */
+static void fw_cfg_wait_for_control(struct fw_cfg_dma *d)
+{
+   do {
+   u32 ctrl = be32_to_cpu(READ_ONCE(d->control));
+
+   if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0)
+   return;
+
+   usleep_range(50, 100);
+   } while (true);
+}
+
+static ssize_t fw_cfg_dma_transfer(void *address, u32 length, u32 control)
+{
+   phys_addr_t dma;
+   struct fw_cfg_dma *d = NULL;
+   ssize_t ret = length;
+
+   d = kmalloc(sizeof(*d), GFP_KERNEL);
+   if (!d) {
+   ret = -ENOMEM;
+   goto end;
+   }
+
+   *d = (struct fw_cfg_dma) {
+   .address = address ? cpu_to_be64(virt_to_phys(address)) : 0,
+   .length = cpu_to_be32(length),
+   .control = cpu_to_be32(control)
+   };
+
+   dma = virt_to_phys(d);
+
+   iowrite32be((u64)dma >> 32, fw_cfg_reg_dma);
+   iowrite32be(dma, fw_cfg_reg_dma + 4);
+
+   fw_cfg_wait_for_control(d);
+
+   if (be32_to_cpu(READ_ONCE(d->control)) & FW_CFG_DMA_CTL_ERROR) {
+   ret = -EIO;
+   }
+
+end:
+   kfree(d);
+
+   return ret;
+}
+
 /* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
 static inline void fw_cfg_read_blob(u16 key,
void *buf, loff_t pos, size_t count)
@@ -103,6 +177,47 @@ static inline void fw_cfg_read_blob(u16 key,
acpi_release_global_lock(glk);
 }
 
+#ifdef CONFIG_CRASH_CORE
+/* write chunk of given fw_cfg blob (caller responsible for sanity-check) */
+static ssize_t fw_cfg_write_blob(u16 key,
+void *buf, loff_t pos, size_t count)
+{
+   u32 glk = -1U;
+   acpi_status status;
+   ssize_t ret = count;
+
+   /* If we have ACPI, ensure mutual exclusion against any potential
+* device access by the firmware, e.g. via AML methods:
+*/
+   status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, );
+   if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
+   /* Should never get here */
+   WARN(1, "%s: Failed to lock ACPI!\n", __func__);
+   return -EINVAL;
+   }
+
+   mutex_lock(_cfg_dev_lock);
+   if (pos == 0) {
+   ret = fw_cfg_dma_transfer(buf, count, key << 16
+ | FW_CFG_DMA_CTL_SELECT
+ | FW_CFG_DMA_CTL_WRITE);
+   } else {
+   iowrite16(fw_cfg_sel_endianness(key), fw_cfg_reg_ctrl);
+   ret = fw_cfg_dma_transfer(NULL, pos, FW_CFG_DMA_CTL_SKIP);
+   if (r

  1   2   3   >