lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAGi-RUJCkEuqukEawjh_TqmWTYeYP7Qimaz3OTgpWnTZr9bZPA@mail.gmail.com>
Date:   Fri, 24 Jan 2020 00:10:09 +0200
From:   Ramon Fried <rfried.dev@...il.com>
To:     Kishon Vijay Abraham I <kishon@...com>
Cc:     Lorenzo Pieralisi <lorenzo.pieralisi@....com>,
        Andrew Murray <andrew.murray@....com>,
        Bjorn Helgaas <bhelgaas@...gle.com>,
        Gustavo Pimentel <gustavo.pimentel@...opsys.com>,
        Murali Karicheri <m-karicheri2@...com>,
        Jingoo Han <jingoohan1@...il.com>, linux-pci@...r.kernel.org,
        linux-kernel@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
        Xiaowei Bao <xiaowei.bao@....com>
Subject: Re: [PATCH 4/4] PCI: cadence: Add MSI-X support to Endpoint driver

On Wed, Dec 11, 2019 at 2:47 PM Kishon Vijay Abraham I <kishon@...com> wrote:
>
> From: Alan Douglas <adouglas@...ence.com>
>
> Implement ->set_msix() and ->get_msix() callback functions in order
> to configure MSIX capability in the PCIe endpoint controller.
>
> Add cdns_pcie_ep_send_msix_irq() to send MSIX interrupts to Host.
> cdns_pcie_ep_send_msix_irq() gets the MSIX table address (virtual
> address) from "struct cdns_pcie_epf" that gets initialized in
> ->set_bar() call back function.
>
> [kishon@...com: Re-implement MSIX support in accordance with the
>  re-designed core MSI-X interfaces]
> Signed-off-by: Kishon Vijay Abraham I <kishon@...com>
> Signed-off-by: Alan Douglas <adouglas@...ence.com>
> ---
>  .../pci/controller/cadence/pcie-cadence-ep.c  | 112 +++++++++++++++++-
>  drivers/pci/controller/cadence/pcie-cadence.h |  10 ++
>  2 files changed, 121 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
> index 088394b6be04..c3081e8e52a4 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
> +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
> @@ -52,6 +52,7 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
>                                 struct pci_epf_bar *epf_bar)
>  {
>         struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> +       struct cdns_pcie_epf *epf = &ep->epf[fn];
>         struct cdns_pcie *pcie = &ep->pcie;
>         dma_addr_t bar_phys = epf_bar->phys_addr;
>         enum pci_barno bar = epf_bar->barno;
> @@ -112,6 +113,8 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
>                 CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
>         cdns_pcie_writel(pcie, reg, cfg);
>
> +       epf->epf_bar[bar] = epf_bar;
> +
>         return 0;
>  }
>
> @@ -119,6 +122,7 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
>                                    struct pci_epf_bar *epf_bar)
>  {
>         struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> +       struct cdns_pcie_epf *epf = &ep->epf[fn];
>         struct cdns_pcie *pcie = &ep->pcie;
>         enum pci_barno bar = epf_bar->barno;
>         u32 reg, cfg, b, ctrl;
> @@ -140,6 +144,8 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
>
>         cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
>         cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
> +
> +       epf->epf_bar[bar] = NULL;
>  }
>
>  static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
> @@ -225,6 +231,50 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
>         return mme;
>  }
>
> +static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
> +{
> +       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> +       struct cdns_pcie *pcie = &ep->pcie;
> +       u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
> +       u32 val, reg;
> +
> +       reg = cap + PCI_MSIX_FLAGS;
> +       val = cdns_pcie_ep_fn_readw(pcie, func_no, reg);
> +       if (!(val & PCI_MSIX_FLAGS_ENABLE))
> +               return -EINVAL;
> +
> +       val &= PCI_MSIX_FLAGS_QSIZE;
> +
> +       return val;
> +}
> +
> +static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u16 interrupts,
> +                                enum pci_barno bir, u32 offset)
> +{
> +       struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
> +       struct cdns_pcie *pcie = &ep->pcie;
> +       u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
> +       u32 val, reg;
> +
> +       reg = cap + PCI_MSIX_FLAGS;
> +       val = cdns_pcie_ep_fn_readw(pcie, fn, reg);
> +       val &= ~PCI_MSIX_FLAGS_QSIZE;
> +       val |= interrupts;
> +       cdns_pcie_ep_fn_writew(pcie, fn, reg, val);
> +
> +       /* Set MSIX BAR and offset */
> +       reg = cap + PCI_MSIX_TABLE;
> +       val = offset | bir;
> +       cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
> +
> +       /* Set PBA BAR and offset.  BAR must match MSIX BAR */
> +       reg = cap + PCI_MSIX_PBA;
> +       val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
> +       cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
> +
> +       return 0;
> +}
> +
>  static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
>                                      u8 intx, bool is_asserted)
>  {
> @@ -331,6 +381,56 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
>         return 0;
>  }
>
> +static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn,
> +                                     u16 interrupt_num)
> +{
> +       u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
> +       u32 tbl_offset, msg_data, reg, vec_ctrl;
> +       struct cdns_pcie *pcie = &ep->pcie;
> +       struct pci_epf_msix_tbl *msix_tbl;
> +       struct pci_epf_bar *epf_bar;
> +       struct cdns_pcie_epf *epf;
> +       u64 pci_addr_mask = 0xff;
> +       u64 msg_addr;
> +       u16 flags;
> +       u8 bir;
> +
> +       /* Check whether the MSI-X feature has been enabled by the PCI host. */
> +       flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSIX_FLAGS);
> +       if (!(flags & PCI_MSIX_FLAGS_ENABLE))
> +               return -EINVAL;
> +
> +       reg = cap + PCI_MSIX_TABLE;
> +       tbl_offset = cdns_pcie_ep_fn_readl(pcie, fn, reg);
> +       bir = tbl_offset & PCI_MSIX_TABLE_BIR;
> +       tbl_offset &= PCI_MSIX_TABLE_OFFSET;
> +
> +       epf = &ep->epf[fn];
> +       epf_bar = epf->epf_bar[bir];
> +       msix_tbl = epf_bar->addr;
> +       msix_tbl = (struct pci_epf_msix_tbl *)((char *)msix_tbl + tbl_offset);
> +
> +       msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
> +       msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
> +       vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl;
> +
> +       /* Set the outbound region if needed. */
> +       if (unlikely(ep->irq_pci_addr != (msg_addr & ~pci_addr_mask) ||
I'm not sure about this _unlikely_, because unlike MSI, msg_addr will
be different for every vector.
It's interesting if safe to assume that host will allocate all message
address in linear fashion,
in that case maybe it's wiser to map all the the area at once and just
offset into it.

Thanks,
Ramon.

> +                    ep->irq_pci_fn != fn)) {
> +               /* First region was reserved for IRQ writes. */
> +               cdns_pcie_set_outbound_region(pcie, fn, 0,
> +                                             false,
> +                                             ep->irq_phys_addr,
> +                                             msg_addr & ~pci_addr_mask,
> +                                             pci_addr_mask + 1);
> +               ep->irq_pci_addr = (msg_addr & ~pci_addr_mask);
> +               ep->irq_pci_fn = fn;
> +       }
> +       writel(msg_data, ep->irq_cpu_addr + (msg_addr & pci_addr_mask));
> +
> +       return 0;
> +}
> +
>  static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
>                                   enum pci_epc_irq_type type,
>                                   u16 interrupt_num)
> @@ -344,6 +444,9 @@ static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
>         case PCI_EPC_IRQ_MSI:
>                 return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
>
> +       case PCI_EPC_IRQ_MSIX:
> +               return cdns_pcie_ep_send_msix_irq(ep, fn, interrupt_num);
> +
>         default:
>                 break;
>         }
> @@ -381,7 +484,7 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
>  static const struct pci_epc_features cdns_pcie_epc_features = {
>         .linkup_notifier = false,
>         .msi_capable = true,
> -       .msix_capable = false,
> +       .msix_capable = true,
>  };
>
>  static const struct pci_epc_features*
> @@ -398,6 +501,8 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = {
>         .unmap_addr     = cdns_pcie_ep_unmap_addr,
>         .set_msi        = cdns_pcie_ep_set_msi,
>         .get_msi        = cdns_pcie_ep_get_msi,
> +       .set_msix       = cdns_pcie_ep_set_msix,
> +       .get_msix       = cdns_pcie_ep_get_msix,
>         .raise_irq      = cdns_pcie_ep_raise_irq,
>         .start          = cdns_pcie_ep_start,
>         .get_features   = cdns_pcie_ep_get_features,
> @@ -457,6 +562,11 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
>         if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0)
>                 epc->max_functions = 1;
>
> +       ep->epf = devm_kcalloc(dev, epc->max_functions, sizeof(*ep->epf),
> +                              GFP_KERNEL);
> +       if (!ep->epf)
> +               return -ENOMEM;
> +
>         ret = pci_epc_mem_init(epc, pcie->mem_res->start,
>                                resource_size(pcie->mem_res));
>         if (ret < 0) {
> diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
> index ffa8b9f78ff8..207d6ba03f70 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence.h
> +++ b/drivers/pci/controller/cadence/pcie-cadence.h
> @@ -99,6 +99,7 @@
>  #define CDNS_PCIE_EP_FUNC_BASE(fn)     (((fn) << 12) & GENMASK(19, 12))
>
>  #define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET       0x90
> +#define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET      0xb0
>
>  /*
>   * Root Port Registers (PCI configuration space for the root port function)
> @@ -281,6 +282,14 @@ struct cdns_pcie_rc {
>         u16                     device_id;
>  };
>
> +/**
> + * struct cdns_pcie_epf - Structure to hold info about endpoint function
> + * @epf_bar: reference to the pci_epf_bar for the six Base Address Registers
> + */
> +struct cdns_pcie_epf {
> +       struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
> +};
> +
>  /**
>   * struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
>   * @pcie: Cadence PCIe controller
> @@ -308,6 +317,7 @@ struct cdns_pcie_ep {
>         u64                     irq_pci_addr;
>         u8                      irq_pci_fn;
>         u8                      irq_pending;
> +       struct cdns_pcie_epf    *epf;
>  };
>
>
> --
> 2.17.1
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ