提交 a4ff8e7a 编写于 作者: L Li Ming 提交者: Bjorn Helgaas

PCI/DOE: Fix maximum data object length miscalculation

Per PCIe r6.0, sec 6.30.1, a data object Length of 0x0 indicates 2^18
DWORDs (256K DW or 1MB) being transferred.  Adjust the value of data object
length for this case on both sending side and receiving side.

Don't bother checking whether Length is greater than SZ_1M because all
values of the 18-bit Length field are valid, and it is impossible to
represent anything larger than SZ_1M:

  0x00000    256K DW (1M bytes)
  0x00001       1 DW (4 bytes)
  ...
  0x3ffff  256K-1 DW (1M - 4 bytes)

[bhelgaas: commit log]
Link: https://lore.kernel.org/r/20221116015637.3299664-1-ming4.li@intel.com
Fixes: 9d24322e ("PCI/DOE: Add DOE mailbox support functions")
Signed-off-by: NLi Ming <ming4.li@intel.com>
Signed-off-by: NBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: NJonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: NLukas Wunner <lukas@wunner.de>
Cc: stable@vger.kernel.org	# v6.0+
上级 9abf2313
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
#define PCI_DOE_FLAG_CANCEL 0 #define PCI_DOE_FLAG_CANCEL 0
#define PCI_DOE_FLAG_DEAD 1 #define PCI_DOE_FLAG_DEAD 1
/* Max data object length is 2^18 dwords */
#define PCI_DOE_MAX_LENGTH (1 << 18)
/** /**
* struct pci_doe_mb - State for a single DOE mailbox * struct pci_doe_mb - State for a single DOE mailbox
* *
...@@ -107,6 +110,7 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb, ...@@ -107,6 +110,7 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb,
{ {
struct pci_dev *pdev = doe_mb->pdev; struct pci_dev *pdev = doe_mb->pdev;
int offset = doe_mb->cap_offset; int offset = doe_mb->cap_offset;
size_t length;
u32 val; u32 val;
int i; int i;
...@@ -123,15 +127,20 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb, ...@@ -123,15 +127,20 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb,
if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) if (FIELD_GET(PCI_DOE_STATUS_ERROR, val))
return -EIO; return -EIO;
/* Length is 2 DW of header + length of payload in DW */
length = 2 + task->request_pl_sz / sizeof(u32);
if (length > PCI_DOE_MAX_LENGTH)
return -EIO;
if (length == PCI_DOE_MAX_LENGTH)
length = 0;
/* Write DOE Header */ /* Write DOE Header */
val = FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_VID, task->prot.vid) | val = FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_VID, task->prot.vid) |
FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, task->prot.type); FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, task->prot.type);
pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, val); pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, val);
/* Length is 2 DW of header + length of payload in DW */
pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH,
2 + task->request_pl_sz / length));
sizeof(u32)));
for (i = 0; i < task->request_pl_sz / sizeof(u32); i++) for (i = 0; i < task->request_pl_sz / sizeof(u32); i++)
pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
task->request_pl[i]); task->request_pl[i]);
...@@ -178,7 +187,10 @@ static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *tas ...@@ -178,7 +187,10 @@ static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *tas
pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0); pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
length = FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, val); length = FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, val);
if (length > SZ_1M || length < 2) /* A value of 0x0 indicates max data object length */
if (!length)
length = PCI_DOE_MAX_LENGTH;
if (length < 2)
return -EIO; return -EIO;
/* First 2 dwords have already been read */ /* First 2 dwords have already been read */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册