Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mei: dma ring: implement transmit flow

Implement a circular buffer on allocated system memory. Read and write
indices are stored on the control block which is also shared between the
device and the host.
Two new functions are exported from the DMA module: mei_dma_ring_write,
and mei_dma_ring_empty_slots. The former simply copy a packet on the TX
DMA circular buffer and later, returns the number of empty slots on the
TX DMA circular buffer.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Tomas Winkler and committed by
Greg Kroah-Hartman
c30362cc 6316321f

+142 -13
+51 -13
drivers/misc/mei/client.c
··· 1558 1558 struct mei_msg_hdr mei_hdr; 1559 1559 size_t hdr_len = sizeof(mei_hdr); 1560 1560 size_t len; 1561 - size_t hbuf_len; 1561 + size_t hbuf_len, dr_len; 1562 1562 int hbuf_slots; 1563 + u32 dr_slots; 1564 + u32 dma_len; 1563 1565 int rets; 1564 1566 bool first_chunk; 1567 + const void *data; 1565 1568 1566 1569 if (WARN_ON(!cl || !cl->dev)) 1567 1570 return -ENODEV; ··· 1585 1582 } 1586 1583 1587 1584 len = buf->size - cb->buf_idx; 1585 + data = buf->data + cb->buf_idx; 1588 1586 hbuf_slots = mei_hbuf_empty_slots(dev); 1589 1587 if (hbuf_slots < 0) { 1590 1588 rets = -EOVERFLOW; ··· 1593 1589 } 1594 1590 1595 1591 hbuf_len = mei_slots2data(hbuf_slots); 1592 + dr_slots = mei_dma_ring_empty_slots(dev); 1593 + dr_len = mei_slots2data(dr_slots); 1596 1594 1597 1595 mei_msg_hdr_init(&mei_hdr, cb); 1598 1596 ··· 1605 1599 if (len + hdr_len <= hbuf_len) { 1606 1600 mei_hdr.length = len; 1607 1601 mei_hdr.msg_complete = 1; 1602 + } else if (dr_slots && hbuf_len >= hdr_len + sizeof(dma_len)) { 1603 + mei_hdr.dma_ring = 1; 1604 + if (len > dr_len) 1605 + len = dr_len; 1606 + else 1607 + mei_hdr.msg_complete = 1; 1608 + 1609 + mei_hdr.length = sizeof(dma_len); 1610 + dma_len = len; 1611 + data = &dma_len; 1608 1612 } else if ((u32)hbuf_slots == mei_hbuf_depth(dev)) { 1609 - mei_hdr.length = hbuf_len - hdr_len; 1613 + len = hbuf_len - hdr_len; 1614 + mei_hdr.length = len; 1610 1615 } else { 1611 1616 return 0; 1612 1617 } 1613 1618 1614 - cl_dbg(dev, cl, "buf: size = %zu idx = %zu\n", 1615 - cb->buf.size, cb->buf_idx); 1619 + if (mei_hdr.dma_ring) 1620 + mei_dma_ring_write(dev, buf->data + cb->buf_idx, len); 1616 1621 1617 - rets = mei_write_message(dev, &mei_hdr, hdr_len, 1618 - buf->data + cb->buf_idx, mei_hdr.length); 1622 + rets = mei_write_message(dev, &mei_hdr, hdr_len, data, mei_hdr.length); 1619 1623 if (rets) 1620 1624 goto err; 1621 1625 1622 1626 cl->status = 0; 1623 1627 cl->writing_state = MEI_WRITING; 1624 - cb->buf_idx += mei_hdr.length; 1628 + cb->buf_idx += len; 1625 1629 1626 1630 if (first_chunk) { 1627 1631 if (mei_cl_tx_flow_ctrl_creds_reduce(cl)) { ··· 1666 1650 struct mei_msg_data *buf; 1667 1651 struct mei_msg_hdr mei_hdr; 1668 1652 size_t hdr_len = sizeof(mei_hdr); 1669 - size_t len; 1670 - size_t hbuf_len; 1653 + size_t len, hbuf_len, dr_len; 1671 1654 int hbuf_slots; 1655 + u32 dr_slots; 1656 + u32 dma_len; 1672 1657 ssize_t rets; 1673 1658 bool blocking; 1659 + const void *data; 1674 1660 1675 1661 if (WARN_ON(!cl || !cl->dev)) 1676 1662 return -ENODEV; ··· 1684 1666 1685 1667 buf = &cb->buf; 1686 1668 len = buf->size; 1687 - blocking = cb->blocking; 1688 1669 1689 1670 cl_dbg(dev, cl, "len=%zd\n", len); 1671 + 1672 + blocking = cb->blocking; 1673 + data = buf->data; 1690 1674 1691 1675 rets = pm_runtime_get(dev->dev); 1692 1676 if (rets < 0 && rets != -EINPROGRESS) { ··· 1726 1706 } 1727 1707 1728 1708 hbuf_len = mei_slots2data(hbuf_slots); 1709 + dr_slots = mei_dma_ring_empty_slots(dev); 1710 + dr_len = mei_slots2data(dr_slots); 1729 1711 1730 1712 if (len + hdr_len <= hbuf_len) { 1731 1713 mei_hdr.length = len; 1732 1714 mei_hdr.msg_complete = 1; 1715 + } else if (dr_slots && hbuf_len >= hdr_len + sizeof(dma_len)) { 1716 + mei_hdr.dma_ring = 1; 1717 + if (len > dr_len) 1718 + len = dr_len; 1719 + else 1720 + mei_hdr.msg_complete = 1; 1721 + 1722 + mei_hdr.length = sizeof(dma_len); 1723 + dma_len = len; 1724 + data = &dma_len; 1733 1725 } else { 1734 - mei_hdr.length = hbuf_len - hdr_len; 1726 + len = hbuf_len - hdr_len; 1727 + mei_hdr.length = len; 1735 1728 } 1736 1729 1730 + if (mei_hdr.dma_ring) 1731 + mei_dma_ring_write(dev, buf->data, len); 1732 + 1737 1733 rets = mei_write_message(dev, &mei_hdr, hdr_len, 1738 - buf->data, mei_hdr.length); 1734 + data, mei_hdr.length); 1739 1735 if (rets) 1740 1736 goto err; 1741 1737 ··· 1760 1724 goto err; 1761 1725 1762 1726 cl->writing_state = MEI_WRITING; 1763 - cb->buf_idx = mei_hdr.length; 1727 + cb->buf_idx = len; 1728 + /* restore return value */ 1729 + len = buf->size; 1764 1730 1765 1731 out: 1766 1732 if (mei_hdr.msg_complete)
+89
drivers/misc/mei/dma-ring.c
··· 139 139 } 140 140 141 141 /** 142 + * mei_dma_copy_to() - copy to a buffer to the dma ring 143 + * @dev: mei device 144 + * @buf: data buffer 145 + * @offset: offset in slots. 146 + * @n: number of slots to copy. 147 + */ 148 + static size_t mei_dma_copy_to(struct mei_device *dev, unsigned char *buf, 149 + u32 offset, u32 n) 150 + { 151 + unsigned char *hbuf = dev->dr_dscr[DMA_DSCR_HOST].vaddr; 152 + 153 + size_t b_offset = offset << 2; 154 + size_t b_n = n << 2; 155 + 156 + memcpy(hbuf + b_offset, buf, b_n); 157 + 158 + return b_n; 159 + } 160 + 161 + /** 142 162 * mei_dma_ring_read() - read data from the ring 143 163 * @dev: mei device 144 164 * @buf: buffer to read into: may be NULL in case of droping the data. ··· 197 177 mei_dma_copy_from(dev, buf, rd_idx, rem); 198 178 out: 199 179 WRITE_ONCE(ctrl->dbuf_rd_idx, ctrl->dbuf_rd_idx + slots); 180 + } 181 + 182 + static inline u32 mei_dma_ring_hbuf_depth(struct mei_device *dev) 183 + { 184 + return dev->dr_dscr[DMA_DSCR_HOST].size >> 2; 185 + } 186 + 187 + /** 188 + * mei_dma_ring_empty_slots() - calaculate number of empty slots in dma ring 189 + * @dev: mei_device 190 + * 191 + * Return: number of empty slots 192 + */ 193 + u32 mei_dma_ring_empty_slots(struct mei_device *dev) 194 + { 195 + struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev); 196 + u32 wr_idx, rd_idx, hbuf_depth, empty; 197 + 198 + if (!mei_dma_ring_is_allocated(dev)) 199 + return 0; 200 + 201 + if (WARN_ON(!ctrl)) 202 + return 0; 203 + 204 + /* easier to work in slots */ 205 + hbuf_depth = mei_dma_ring_hbuf_depth(dev); 206 + rd_idx = READ_ONCE(ctrl->hbuf_rd_idx); 207 + wr_idx = READ_ONCE(ctrl->hbuf_wr_idx); 208 + 209 + if (rd_idx > wr_idx) 210 + empty = rd_idx - wr_idx; 211 + else 212 + empty = hbuf_depth - (wr_idx - rd_idx); 213 + 214 + return empty; 215 + } 216 + 217 + /** 218 + * mei_dma_ring_write - write data to dma ring host buffer 219 + * 220 + * @dev: mei_device 221 + * @buf: data will be written 222 + * @len: data length 223 + */ 224 + void mei_dma_ring_write(struct mei_device *dev, unsigned char *buf, u32 len) 225 + { 226 + struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev); 227 + u32 hbuf_depth; 228 + u32 wr_idx, rem, slots; 229 + 230 + if (WARN_ON(!ctrl)) 231 + return; 232 + 233 + dev_dbg(dev->dev, "writing to dma %u bytes\n", len); 234 + hbuf_depth = mei_dma_ring_hbuf_depth(dev); 235 + wr_idx = READ_ONCE(ctrl->hbuf_wr_idx) & (hbuf_depth - 1); 236 + slots = mei_data2slots(len); 237 + 238 + if (wr_idx + slots > hbuf_depth) { 239 + buf += mei_dma_copy_to(dev, buf, wr_idx, hbuf_depth - wr_idx); 240 + rem = slots - (hbuf_depth - wr_idx); 241 + wr_idx = 0; 242 + } else { 243 + rem = slots; 244 + } 245 + 246 + mei_dma_copy_to(dev, buf, wr_idx, rem); 247 + 248 + WRITE_ONCE(ctrl->hbuf_wr_idx, ctrl->hbuf_wr_idx + slots); 200 249 }
+2
drivers/misc/mei/mei_dev.h
··· 599 599 bool mei_dma_ring_is_allocated(struct mei_device *dev); 600 600 void mei_dma_ring_reset(struct mei_device *dev); 601 601 void mei_dma_ring_read(struct mei_device *dev, unsigned char *buf, u32 len); 602 + void mei_dma_ring_write(struct mei_device *dev, unsigned char *buf, u32 len); 603 + u32 mei_dma_ring_empty_slots(struct mei_device *dev); 602 604 603 605 /* 604 606 * MEI interrupt functions prototype