mps的全称是max-payload-size,它决定了每个TLP报文能够传输的最大净核字节数
mrrs的全称是max-read-request-size,它是指每个读请求能读到的最大字节数
这两个值可以通过lspci查到:如下所示
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd+ ExtTag+ PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 512 bytes
这两个值受命令行参数pcie_bus_config的影响,而pcie_bus_config 可以取下面四个值
enum pcie_bus_config_types {
PCIE_BUS_TUNE_OFF, /* Don't touch MPS at all */
PCIE_BUS_DEFAULT, /* Ensure MPS matches upstream bridge */
PCIE_BUS_SAFE, /* Use largest MPS boot-time devices support */
PCIE_BUS_PERFORMANCE, /* Use MPS and MRRS for best performance */
PCIE_BUS_PEER2PEER, /* Set MPS = 128 for all devices */
};
一般性能调优的话,可以添加命令行参数pci=PCIE_BUS_PERFORMANCE,如果不添加的话pcie_bus_config的默认值是PCIE_BUS_TUNE_OFF
void pcie_bus_configure_settings(struct pci_bus *bus)
{
u8 smpss = 0;
if (!bus->self)
return;
if (!pci_is_pcie(bus->self))
return;
/*
* FIXME - Peer to peer DMA is possible, though the endpoint would need
* to be aware of the MPS of the destination. To work around this,
* simply force the MPS of the entire system to the smallest possible.
*/
if (pcie_bus_config == PCIE_BUS_PEER2PEER)
smpss = 0;
if (pcie_bus_config == PCIE_BUS_SAFE) {
smpss = bus->self->pcie_mpss;
pcie_find_smpss(bus->self, &smpss);
pci_walk_bus(bus, pcie_find_smpss, &smpss);
}
pcie_bus_configure_set(bus->self, &smpss);
pci_walk_bus(bus, pcie_bus_configure_set, &smpss);
}
static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
{
int mps, orig_mps;
if (!pci_is_pcie(dev))
return 0;
if (pcie_bus_config == PCIE_BUS_TUNE_OFF ||
pcie_bus_config == PCIE_BUS_DEFAULT)
return 0;
mps = 128 << *(u8 *)data;
orig_mps = pcie_get_mps(dev);
#可以看到performance的话,kernel 会同时修改mps和mrrs
pcie_write_mps(dev, mps);
pcie_write_mrrs(dev);
pci_info(dev, "Max Payload Size set to %4d/%4d (was %4d), Max Read Rq %4d\n",
pcie_get_mps(dev), 128 << dev->pcie_mpss,
orig_mps, pcie_get_readrq(dev));
return 0;
}
当然有的驱动中可以单独调用pcie_set_readrq 来设置mrrs来增强性能
int pcie_set_readrq(struct pci_dev *dev, int rq)
{
u16 v;
if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
return -EINVAL;
/*
* If using the "performance" PCIe config, we clamp the read rq
* size to the max packet size to keep the host bridge from
* generating requests larger than we can cope with.
*/
if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
int mps = pcie_get_mps(dev);
if (mps < rq)
rq = mps;
}
v = (ffs(rq) - 8) << 12;
return pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_READRQ, v);
}