mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-31 16:38:12 +00:00
PCI: endpoint: Fix ->set_msix() to take BIR and offset as arguments
commit8963106eab
("PCI: endpoint: Add MSI-X interfaces") while adding support to raise MSI-X interrupts from endpoint didn't include BAR Indicator register (BIR) configuration and MSI-X table offset as arguments in pci_epc_set_msix(). This would result in endpoint controller register using random BAR indicator register, the memory for which might not be allocated by the endpoint function driver. Add BAR indicator register and MSI-X table offset as arguments in pci_epc_set_msix() and allocate space for MSI-X table and pending bit array (PBA) in pci-epf-test endpoint function driver. Fixes:8963106eab
("PCI: endpoint: Add MSI-X interfaces") Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
This commit is contained in:
parent
cf376b4b59
commit
83153d9f36
4 changed files with 49 additions and 13 deletions
|
@ -278,7 +278,8 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
|
|||
return val;
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
|
||||
static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts,
|
||||
enum pci_barno bir, u32 offset)
|
||||
{
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
@ -287,12 +288,22 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
|
|||
if (!ep->msix_cap)
|
||||
return -EINVAL;
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_FLAGS;
|
||||
val = dw_pcie_readw_dbi(pci, reg);
|
||||
val &= ~PCI_MSIX_FLAGS_QSIZE;
|
||||
val |= interrupts;
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
dw_pcie_writew_dbi(pci, reg, val);
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_TABLE;
|
||||
val = offset | bir;
|
||||
dw_pcie_writel_dbi(pci, reg, val);
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_PBA;
|
||||
val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
|
||||
dw_pcie_writel_dbi(pci, reg, val);
|
||||
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -50,6 +50,7 @@ struct pci_epf_test {
|
|||
void *reg[PCI_STD_NUM_BARS];
|
||||
struct pci_epf *epf;
|
||||
enum pci_barno test_reg_bar;
|
||||
size_t msix_table_offset;
|
||||
struct delayed_work cmd_handler;
|
||||
struct dma_chan *dma_chan;
|
||||
struct completion transfer_complete;
|
||||
|
@ -659,6 +660,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
|
|||
|
||||
static int pci_epf_test_core_init(struct pci_epf *epf)
|
||||
{
|
||||
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
||||
struct pci_epf_header *header = epf->header;
|
||||
const struct pci_epc_features *epc_features;
|
||||
struct pci_epc *epc = epf->epc;
|
||||
|
@ -692,7 +694,9 @@ static int pci_epf_test_core_init(struct pci_epf *epf)
|
|||
}
|
||||
|
||||
if (msix_capable) {
|
||||
ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts);
|
||||
ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts,
|
||||
epf_test->test_reg_bar,
|
||||
epf_test->msix_table_offset);
|
||||
if (ret) {
|
||||
dev_err(dev, "MSI-X configuration failed\n");
|
||||
return ret;
|
||||
|
@ -734,6 +738,10 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
|
|||
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
||||
struct device *dev = &epf->dev;
|
||||
struct pci_epf_bar *epf_bar;
|
||||
size_t msix_table_size = 0;
|
||||
size_t test_reg_bar_size;
|
||||
size_t pba_size = 0;
|
||||
bool msix_capable;
|
||||
void *base;
|
||||
int bar, add;
|
||||
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
||||
|
@ -742,13 +750,25 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
|
|||
|
||||
epc_features = epf_test->epc_features;
|
||||
|
||||
if (epc_features->bar_fixed_size[test_reg_bar])
|
||||
test_reg_size = bar_size[test_reg_bar];
|
||||
else
|
||||
test_reg_size = sizeof(struct pci_epf_test_reg);
|
||||
test_reg_bar_size = ALIGN(sizeof(struct pci_epf_test_reg), 128);
|
||||
|
||||
base = pci_epf_alloc_space(epf, test_reg_size,
|
||||
test_reg_bar, epc_features->align);
|
||||
msix_capable = epc_features->msix_capable;
|
||||
if (msix_capable) {
|
||||
msix_table_size = PCI_MSIX_ENTRY_SIZE * epf->msix_interrupts;
|
||||
epf_test->msix_table_offset = test_reg_bar_size;
|
||||
/* Align to QWORD or 8 Bytes */
|
||||
pba_size = ALIGN(DIV_ROUND_UP(epf->msix_interrupts, 8), 8);
|
||||
}
|
||||
test_reg_size = test_reg_bar_size + msix_table_size + pba_size;
|
||||
|
||||
if (epc_features->bar_fixed_size[test_reg_bar]) {
|
||||
if (test_reg_size > bar_size[test_reg_bar])
|
||||
return -ENOMEM;
|
||||
test_reg_size = bar_size[test_reg_bar];
|
||||
}
|
||||
|
||||
base = pci_epf_alloc_space(epf, test_reg_size, test_reg_bar,
|
||||
epc_features->align);
|
||||
if (!base) {
|
||||
dev_err(dev, "Failed to allocated register space\n");
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -297,10 +297,13 @@ EXPORT_SYMBOL_GPL(pci_epc_get_msix);
|
|||
* @epc: the EPC device on which MSI-X has to be configured
|
||||
* @func_no: the endpoint function number in the EPC device
|
||||
* @interrupts: number of MSI-X interrupts required by the EPF
|
||||
* @bir: BAR where the MSI-X table resides
|
||||
* @offset: Offset pointing to the start of MSI-X table
|
||||
*
|
||||
* Invoke to set the required number of MSI-X interrupts.
|
||||
*/
|
||||
int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
|
||||
int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts,
|
||||
enum pci_barno bir, u32 offset)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -312,7 +315,7 @@ int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts)
|
|||
return 0;
|
||||
|
||||
mutex_lock(&epc->lock);
|
||||
ret = epc->ops->set_msix(epc, func_no, interrupts - 1);
|
||||
ret = epc->ops->set_msix(epc, func_no, interrupts - 1, bir, offset);
|
||||
mutex_unlock(&epc->lock);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -53,7 +53,8 @@ struct pci_epc_ops {
|
|||
phys_addr_t addr);
|
||||
int (*set_msi)(struct pci_epc *epc, u8 func_no, u8 interrupts);
|
||||
int (*get_msi)(struct pci_epc *epc, u8 func_no);
|
||||
int (*set_msix)(struct pci_epc *epc, u8 func_no, u16 interrupts);
|
||||
int (*set_msix)(struct pci_epc *epc, u8 func_no, u16 interrupts,
|
||||
enum pci_barno, u32 offset);
|
||||
int (*get_msix)(struct pci_epc *epc, u8 func_no);
|
||||
int (*raise_irq)(struct pci_epc *epc, u8 func_no,
|
||||
enum pci_epc_irq_type type, u16 interrupt_num);
|
||||
|
@ -180,7 +181,8 @@ void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no,
|
|||
phys_addr_t phys_addr);
|
||||
int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts);
|
||||
int pci_epc_get_msi(struct pci_epc *epc, u8 func_no);
|
||||
int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts);
|
||||
int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts,
|
||||
enum pci_barno, u32 offset);
|
||||
int pci_epc_get_msix(struct pci_epc *epc, u8 func_no);
|
||||
int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no,
|
||||
enum pci_epc_irq_type type, u16 interrupt_num);
|
||||
|
|
Loading…
Reference in a new issue