Skip to content

Commit 98e7086

Browse files
Tomas Winklergregkh
authored andcommitted
mei: add support for variable length mei headers.
Remove header size knowledge from me and txe hw layers, this requires to change the write handler to accept header and its length as well as data and its length. HBM messages are fixed to use basic header, hence we add mei_hbm2slots() that converts HBM message length and mei message header, while mei_data2slots() converts data length directly to the slots. Signed-off-by: Tomas Winkler <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b34e9a1 commit 98e7086

File tree

6 files changed

+102
-64
lines changed

6 files changed

+102
-64
lines changed

drivers/misc/mei/client.c

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,7 @@ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
863863
int slots;
864864
int ret;
865865

866-
msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
866+
msg_slots = mei_hbm2slots(sizeof(struct hbm_client_connect_request));
867867
slots = mei_hbuf_empty_slots(dev);
868868
if (slots < 0)
869869
return -EOVERFLOW;
@@ -1055,11 +1055,10 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
10551055
int slots;
10561056
int rets;
10571057

1058-
msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
1059-
10601058
if (mei_cl_is_other_connecting(cl))
10611059
return 0;
10621060

1061+
msg_slots = mei_hbm2slots(sizeof(struct hbm_client_connect_request));
10631062
slots = mei_hbuf_empty_slots(dev);
10641063
if (slots < 0)
10651064
return -EOVERFLOW;
@@ -1299,7 +1298,7 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
12991298
int ret;
13001299
bool request;
13011300

1302-
msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
1301+
msg_slots = mei_hbm2slots(sizeof(struct hbm_client_connect_request));
13031302
slots = mei_hbuf_empty_slots(dev);
13041303
if (slots < 0)
13051304
return -EOVERFLOW;
@@ -1571,6 +1570,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
15711570
struct mei_device *dev;
15721571
struct mei_msg_data *buf;
15731572
struct mei_msg_hdr mei_hdr;
1573+
size_t hdr_len = sizeof(mei_hdr);
15741574
size_t len;
15751575
size_t hbuf_len;
15761576
int hbuf_slots;
@@ -1601,27 +1601,29 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
16011601
rets = -EOVERFLOW;
16021602
goto err;
16031603
}
1604-
hbuf_len = mei_slots2data(hbuf_slots) - sizeof(struct mei_msg_hdr);
1604+
1605+
hbuf_len = mei_slots2data(hbuf_slots);
16051606

16061607
mei_msg_hdr_init(&mei_hdr, cb);
16071608

16081609
/**
16091610
* Split the message only if we can write the whole host buffer
16101611
* otherwise wait for next time the host buffer is empty.
16111612
*/
1612-
if (hbuf_len >= len) {
1613+
if (len + hdr_len <= hbuf_len) {
16131614
mei_hdr.length = len;
16141615
mei_hdr.msg_complete = 1;
16151616
} else if ((u32)hbuf_slots == mei_hbuf_depth(dev)) {
1616-
mei_hdr.length = hbuf_len;
1617+
mei_hdr.length = hbuf_len - hdr_len;
16171618
} else {
16181619
return 0;
16191620
}
16201621

16211622
cl_dbg(dev, cl, "buf: size = %zu idx = %zu\n",
16221623
cb->buf.size, cb->buf_idx);
16231624

1624-
rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
1625+
rets = mei_write_message(dev, &mei_hdr, hdr_len,
1626+
buf->data + cb->buf_idx, mei_hdr.length);
16251627
if (rets)
16261628
goto err;
16271629

@@ -1661,6 +1663,7 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
16611663
struct mei_device *dev;
16621664
struct mei_msg_data *buf;
16631665
struct mei_msg_hdr mei_hdr;
1666+
size_t hdr_len = sizeof(mei_hdr);
16641667
size_t len;
16651668
size_t hbuf_len;
16661669
int hbuf_slots;
@@ -1716,15 +1719,17 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
17161719
goto out;
17171720
}
17181721

1719-
hbuf_len = mei_slots2data(hbuf_slots) - sizeof(struct mei_msg_hdr);
1720-
if (hbuf_len >= len) {
1722+
hbuf_len = mei_slots2data(hbuf_slots);
1723+
1724+
if (len + hdr_len <= hbuf_len) {
17211725
mei_hdr.length = len;
17221726
mei_hdr.msg_complete = 1;
17231727
} else {
1724-
mei_hdr.length = hbuf_len;
1728+
mei_hdr.length = hbuf_len - hdr_len;
17251729
}
17261730

1727-
rets = mei_write_message(dev, &mei_hdr, buf->data);
1731+
rets = mei_write_message(dev, &mei_hdr, hdr_len,
1732+
buf->data, mei_hdr.length);
17281733
if (rets)
17291734
goto err;
17301735

@@ -1761,7 +1766,7 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
17611766
}
17621767
}
17631768

1764-
rets = len;
1769+
rets = buf->size;
17651770
err:
17661771
cl_dbg(dev, cl, "rpm: autosuspend\n");
17671772
pm_runtime_mark_last_busy(dev->dev);

drivers/misc/mei/hbm.c

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,20 @@ static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
9595
}
9696
}
9797

98+
/**
99+
* mei_hbm_write_message - wrapper for sending hbm messages.
100+
*
101+
* @dev: mei device
102+
* @hdr: mei header
103+
* @data: payload
104+
*/
105+
static inline int mei_hbm_write_message(struct mei_device *dev,
106+
struct mei_msg_hdr *hdr,
107+
const void *data)
108+
{
109+
return mei_write_message(dev, hdr, sizeof(*hdr), data, hdr->length);
110+
}
111+
98112
/**
99113
* mei_hbm_idle - set hbm to idle state
100114
*
@@ -174,7 +188,7 @@ static inline int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl,
174188
mei_hbm_hdr(&mei_hdr, len);
175189
mei_hbm_cl_hdr(cl, hbm_cmd, buf, len);
176190

177-
return mei_write_message(dev, &mei_hdr, buf);
191+
return mei_hbm_write_message(dev, &mei_hdr, buf);
178192
}
179193

180194
/**
@@ -267,7 +281,7 @@ int mei_hbm_start_req(struct mei_device *dev)
267281
start_req.host_version.minor_version = HBM_MINOR_VERSION;
268282

269283
dev->hbm_state = MEI_HBM_IDLE;
270-
ret = mei_write_message(dev, &mei_hdr, &start_req);
284+
ret = mei_hbm_write_message(dev, &mei_hdr, &start_req);
271285
if (ret) {
272286
dev_err(dev->dev, "version message write failed: ret = %d\n",
273287
ret);
@@ -304,7 +318,7 @@ static int mei_hbm_enum_clients_req(struct mei_device *dev)
304318
enum_req.flags |= dev->hbm_f_ie_supported ?
305319
MEI_HBM_ENUM_F_IMMEDIATE_ENUM : 0;
306320

307-
ret = mei_write_message(dev, &mei_hdr, &enum_req);
321+
ret = mei_hbm_write_message(dev, &mei_hdr, &enum_req);
308322
if (ret) {
309323
dev_err(dev->dev, "enumeration request write failed: ret = %d.\n",
310324
ret);
@@ -373,7 +387,7 @@ static int mei_hbm_add_cl_resp(struct mei_device *dev, u8 addr, u8 status)
373387
resp.me_addr = addr;
374388
resp.status = status;
375389

376-
ret = mei_write_message(dev, &mei_hdr, &resp);
390+
ret = mei_hbm_write_message(dev, &mei_hdr, &resp);
377391
if (ret)
378392
dev_err(dev->dev, "add client response write failed: ret = %d\n",
379393
ret);
@@ -430,7 +444,7 @@ int mei_hbm_cl_notify_req(struct mei_device *dev,
430444

431445
req.start = start;
432446

433-
ret = mei_write_message(dev, &mei_hdr, &req);
447+
ret = mei_hbm_write_message(dev, &mei_hdr, &req);
434448
if (ret)
435449
dev_err(dev->dev, "notify request failed: ret = %d\n", ret);
436450

@@ -555,7 +569,7 @@ static int mei_hbm_prop_req(struct mei_device *dev, unsigned long start_idx)
555569
prop_req.hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
556570
prop_req.me_addr = addr;
557571

558-
ret = mei_write_message(dev, &mei_hdr, &prop_req);
572+
ret = mei_hbm_write_message(dev, &mei_hdr, &prop_req);
559573
if (ret) {
560574
dev_err(dev->dev, "properties request write failed: ret = %d\n",
561575
ret);
@@ -592,7 +606,7 @@ int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd)
592606
memset(&req, 0, len);
593607
req.hbm_cmd = pg_cmd;
594608

595-
ret = mei_write_message(dev, &mei_hdr, &req);
609+
ret = mei_hbm_write_message(dev, &mei_hdr, &req);
596610
if (ret)
597611
dev_err(dev->dev, "power gate command write failed.\n");
598612
return ret;
@@ -618,7 +632,7 @@ static int mei_hbm_stop_req(struct mei_device *dev)
618632
req.hbm_cmd = HOST_STOP_REQ_CMD;
619633
req.reason = DRIVER_STOP_REQUEST;
620634

621-
return mei_write_message(dev, &mei_hdr, &req);
635+
return mei_hbm_write_message(dev, &mei_hdr, &req);
622636
}
623637

624638
/**

drivers/misc/mei/hw-me.c

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -517,49 +517,55 @@ static u32 mei_me_hbuf_depth(const struct mei_device *dev)
517517
return hw->hbuf_depth;
518518
}
519519

520-
521520
/**
522521
* mei_me_hbuf_write - writes a message to host hw buffer.
523522
*
524523
* @dev: the device structure
525-
* @header: mei HECI header of message
526-
* @buf: message payload will be written
524+
* @hdr: header of message
525+
* @hdr_len: header length in bytes: must be multiplication of a slot (4bytes)
526+
* @data: payload
527+
* @data_len: payload length in bytes
527528
*
528-
* Return: -EIO if write has failed
529+
* Return: 0 if success, < 0 - otherwise.
529530
*/
530531
static int mei_me_hbuf_write(struct mei_device *dev,
531-
struct mei_msg_hdr *header,
532-
const unsigned char *buf)
532+
const void *hdr, size_t hdr_len,
533+
const void *data, size_t data_len)
533534
{
534535
unsigned long rem;
535-
unsigned long length = header->length;
536536
unsigned long i;
537-
u32 *reg_buf = (u32 *)buf;
537+
const u32 *reg_buf;
538538
u32 dw_cnt;
539539
int empty_slots;
540540

541-
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
541+
if (WARN_ON(!hdr || !data || hdr_len & 0x3))
542+
return -EINVAL;
543+
544+
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM((struct mei_msg_hdr *)hdr));
542545

543546
empty_slots = mei_hbuf_empty_slots(dev);
544547
dev_dbg(dev->dev, "empty slots = %hu.\n", empty_slots);
545548

546549
if (empty_slots < 0)
547550
return -EOVERFLOW;
548551

549-
dw_cnt = mei_data2slots(length);
552+
dw_cnt = mei_data2slots(hdr_len + data_len);
550553
if (dw_cnt > (u32)empty_slots)
551554
return -EMSGSIZE;
552555

553-
mei_me_hcbww_write(dev, *((u32 *) header));
556+
reg_buf = hdr;
557+
for (i = 0; i < hdr_len / MEI_SLOT_SIZE; i++)
558+
mei_me_hcbww_write(dev, reg_buf[i]);
554559

555-
for (i = 0; i < length / MEI_SLOT_SIZE; i++)
560+
reg_buf = data;
561+
for (i = 0; i < data_len / MEI_SLOT_SIZE; i++)
556562
mei_me_hcbww_write(dev, reg_buf[i]);
557563

558-
rem = length & 0x3;
564+
rem = data_len & 0x3;
559565
if (rem > 0) {
560566
u32 reg = 0;
561567

562-
memcpy(&reg, &buf[length - rem], rem);
568+
memcpy(&reg, (const u8 *)data + data_len - rem, rem);
563569
mei_me_hcbww_write(dev, reg);
564570
}
565571

drivers/misc/mei/hw-txe.c

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -689,37 +689,34 @@ static void mei_txe_hw_config(struct mei_device *dev)
689689
hw->aliveness, hw->readiness);
690690
}
691691

692-
693692
/**
694693
* mei_txe_write - writes a message to device.
695694
*
696695
* @dev: the device structure
697-
* @header: header of message
698-
* @buf: message buffer will be written
696+
* @hdr: header of message
697+
* @hdr_len: header length in bytes - must multiplication of a slot (4bytes)
698+
* @data: payload
699+
* @data_len: paylead length in bytes
699700
*
700-
* Return: 0 if success, <0 - otherwise.
701+
* Return: 0 if success, < 0 - otherwise.
701702
*/
702-
703703
static int mei_txe_write(struct mei_device *dev,
704-
struct mei_msg_hdr *header,
705-
const unsigned char *buf)
704+
const void *hdr, size_t hdr_len,
705+
const void *data, size_t data_len)
706706
{
707707
struct mei_txe_hw *hw = to_txe_hw(dev);
708708
unsigned long rem;
709-
unsigned long length;
710-
unsigned long i;
709+
const u32 *reg_buf;
711710
u32 slots = TXE_HBUF_DEPTH;
712-
u32 *reg_buf = (u32 *)buf;
713711
u32 dw_cnt;
712+
unsigned long i, j;
714713

715-
if (WARN_ON(!header || !buf))
714+
if (WARN_ON(!hdr || !data || hdr_len & 0x3))
716715
return -EINVAL;
717716

718-
length = header->length;
719-
720-
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
717+
dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM((struct mei_msg_hdr *)hdr));
721718

722-
dw_cnt = mei_data2slots(length);
719+
dw_cnt = mei_data2slots(hdr_len + data_len);
723720
if (dw_cnt > slots)
724721
return -EMSGSIZE;
725722

@@ -737,17 +734,20 @@ static int mei_txe_write(struct mei_device *dev,
737734
return -EAGAIN;
738735
}
739736

740-
mei_txe_input_payload_write(dev, 0, *((u32 *)header));
737+
reg_buf = hdr;
738+
for (i = 0; i < hdr_len / MEI_SLOT_SIZE; i++)
739+
mei_txe_input_payload_write(dev, i, reg_buf[i]);
741740

742-
for (i = 0; i < length / 4; i++)
743-
mei_txe_input_payload_write(dev, i + 1, reg_buf[i]);
741+
reg_buf = data;
742+
for (j = 0; j < data_len / MEI_SLOT_SIZE; j++)
743+
mei_txe_input_payload_write(dev, i + j, reg_buf[j]);
744744

745-
rem = length & 0x3;
745+
rem = data_len & 0x3;
746746
if (rem > 0) {
747747
u32 reg = 0;
748748

749-
memcpy(&reg, &buf[length - rem], rem);
750-
mei_txe_input_payload_write(dev, i + 1, reg);
749+
memcpy(&reg, (const u8 *)data + data_len - rem, rem);
750+
mei_txe_input_payload_write(dev, i + j, reg);
751751
}
752752

753753
/* after each write the whole buffer is consumed */

drivers/misc/mei/interrupt.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
173173
int slots;
174174
int ret;
175175

176-
msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_response));
176+
msg_slots = mei_hbm2slots(sizeof(struct hbm_client_connect_response));
177177
slots = mei_hbuf_empty_slots(dev);
178178
if (slots < 0)
179179
return -EOVERFLOW;
@@ -208,7 +208,7 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
208208
if (!list_empty(&cl->rd_pending))
209209
return 0;
210210

211-
msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
211+
msg_slots = mei_hbm2slots(sizeof(struct hbm_flow_control));
212212
slots = mei_hbuf_empty_slots(dev);
213213
if (slots < 0)
214214
return -EOVERFLOW;

0 commit comments

Comments
 (0)