From: Kalle Valo <[email protected]>
Currently MHI loads the firmware image from the path provided by client
devices. ath11k needs to support firmware image embedded along with meta data
(named as firmware-2.bin). So allow the client driver to request the firmware
file from user space on it's own and provide the firmware image data and size
to MHI via a pointer struct mhi_controller::fw_data.
This is an optional feature, if fw_data is NULL MHI load the firmware using the
name from struct mhi_controller::fw_image string as before.
Tested with ath11k and WCN6855 hw2.0.
Signed-off-by: Kalle Valo <[email protected]>
---
drivers/bus/mhi/host/boot.c | 27 +++++++++++++++++++--------
include/linux/mhi.h | 6 ++++++
2 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c
index 1c69feee1703..d6d5f424491e 100644
--- a/drivers/bus/mhi/host/boot.c
+++ b/drivers/bus/mhi/host/boot.c
@@ -365,12 +365,10 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl,
}
static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl,
- const struct firmware *firmware,
+ const u8 *buf, size_t remainder,
struct image_info *img_info)
{
- size_t remainder = firmware->size;
size_t to_cpy;
- const u8 *buf = firmware->data;
struct mhi_buf *mhi_buf = img_info->mhi_buf;
struct bhi_vec_entry *bhi_vec = img_info->bhi_vec;
@@ -392,9 +390,10 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
const struct firmware *firmware = NULL;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
const char *fw_name;
+ const u8 *fw_data;
void *buf;
dma_addr_t dma_addr;
- size_t size;
+ size_t size, fw_sz;
int i, ret;
if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
@@ -424,6 +423,14 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
fw_name = (mhi_cntrl->ee == MHI_EE_EDL) ?
mhi_cntrl->edl_image : mhi_cntrl->fw_image;
+ if (!fw_name && mhi_cntrl->fbc_download &&
+ mhi_cntrl->fw_data && mhi_cntrl->fw_sz) {
+ size = mhi_cntrl->sbl_size;
+ fw_data = mhi_cntrl->fw_data;
+ fw_sz = mhi_cntrl->fw_sz;
+ goto skip_req_fw;
+ }
+
if (!fw_name || (mhi_cntrl->fbc_download && (!mhi_cntrl->sbl_size ||
!mhi_cntrl->seg_len))) {
dev_err(dev,
@@ -443,6 +450,10 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
if (size > firmware->size)
size = firmware->size;
+ fw_data = firmware->data;
+ fw_sz = firmware->size;
+
+skip_req_fw:
buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, &dma_addr,
GFP_KERNEL);
if (!buf) {
@@ -451,7 +462,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
}
/* Download image using BHI */
- memcpy(buf, firmware->data, size);
+ memcpy(buf, fw_data, size);
ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size);
dma_free_coherent(mhi_cntrl->cntrl_dev, size, buf, dma_addr);
@@ -463,7 +474,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
}
/* Wait for ready since EDL image was loaded */
- if (fw_name == mhi_cntrl->edl_image) {
+ if (fw_name && fw_name == mhi_cntrl->edl_image) {
release_firmware(firmware);
goto fw_load_ready_state;
}
@@ -478,14 +489,14 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
*/
if (mhi_cntrl->fbc_download) {
ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image,
- firmware->size);
+ fw_sz);
if (ret) {
release_firmware(firmware);
goto error_fw_load;
}
/* Load the firmware into BHIE vec table */
- mhi_firmware_copy(mhi_cntrl, firmware, mhi_cntrl->fbc_image);
+ mhi_firmware_copy(mhi_cntrl, fw_data, fw_sz, mhi_cntrl->fbc_image);
}
release_firmware(firmware);
diff --git a/include/linux/mhi.h b/include/linux/mhi.h
index a5441ad33c74..0d11fe22633e 100644
--- a/include/linux/mhi.h
+++ b/include/linux/mhi.h
@@ -299,6 +299,10 @@ struct mhi_controller_config {
* @iova_start: IOMMU starting address for data (required)
* @iova_stop: IOMMU stop address for data (required)
* @fw_image: Firmware image name for normal booting (optional)
+ * @fw_data: Firmware image data content for normal booting, used only
+ * if fw_image is NULL (optional)
+ * @fw_sz: Firmware image data size for normal booting, used only if fw_image
+ * is NULL (optional)
* @edl_image: Firmware image name for emergency download mode (optional)
* @rddm_size: RAM dump size that host should allocate for debugging purpose
* @sbl_size: SBL image size downloaded through BHIe (optional)
@@ -384,6 +388,8 @@ struct mhi_controller {
dma_addr_t iova_start;
dma_addr_t iova_stop;
const char *fw_image;
+ const u8 *fw_data;
+ size_t fw_sz;
const char *edl_image;
size_t rddm_size;
size_t sbl_size;
--
2.30.2
On 1/11/2023 2:25 AM, Kalle Valo wrote:
> From: Kalle Valo <[email protected]>
>
> Currently MHI loads the firmware image from the path provided by client
> devices. ath11k needs to support firmware image embedded along with meta data
> (named as firmware-2.bin). So allow the client driver to request the firmware
> file from user space on it's own and provide the firmware image data and size
> to MHI via a pointer struct mhi_controller::fw_data.
>
> This is an optional feature, if fw_data is NULL MHI load the firmware using the
> name from struct mhi_controller::fw_image string as before.
>
> Tested with ath11k and WCN6855 hw2.0.
>
> Signed-off-by: Kalle Valo <[email protected]>
> ---
> drivers/bus/mhi/host/boot.c | 27 +++++++++++++++++++--------
> include/linux/mhi.h | 6 ++++++
> 2 files changed, 25 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c
> index 1c69feee1703..d6d5f424491e 100644
> --- a/drivers/bus/mhi/host/boot.c
> +++ b/drivers/bus/mhi/host/boot.c
> @@ -365,12 +365,10 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl,
> }
>
> static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl,
> - const struct firmware *firmware,
> + const u8 *buf, size_t remainder,
> struct image_info *img_info)
> {
> - size_t remainder = firmware->size;
> size_t to_cpy;
> - const u8 *buf = firmware->data;
> struct mhi_buf *mhi_buf = img_info->mhi_buf;
> struct bhi_vec_entry *bhi_vec = img_info->bhi_vec;
>
> @@ -392,9 +390,10 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
> const struct firmware *firmware = NULL;
> struct device *dev = &mhi_cntrl->mhi_dev->dev;
> const char *fw_name;
> + const u8 *fw_data;
> void *buf;
> dma_addr_t dma_addr;
> - size_t size;
> + size_t size, fw_sz;
> int i, ret;
>
> if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
> @@ -424,6 +423,14 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
> fw_name = (mhi_cntrl->ee == MHI_EE_EDL) ?
> mhi_cntrl->edl_image : mhi_cntrl->fw_image;
>
> + if (!fw_name && mhi_cntrl->fbc_download &&
> + mhi_cntrl->fw_data && mhi_cntrl->fw_sz) {
> + size = mhi_cntrl->sbl_size;
> + fw_data = mhi_cntrl->fw_data;
> + fw_sz = mhi_cntrl->fw_sz;
> + goto skip_req_fw;
> + }
> +
> if (!fw_name || (mhi_cntrl->fbc_download && (!mhi_cntrl->sbl_size ||
> !mhi_cntrl->seg_len))) {
> dev_err(dev,
> @@ -443,6 +450,10 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
> if (size > firmware->size)
> size = firmware->size;
>
> + fw_data = firmware->data;
> + fw_sz = firmware->size;
> +
> +skip_req_fw:
> buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, &dma_addr,
> GFP_KERNEL);
> if (!buf) {
> @@ -451,7 +462,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
> }
>
> /* Download image using BHI */
> - memcpy(buf, firmware->data, size);
> + memcpy(buf, fw_data, size);
> ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size);
> dma_free_coherent(mhi_cntrl->cntrl_dev, size, buf, dma_addr);
>
> @@ -463,7 +474,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
> }
>
> /* Wait for ready since EDL image was loaded */
> - if (fw_name == mhi_cntrl->edl_image) {
> + if (fw_name && fw_name == mhi_cntrl->edl_image) {
> release_firmware(firmware);
> goto fw_load_ready_state;
> }
> @@ -478,14 +489,14 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
> */
> if (mhi_cntrl->fbc_download) {
> ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image,
> - firmware->size);
> + fw_sz);
Minor nit, but it seems like this could be all on one line.
> if (ret) {
> release_firmware(firmware);
> goto error_fw_load;
> }
>
> /* Load the firmware into BHIE vec table */
> - mhi_firmware_copy(mhi_cntrl, firmware, mhi_cntrl->fbc_image);
> + mhi_firmware_copy(mhi_cntrl, fw_data, fw_sz, mhi_cntrl->fbc_image);
> }
>
> release_firmware(firmware);
> diff --git a/include/linux/mhi.h b/include/linux/mhi.h
> index a5441ad33c74..0d11fe22633e 100644
> --- a/include/linux/mhi.h
> +++ b/include/linux/mhi.h
> @@ -299,6 +299,10 @@ struct mhi_controller_config {
> * @iova_start: IOMMU starting address for data (required)
> * @iova_stop: IOMMU stop address for data (required)
> * @fw_image: Firmware image name for normal booting (optional)
> + * @fw_data: Firmware image data content for normal booting, used only
> + * if fw_image is NULL (optional)
The implementation requires fbc_download to be set, which is not a
requirement for fw_image. That is not apparent here.
> + * @fw_sz: Firmware image data size for normal booting, used only if fw_image
> + * is NULL (optional)
> * @edl_image: Firmware image name for emergency download mode (optional)
> * @rddm_size: RAM dump size that host should allocate for debugging purpose
> * @sbl_size: SBL image size downloaded through BHIe (optional)
> @@ -384,6 +388,8 @@ struct mhi_controller {
> dma_addr_t iova_start;
> dma_addr_t iova_stop;
> const char *fw_image;
> + const u8 *fw_data;
> + size_t fw_sz;
Did you run pahole? I remember this struct being well packed, and I
think this will add a compiler hole but I have not actually verified.
> const char *edl_image;
> size_t rddm_size;
> size_t sbl_size;
Jeffrey Hugo <[email protected]> writes:
> On 1/11/2023 2:25 AM, Kalle Valo wrote:
>> From: Kalle Valo <[email protected]>
>>
>> Currently MHI loads the firmware image from the path provided by client
>> devices. ath11k needs to support firmware image embedded along with meta data
>> (named as firmware-2.bin). So allow the client driver to request the firmware
>> file from user space on it's own and provide the firmware image data and size
>> to MHI via a pointer struct mhi_controller::fw_data.
>>
>> This is an optional feature, if fw_data is NULL MHI load the firmware using the
>> name from struct mhi_controller::fw_image string as before.
>>
>> Tested with ath11k and WCN6855 hw2.0.
>>
>> Signed-off-by: Kalle Valo <[email protected]>
[...]
>> @@ -478,14 +489,14 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
>> */
>> if (mhi_cntrl->fbc_download) {
>> ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image,
>> - firmware->size);
>> + fw_sz);
>
> Minor nit, but it seems like this could be all on one line.
Will fix in v2.
>> --- a/include/linux/mhi.h
>> +++ b/include/linux/mhi.h
>> @@ -299,6 +299,10 @@ struct mhi_controller_config {
>> * @iova_start: IOMMU starting address for data (required)
>> * @iova_stop: IOMMU stop address for data (required)
>> * @fw_image: Firmware image name for normal booting (optional)
>> + * @fw_data: Firmware image data content for normal booting, used only
>> + * if fw_image is NULL (optional)
>
> The implementation requires fbc_download to be set, which is not a
> requirement for fw_image. That is not apparent here.
Ah, I had missed that. Will mention that in v2.
>> @@ -384,6 +388,8 @@ struct mhi_controller {
>> dma_addr_t iova_start;
>> dma_addr_t iova_stop;
>> const char *fw_image;
>> + const u8 *fw_data;
>> + size_t fw_sz;
>
> Did you run pahole? I remember this struct being well packed, and I
> think this will add a compiler hole but I have not actually verified.
I actually haven't used pahole for ages. I will run it and check how
this structure is packed.
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Kalle Valo <[email protected]> writes:
> Jeffrey Hugo <[email protected]> writes:
>
>> On 1/11/2023 2:25 AM, Kalle Valo wrote:
>>> From: Kalle Valo <[email protected]>
>>>
>>> Currently MHI loads the firmware image from the path provided by client
>>> devices. ath11k needs to support firmware image embedded along with meta data
>>> (named as firmware-2.bin). So allow the client driver to request the firmware
>>> file from user space on it's own and provide the firmware image data and size
>>> to MHI via a pointer struct mhi_controller::fw_data.
>>>
>>> This is an optional feature, if fw_data is NULL MHI load the firmware using the
>>> name from struct mhi_controller::fw_image string as before.
>>>
>>> Tested with ath11k and WCN6855 hw2.0.
>>>
>>> Signed-off-by: Kalle Valo <[email protected]>
[...]
>> Did you run pahole? I remember this struct being well packed, and I
>> think this will add a compiler hole but I have not actually verified.
>
> I actually haven't used pahole for ages. I will run it and check how
> this structure is packed.
Below is what pahole shows with GCC 8.3 on x86_64. Look pretty well
packed, right?
struct mhi_controller {
struct device * cntrl_dev; /* 0 8 */
struct mhi_device * mhi_dev; /* 8 8 */
struct dentry * debugfs_dentry; /* 16 8 */
void * regs; /* 24 8 */
void * bhi; /* 32 8 */
void * bhie; /* 40 8 */
void * wake_db; /* 48 8 */
dma_addr_t iova_start; /* 56 8 */
/* --- cacheline 1 boundary (64 bytes) --- */
dma_addr_t iova_stop; /* 64 8 */
const char * fw_image; /* 72 8 */
const u8 * fw_data; /* 80 8 */
size_t fw_sz; /* 88 8 */
const char * edl_image; /* 96 8 */
size_t rddm_size; /* 104 8 */
size_t sbl_size; /* 112 8 */
size_t seg_len; /* 120 8 */
/* --- cacheline 2 boundary (128 bytes) --- */
size_t reg_len; /* 128 8 */
struct image_info * fbc_image; /* 136 8 */
struct image_info * rddm_image; /* 144 8 */
struct mhi_chan * mhi_chan; /* 152 8 */
struct list_head lpm_chans; /* 160 16 */
int * irq; /* 176 8 */
u32 max_chan; /* 184 4 */
u32 total_ev_rings; /* 188 4 */
/* --- cacheline 3 boundary (192 bytes) --- */
u32 hw_ev_rings; /* 192 4 */
u32 sw_ev_rings; /* 196 4 */
u32 nr_irqs; /* 200 4 */
u32 family_number; /* 204 4 */
u32 device_number; /* 208 4 */
u32 major_version; /* 212 4 */
u32 minor_version; /* 216 4 */
u32 serial_number; /* 220 4 */
u32 oem_pk_hash[16]; /* 224 64 */
/* --- cacheline 4 boundary (256 bytes) was 32 bytes ago --- */
struct mhi_event * mhi_event; /* 288 8 */
struct mhi_cmd * mhi_cmd; /* 296 8 */
struct mhi_ctxt * mhi_ctxt; /* 304 8 */
struct mutex pm_mutex; /* 312 160 */
/* --- cacheline 7 boundary (448 bytes) was 24 bytes ago --- */
rwlock_t pm_lock; /* 472 72 */
/* --- cacheline 8 boundary (512 bytes) was 32 bytes ago --- */
u32 timeout_ms; /* 544 4 */
u32 pm_state; /* 548 4 */
u32 db_access; /* 552 4 */
enum mhi_ee_type ee; /* 556 4 */
enum mhi_state dev_state; /* 560 4 */
atomic_t dev_wake; /* 564 4 */
atomic_t pending_pkts; /* 568 4 */
u32 M0; /* 572 4 */
/* --- cacheline 9 boundary (576 bytes) --- */
u32 M2; /* 576 4 */
u32 M3; /* 580 4 */
struct list_head transition_list; /* 584 16 */
spinlock_t transition_lock; /* 600 72 */
/* --- cacheline 10 boundary (640 bytes) was 32 bytes ago --- */
spinlock_t wlock; /* 672 72 */
/* --- cacheline 11 boundary (704 bytes) was 40 bytes ago --- */
struct mhi_link_info mhi_link_info; /* 744 8 */
struct work_struct st_worker; /* 752 80 */
/* --- cacheline 13 boundary (832 bytes) --- */
struct workqueue_struct * hiprio_wq; /* 832 8 */
wait_queue_head_t state_event; /* 840 88 */
/* --- cacheline 14 boundary (896 bytes) was 32 bytes ago --- */
void (*status_cb)(struct mhi_controller *, enum mhi_callback); /* 928 8 */
void (*wake_get)(struct mhi_controller *, bool); /* 936 8 */
void (*wake_put)(struct mhi_controller *, bool); /* 944 8 */
void (*wake_toggle)(struct mhi_controller *); /* 952 8 */
/* --- cacheline 15 boundary (960 bytes) --- */
int (*runtime_get)(struct mhi_controller *); /* 960 8 */
void (*runtime_put)(struct mhi_controller *); /* 968 8 */
int (*map_single)(struct mhi_controller *, struct mhi_buf_info *); /* 976 8 */
void (*unmap_single)(struct mhi_controller *, struct mhi_buf_info *); /* 984 8 */
int (*read_reg)(struct mhi_controller *, void *, u32 *); /* 992 8 */
void (*write_reg)(struct mhi_controller *, void *, u32); /* 1000 8 */
void (*reset)(struct mhi_controller *); /* 1008 8 */
size_t buffer_len; /* 1016 8 */
/* --- cacheline 16 boundary (1024 bytes) --- */
int index; /* 1024 4 */
bool bounce_buf; /* 1028 1 */
bool fbc_download; /* 1029 1 */
bool wake_set; /* 1030 1 */
/* XXX 1 byte hole, try to pack */
long unsigned int irq_flags; /* 1032 8 */
u32 mru; /* 1040 4 */
/* size: 1048, cachelines: 17, members: 73 */
/* sum members: 1043, holes: 1, sum holes: 1 */
/* padding: 4 */
/* last cacheline: 24 bytes */
};
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
On 3/8/2023 6:20 AM, Kalle Valo wrote:
> Kalle Valo <[email protected]> writes:
>
>> Jeffrey Hugo <[email protected]> writes:
>>
>>> On 1/11/2023 2:25 AM, Kalle Valo wrote:
>>>> From: Kalle Valo <[email protected]>
>>>>
>>>> Currently MHI loads the firmware image from the path provided by client
>>>> devices. ath11k needs to support firmware image embedded along with meta data
>>>> (named as firmware-2.bin). So allow the client driver to request the firmware
>>>> file from user space on it's own and provide the firmware image data and size
>>>> to MHI via a pointer struct mhi_controller::fw_data.
>>>>
>>>> This is an optional feature, if fw_data is NULL MHI load the firmware using the
>>>> name from struct mhi_controller::fw_image string as before.
>>>>
>>>> Tested with ath11k and WCN6855 hw2.0.
>>>>
>>>> Signed-off-by: Kalle Valo <[email protected]>
>
> [...]
>
>>> Did you run pahole? I remember this struct being well packed, and I
>>> think this will add a compiler hole but I have not actually verified.
>>
>> I actually haven't used pahole for ages. I will run it and check how
>> this structure is packed.
>
> Below is what pahole shows with GCC 8.3 on x86_64. Look pretty well
> packed, right?
Yes, looks almost perfect.
>
> struct mhi_controller {
> struct device * cntrl_dev; /* 0 8 */
> struct mhi_device * mhi_dev; /* 8 8 */
> struct dentry * debugfs_dentry; /* 16 8 */
> void * regs; /* 24 8 */
> void * bhi; /* 32 8 */
> void * bhie; /* 40 8 */
> void * wake_db; /* 48 8 */
> dma_addr_t iova_start; /* 56 8 */
> /* --- cacheline 1 boundary (64 bytes) --- */
> dma_addr_t iova_stop; /* 64 8 */
> const char * fw_image; /* 72 8 */
> const u8 * fw_data; /* 80 8 */
> size_t fw_sz; /* 88 8 */
> const char * edl_image; /* 96 8 */
> size_t rddm_size; /* 104 8 */
> size_t sbl_size; /* 112 8 */
> size_t seg_len; /* 120 8 */
> /* --- cacheline 2 boundary (128 bytes) --- */
> size_t reg_len; /* 128 8 */
> struct image_info * fbc_image; /* 136 8 */
> struct image_info * rddm_image; /* 144 8 */
> struct mhi_chan * mhi_chan; /* 152 8 */
> struct list_head lpm_chans; /* 160 16 */
> int * irq; /* 176 8 */
> u32 max_chan; /* 184 4 */
> u32 total_ev_rings; /* 188 4 */
> /* --- cacheline 3 boundary (192 bytes) --- */
> u32 hw_ev_rings; /* 192 4 */
> u32 sw_ev_rings; /* 196 4 */
> u32 nr_irqs; /* 200 4 */
> u32 family_number; /* 204 4 */
> u32 device_number; /* 208 4 */
> u32 major_version; /* 212 4 */
> u32 minor_version; /* 216 4 */
> u32 serial_number; /* 220 4 */
> u32 oem_pk_hash[16]; /* 224 64 */
> /* --- cacheline 4 boundary (256 bytes) was 32 bytes ago --- */
> struct mhi_event * mhi_event; /* 288 8 */
> struct mhi_cmd * mhi_cmd; /* 296 8 */
> struct mhi_ctxt * mhi_ctxt; /* 304 8 */
> struct mutex pm_mutex; /* 312 160 */
> /* --- cacheline 7 boundary (448 bytes) was 24 bytes ago --- */
> rwlock_t pm_lock; /* 472 72 */
> /* --- cacheline 8 boundary (512 bytes) was 32 bytes ago --- */
> u32 timeout_ms; /* 544 4 */
> u32 pm_state; /* 548 4 */
> u32 db_access; /* 552 4 */
> enum mhi_ee_type ee; /* 556 4 */
> enum mhi_state dev_state; /* 560 4 */
> atomic_t dev_wake; /* 564 4 */
> atomic_t pending_pkts; /* 568 4 */
> u32 M0; /* 572 4 */
> /* --- cacheline 9 boundary (576 bytes) --- */
> u32 M2; /* 576 4 */
> u32 M3; /* 580 4 */
> struct list_head transition_list; /* 584 16 */
> spinlock_t transition_lock; /* 600 72 */
> /* --- cacheline 10 boundary (640 bytes) was 32 bytes ago --- */
> spinlock_t wlock; /* 672 72 */
> /* --- cacheline 11 boundary (704 bytes) was 40 bytes ago --- */
> struct mhi_link_info mhi_link_info; /* 744 8 */
> struct work_struct st_worker; /* 752 80 */
> /* --- cacheline 13 boundary (832 bytes) --- */
> struct workqueue_struct * hiprio_wq; /* 832 8 */
> wait_queue_head_t state_event; /* 840 88 */
> /* --- cacheline 14 boundary (896 bytes) was 32 bytes ago --- */
> void (*status_cb)(struct mhi_controller *, enum mhi_callback); /* 928 8 */
> void (*wake_get)(struct mhi_controller *, bool); /* 936 8 */
> void (*wake_put)(struct mhi_controller *, bool); /* 944 8 */
> void (*wake_toggle)(struct mhi_controller *); /* 952 8 */
> /* --- cacheline 15 boundary (960 bytes) --- */
> int (*runtime_get)(struct mhi_controller *); /* 960 8 */
> void (*runtime_put)(struct mhi_controller *); /* 968 8 */
> int (*map_single)(struct mhi_controller *, struct mhi_buf_info *); /* 976 8 */
> void (*unmap_single)(struct mhi_controller *, struct mhi_buf_info *); /* 984 8 */
> int (*read_reg)(struct mhi_controller *, void *, u32 *); /* 992 8 */
> void (*write_reg)(struct mhi_controller *, void *, u32); /* 1000 8 */
> void (*reset)(struct mhi_controller *); /* 1008 8 */
> size_t buffer_len; /* 1016 8 */
> /* --- cacheline 16 boundary (1024 bytes) --- */
> int index; /* 1024 4 */
> bool bounce_buf; /* 1028 1 */
> bool fbc_download; /* 1029 1 */
> bool wake_set; /* 1030 1 */
>
> /* XXX 1 byte hole, try to pack */
>
> long unsigned int irq_flags; /* 1032 8 */
> u32 mru; /* 1040 4 */
>
> /* size: 1048, cachelines: 17, members: 73 */
> /* sum members: 1043, holes: 1, sum holes: 1 */
> /* padding: 4 */
> /* last cacheline: 24 bytes */
> };
>