1*7e98d785SM Chetan Kumar // SPDX-License-Identifier: GPL-2.0-only 2*7e98d785SM Chetan Kumar /* 3*7e98d785SM Chetan Kumar * Copyright (C) 2020-21 Intel Corporation. 4*7e98d785SM Chetan Kumar */ 5*7e98d785SM Chetan Kumar 6*7e98d785SM Chetan Kumar #include <linux/acpi.h> 7*7e98d785SM Chetan Kumar #include <linux/bitfield.h> 8*7e98d785SM Chetan Kumar #include <linux/module.h> 9*7e98d785SM Chetan Kumar #include <net/rtnetlink.h> 10*7e98d785SM Chetan Kumar 11*7e98d785SM Chetan Kumar #include "iosm_ipc_imem.h" 12*7e98d785SM Chetan Kumar #include "iosm_ipc_pcie.h" 13*7e98d785SM Chetan Kumar #include "iosm_ipc_protocol.h" 14*7e98d785SM Chetan Kumar 15*7e98d785SM Chetan Kumar MODULE_DESCRIPTION("IOSM Driver"); 16*7e98d785SM Chetan Kumar MODULE_LICENSE("GPL v2"); 17*7e98d785SM Chetan Kumar 18*7e98d785SM Chetan Kumar /* WWAN GUID */ 19*7e98d785SM Chetan Kumar static guid_t wwan_acpi_guid = GUID_INIT(0xbad01b75, 0x22a8, 0x4f48, 0x87, 0x92, 20*7e98d785SM Chetan Kumar 0xbd, 0xde, 0x94, 0x67, 0x74, 0x7d); 21*7e98d785SM Chetan Kumar 22*7e98d785SM Chetan Kumar static void ipc_pcie_resources_release(struct iosm_pcie *ipc_pcie) 23*7e98d785SM Chetan Kumar { 24*7e98d785SM Chetan Kumar /* Free the MSI resources. */ 25*7e98d785SM Chetan Kumar ipc_release_irq(ipc_pcie); 26*7e98d785SM Chetan Kumar 27*7e98d785SM Chetan Kumar /* Free mapped doorbell scratchpad bus memory into CPU space. */ 28*7e98d785SM Chetan Kumar iounmap(ipc_pcie->scratchpad); 29*7e98d785SM Chetan Kumar 30*7e98d785SM Chetan Kumar /* Free mapped IPC_REGS bus memory into CPU space. */ 31*7e98d785SM Chetan Kumar iounmap(ipc_pcie->ipc_regs); 32*7e98d785SM Chetan Kumar 33*7e98d785SM Chetan Kumar /* Releases all PCI I/O and memory resources previously reserved by a 34*7e98d785SM Chetan Kumar * successful call to pci_request_regions. Call this function only 35*7e98d785SM Chetan Kumar * after all use of the PCI regions has ceased. 36*7e98d785SM Chetan Kumar */ 37*7e98d785SM Chetan Kumar pci_release_regions(ipc_pcie->pci); 38*7e98d785SM Chetan Kumar } 39*7e98d785SM Chetan Kumar 40*7e98d785SM Chetan Kumar static void ipc_pcie_cleanup(struct iosm_pcie *ipc_pcie) 41*7e98d785SM Chetan Kumar { 42*7e98d785SM Chetan Kumar /* Free the shared memory resources. */ 43*7e98d785SM Chetan Kumar ipc_imem_cleanup(ipc_pcie->imem); 44*7e98d785SM Chetan Kumar 45*7e98d785SM Chetan Kumar ipc_pcie_resources_release(ipc_pcie); 46*7e98d785SM Chetan Kumar 47*7e98d785SM Chetan Kumar /* Signal to the system that the PCI device is not in use. */ 48*7e98d785SM Chetan Kumar pci_disable_device(ipc_pcie->pci); 49*7e98d785SM Chetan Kumar } 50*7e98d785SM Chetan Kumar 51*7e98d785SM Chetan Kumar static void ipc_pcie_deinit(struct iosm_pcie *ipc_pcie) 52*7e98d785SM Chetan Kumar { 53*7e98d785SM Chetan Kumar kfree(ipc_pcie->imem); 54*7e98d785SM Chetan Kumar kfree(ipc_pcie); 55*7e98d785SM Chetan Kumar } 56*7e98d785SM Chetan Kumar 57*7e98d785SM Chetan Kumar static void ipc_pcie_remove(struct pci_dev *pci) 58*7e98d785SM Chetan Kumar { 59*7e98d785SM Chetan Kumar struct iosm_pcie *ipc_pcie = pci_get_drvdata(pci); 60*7e98d785SM Chetan Kumar 61*7e98d785SM Chetan Kumar ipc_pcie_cleanup(ipc_pcie); 62*7e98d785SM Chetan Kumar 63*7e98d785SM Chetan Kumar ipc_pcie_deinit(ipc_pcie); 64*7e98d785SM Chetan Kumar } 65*7e98d785SM Chetan Kumar 66*7e98d785SM Chetan Kumar static int ipc_pcie_resources_request(struct iosm_pcie *ipc_pcie) 67*7e98d785SM Chetan Kumar { 68*7e98d785SM Chetan Kumar struct pci_dev *pci = ipc_pcie->pci; 69*7e98d785SM Chetan Kumar u32 cap = 0; 70*7e98d785SM Chetan Kumar u32 ret; 71*7e98d785SM Chetan Kumar 72*7e98d785SM Chetan Kumar /* Reserved PCI I/O and memory resources. 73*7e98d785SM Chetan Kumar * Mark all PCI regions associated with PCI device pci as 74*7e98d785SM Chetan Kumar * being reserved by owner IOSM_IPC. 75*7e98d785SM Chetan Kumar */ 76*7e98d785SM Chetan Kumar ret = pci_request_regions(pci, "IOSM_IPC"); 77*7e98d785SM Chetan Kumar if (ret) { 78*7e98d785SM Chetan Kumar dev_err(ipc_pcie->dev, "failed pci request regions"); 79*7e98d785SM Chetan Kumar goto pci_request_region_fail; 80*7e98d785SM Chetan Kumar } 81*7e98d785SM Chetan Kumar 82*7e98d785SM Chetan Kumar /* Reserve the doorbell IPC REGS memory resources. 83*7e98d785SM Chetan Kumar * Remap the memory into CPU space. Arrange for the physical address 84*7e98d785SM Chetan Kumar * (BAR) to be visible from this driver. 85*7e98d785SM Chetan Kumar * pci_ioremap_bar() ensures that the memory is marked uncachable. 86*7e98d785SM Chetan Kumar */ 87*7e98d785SM Chetan Kumar ipc_pcie->ipc_regs = pci_ioremap_bar(pci, ipc_pcie->ipc_regs_bar_nr); 88*7e98d785SM Chetan Kumar 89*7e98d785SM Chetan Kumar if (!ipc_pcie->ipc_regs) { 90*7e98d785SM Chetan Kumar dev_err(ipc_pcie->dev, "IPC REGS ioremap error"); 91*7e98d785SM Chetan Kumar ret = -EBUSY; 92*7e98d785SM Chetan Kumar goto ipc_regs_remap_fail; 93*7e98d785SM Chetan Kumar } 94*7e98d785SM Chetan Kumar 95*7e98d785SM Chetan Kumar /* Reserve the MMIO scratchpad memory resources. 96*7e98d785SM Chetan Kumar * Remap the memory into CPU space. Arrange for the physical address 97*7e98d785SM Chetan Kumar * (BAR) to be visible from this driver. 98*7e98d785SM Chetan Kumar * pci_ioremap_bar() ensures that the memory is marked uncachable. 99*7e98d785SM Chetan Kumar */ 100*7e98d785SM Chetan Kumar ipc_pcie->scratchpad = 101*7e98d785SM Chetan Kumar pci_ioremap_bar(pci, ipc_pcie->scratchpad_bar_nr); 102*7e98d785SM Chetan Kumar 103*7e98d785SM Chetan Kumar if (!ipc_pcie->scratchpad) { 104*7e98d785SM Chetan Kumar dev_err(ipc_pcie->dev, "doorbell scratchpad ioremap error"); 105*7e98d785SM Chetan Kumar ret = -EBUSY; 106*7e98d785SM Chetan Kumar goto scratch_remap_fail; 107*7e98d785SM Chetan Kumar } 108*7e98d785SM Chetan Kumar 109*7e98d785SM Chetan Kumar /* Install the irq handler triggered by CP. */ 110*7e98d785SM Chetan Kumar ret = ipc_acquire_irq(ipc_pcie); 111*7e98d785SM Chetan Kumar if (ret) { 112*7e98d785SM Chetan Kumar dev_err(ipc_pcie->dev, "acquiring MSI irq failed!"); 113*7e98d785SM Chetan Kumar goto irq_acquire_fail; 114*7e98d785SM Chetan Kumar } 115*7e98d785SM Chetan Kumar 116*7e98d785SM Chetan Kumar /* Enable bus-mastering for the IOSM IPC device. */ 117*7e98d785SM Chetan Kumar pci_set_master(pci); 118*7e98d785SM Chetan Kumar 119*7e98d785SM Chetan Kumar /* Enable LTR if possible 120*7e98d785SM Chetan Kumar * This is needed for L1.2! 121*7e98d785SM Chetan Kumar */ 122*7e98d785SM Chetan Kumar pcie_capability_read_dword(ipc_pcie->pci, PCI_EXP_DEVCAP2, &cap); 123*7e98d785SM Chetan Kumar if (cap & PCI_EXP_DEVCAP2_LTR) 124*7e98d785SM Chetan Kumar pcie_capability_set_word(ipc_pcie->pci, PCI_EXP_DEVCTL2, 125*7e98d785SM Chetan Kumar PCI_EXP_DEVCTL2_LTR_EN); 126*7e98d785SM Chetan Kumar 127*7e98d785SM Chetan Kumar dev_dbg(ipc_pcie->dev, "link between AP and CP is fully on"); 128*7e98d785SM Chetan Kumar 129*7e98d785SM Chetan Kumar return ret; 130*7e98d785SM Chetan Kumar 131*7e98d785SM Chetan Kumar irq_acquire_fail: 132*7e98d785SM Chetan Kumar iounmap(ipc_pcie->scratchpad); 133*7e98d785SM Chetan Kumar scratch_remap_fail: 134*7e98d785SM Chetan Kumar iounmap(ipc_pcie->ipc_regs); 135*7e98d785SM Chetan Kumar ipc_regs_remap_fail: 136*7e98d785SM Chetan Kumar pci_release_regions(pci); 137*7e98d785SM Chetan Kumar pci_request_region_fail: 138*7e98d785SM Chetan Kumar return ret; 139*7e98d785SM Chetan Kumar } 140*7e98d785SM Chetan Kumar 141*7e98d785SM Chetan Kumar bool ipc_pcie_check_aspm_enabled(struct iosm_pcie *ipc_pcie, 142*7e98d785SM Chetan Kumar bool parent) 143*7e98d785SM Chetan Kumar { 144*7e98d785SM Chetan Kumar struct pci_dev *pdev; 145*7e98d785SM Chetan Kumar u16 value = 0; 146*7e98d785SM Chetan Kumar u32 enabled; 147*7e98d785SM Chetan Kumar 148*7e98d785SM Chetan Kumar if (parent) 149*7e98d785SM Chetan Kumar pdev = ipc_pcie->pci->bus->self; 150*7e98d785SM Chetan Kumar else 151*7e98d785SM Chetan Kumar pdev = ipc_pcie->pci; 152*7e98d785SM Chetan Kumar 153*7e98d785SM Chetan Kumar pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &value); 154*7e98d785SM Chetan Kumar enabled = value & PCI_EXP_LNKCTL_ASPMC; 155*7e98d785SM Chetan Kumar dev_dbg(ipc_pcie->dev, "ASPM L1: 0x%04X 0x%03X", pdev->device, value); 156*7e98d785SM Chetan Kumar 157*7e98d785SM Chetan Kumar return (enabled == PCI_EXP_LNKCTL_ASPM_L1 || 158*7e98d785SM Chetan Kumar enabled == PCI_EXP_LNKCTL_ASPMC); 159*7e98d785SM Chetan Kumar } 160*7e98d785SM Chetan Kumar 161*7e98d785SM Chetan Kumar bool ipc_pcie_check_data_link_active(struct iosm_pcie *ipc_pcie) 162*7e98d785SM Chetan Kumar { 163*7e98d785SM Chetan Kumar struct pci_dev *parent; 164*7e98d785SM Chetan Kumar u16 link_status = 0; 165*7e98d785SM Chetan Kumar 166*7e98d785SM Chetan Kumar if (!ipc_pcie->pci->bus || !ipc_pcie->pci->bus->self) { 167*7e98d785SM Chetan Kumar dev_err(ipc_pcie->dev, "root port not found"); 168*7e98d785SM Chetan Kumar return false; 169*7e98d785SM Chetan Kumar } 170*7e98d785SM Chetan Kumar 171*7e98d785SM Chetan Kumar parent = ipc_pcie->pci->bus->self; 172*7e98d785SM Chetan Kumar 173*7e98d785SM Chetan Kumar pcie_capability_read_word(parent, PCI_EXP_LNKSTA, &link_status); 174*7e98d785SM Chetan Kumar dev_dbg(ipc_pcie->dev, "Link status: 0x%04X", link_status); 175*7e98d785SM Chetan Kumar 176*7e98d785SM Chetan Kumar return link_status & PCI_EXP_LNKSTA_DLLLA; 177*7e98d785SM Chetan Kumar } 178*7e98d785SM Chetan Kumar 179*7e98d785SM Chetan Kumar static bool ipc_pcie_check_aspm_supported(struct iosm_pcie *ipc_pcie, 180*7e98d785SM Chetan Kumar bool parent) 181*7e98d785SM Chetan Kumar { 182*7e98d785SM Chetan Kumar struct pci_dev *pdev; 183*7e98d785SM Chetan Kumar u32 support; 184*7e98d785SM Chetan Kumar u32 cap = 0; 185*7e98d785SM Chetan Kumar 186*7e98d785SM Chetan Kumar if (parent) 187*7e98d785SM Chetan Kumar pdev = ipc_pcie->pci->bus->self; 188*7e98d785SM Chetan Kumar else 189*7e98d785SM Chetan Kumar pdev = ipc_pcie->pci; 190*7e98d785SM Chetan Kumar pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &cap); 191*7e98d785SM Chetan Kumar support = u32_get_bits(cap, PCI_EXP_LNKCAP_ASPMS); 192*7e98d785SM Chetan Kumar if (support < PCI_EXP_LNKCTL_ASPM_L1) { 193*7e98d785SM Chetan Kumar dev_dbg(ipc_pcie->dev, "ASPM L1 not supported: 0x%04X", 194*7e98d785SM Chetan Kumar pdev->device); 195*7e98d785SM Chetan Kumar return false; 196*7e98d785SM Chetan Kumar } 197*7e98d785SM Chetan Kumar return true; 198*7e98d785SM Chetan Kumar } 199*7e98d785SM Chetan Kumar 200*7e98d785SM Chetan Kumar void ipc_pcie_config_aspm(struct iosm_pcie *ipc_pcie) 201*7e98d785SM Chetan Kumar { 202*7e98d785SM Chetan Kumar bool parent_aspm_enabled, dev_aspm_enabled; 203*7e98d785SM Chetan Kumar 204*7e98d785SM Chetan Kumar /* check if both root port and child supports ASPM L1 */ 205*7e98d785SM Chetan Kumar if (!ipc_pcie_check_aspm_supported(ipc_pcie, true) || 206*7e98d785SM Chetan Kumar !ipc_pcie_check_aspm_supported(ipc_pcie, false)) 207*7e98d785SM Chetan Kumar return; 208*7e98d785SM Chetan Kumar 209*7e98d785SM Chetan Kumar parent_aspm_enabled = ipc_pcie_check_aspm_enabled(ipc_pcie, true); 210*7e98d785SM Chetan Kumar dev_aspm_enabled = ipc_pcie_check_aspm_enabled(ipc_pcie, false); 211*7e98d785SM Chetan Kumar 212*7e98d785SM Chetan Kumar dev_dbg(ipc_pcie->dev, "ASPM parent: %s device: %s", 213*7e98d785SM Chetan Kumar parent_aspm_enabled ? "Enabled" : "Disabled", 214*7e98d785SM Chetan Kumar dev_aspm_enabled ? "Enabled" : "Disabled"); 215*7e98d785SM Chetan Kumar } 216*7e98d785SM Chetan Kumar 217*7e98d785SM Chetan Kumar /* Initializes PCIe endpoint configuration */ 218*7e98d785SM Chetan Kumar static void ipc_pcie_config_init(struct iosm_pcie *ipc_pcie) 219*7e98d785SM Chetan Kumar { 220*7e98d785SM Chetan Kumar /* BAR0 is used for doorbell */ 221*7e98d785SM Chetan Kumar ipc_pcie->ipc_regs_bar_nr = IPC_DOORBELL_BAR0; 222*7e98d785SM Chetan Kumar 223*7e98d785SM Chetan Kumar /* update HW configuration */ 224*7e98d785SM Chetan Kumar ipc_pcie->scratchpad_bar_nr = IPC_SCRATCHPAD_BAR2; 225*7e98d785SM Chetan Kumar ipc_pcie->doorbell_reg_offset = IPC_DOORBELL_CH_OFFSET; 226*7e98d785SM Chetan Kumar ipc_pcie->doorbell_write = IPC_WRITE_PTR_REG_0; 227*7e98d785SM Chetan Kumar ipc_pcie->doorbell_capture = IPC_CAPTURE_PTR_REG_0; 228*7e98d785SM Chetan Kumar } 229*7e98d785SM Chetan Kumar 230*7e98d785SM Chetan Kumar /* This will read the BIOS WWAN RTD3 settings: 231*7e98d785SM Chetan Kumar * D0L1.2/D3L2/Disabled 232*7e98d785SM Chetan Kumar */ 233*7e98d785SM Chetan Kumar static enum ipc_pcie_sleep_state ipc_pcie_read_bios_cfg(struct device *dev) 234*7e98d785SM Chetan Kumar { 235*7e98d785SM Chetan Kumar union acpi_object *object; 236*7e98d785SM Chetan Kumar acpi_handle handle_acpi; 237*7e98d785SM Chetan Kumar 238*7e98d785SM Chetan Kumar handle_acpi = ACPI_HANDLE(dev); 239*7e98d785SM Chetan Kumar if (!handle_acpi) { 240*7e98d785SM Chetan Kumar pr_debug("pci device is NOT ACPI supporting device\n"); 241*7e98d785SM Chetan Kumar goto default_ret; 242*7e98d785SM Chetan Kumar } 243*7e98d785SM Chetan Kumar 244*7e98d785SM Chetan Kumar object = acpi_evaluate_dsm(handle_acpi, &wwan_acpi_guid, 0, 3, NULL); 245*7e98d785SM Chetan Kumar 246*7e98d785SM Chetan Kumar if (object && object->integer.value == 3) 247*7e98d785SM Chetan Kumar return IPC_PCIE_D3L2; 248*7e98d785SM Chetan Kumar 249*7e98d785SM Chetan Kumar default_ret: 250*7e98d785SM Chetan Kumar return IPC_PCIE_D0L12; 251*7e98d785SM Chetan Kumar } 252*7e98d785SM Chetan Kumar 253*7e98d785SM Chetan Kumar static int ipc_pcie_probe(struct pci_dev *pci, 254*7e98d785SM Chetan Kumar const struct pci_device_id *pci_id) 255*7e98d785SM Chetan Kumar { 256*7e98d785SM Chetan Kumar struct iosm_pcie *ipc_pcie = kzalloc(sizeof(*ipc_pcie), GFP_KERNEL); 257*7e98d785SM Chetan Kumar 258*7e98d785SM Chetan Kumar pr_debug("Probing device 0x%X from the vendor 0x%X", pci_id->device, 259*7e98d785SM Chetan Kumar pci_id->vendor); 260*7e98d785SM Chetan Kumar 261*7e98d785SM Chetan Kumar if (!ipc_pcie) 262*7e98d785SM Chetan Kumar goto ret_fail; 263*7e98d785SM Chetan Kumar 264*7e98d785SM Chetan Kumar /* Initialize ipc dbg component for the PCIe device */ 265*7e98d785SM Chetan Kumar ipc_pcie->dev = &pci->dev; 266*7e98d785SM Chetan Kumar 267*7e98d785SM Chetan Kumar /* Set the driver specific data. */ 268*7e98d785SM Chetan Kumar pci_set_drvdata(pci, ipc_pcie); 269*7e98d785SM Chetan Kumar 270*7e98d785SM Chetan Kumar /* Save the address of the PCI device configuration. */ 271*7e98d785SM Chetan Kumar ipc_pcie->pci = pci; 272*7e98d785SM Chetan Kumar 273*7e98d785SM Chetan Kumar /* Update platform configuration */ 274*7e98d785SM Chetan Kumar ipc_pcie_config_init(ipc_pcie); 275*7e98d785SM Chetan Kumar 276*7e98d785SM Chetan Kumar /* Initialize the device before it is used. Ask low-level code 277*7e98d785SM Chetan Kumar * to enable I/O and memory. Wake up the device if it was suspended. 278*7e98d785SM Chetan Kumar */ 279*7e98d785SM Chetan Kumar if (pci_enable_device(pci)) { 280*7e98d785SM Chetan Kumar dev_err(ipc_pcie->dev, "failed to enable the AP PCIe device"); 281*7e98d785SM Chetan Kumar /* If enable of PCIe device has failed then calling 282*7e98d785SM Chetan Kumar * ipc_pcie_cleanup will panic the system. More over 283*7e98d785SM Chetan Kumar * ipc_pcie_cleanup() is required to be called after 284*7e98d785SM Chetan Kumar * ipc_imem_mount() 285*7e98d785SM Chetan Kumar */ 286*7e98d785SM Chetan Kumar goto pci_enable_fail; 287*7e98d785SM Chetan Kumar } 288*7e98d785SM Chetan Kumar 289*7e98d785SM Chetan Kumar ipc_pcie_config_aspm(ipc_pcie); 290*7e98d785SM Chetan Kumar dev_dbg(ipc_pcie->dev, "PCIe device enabled."); 291*7e98d785SM Chetan Kumar 292*7e98d785SM Chetan Kumar /* Read WWAN RTD3 BIOS Setting 293*7e98d785SM Chetan Kumar */ 294*7e98d785SM Chetan Kumar ipc_pcie->d3l2_support = ipc_pcie_read_bios_cfg(&pci->dev); 295*7e98d785SM Chetan Kumar 296*7e98d785SM Chetan Kumar ipc_pcie->suspend = 0; 297*7e98d785SM Chetan Kumar 298*7e98d785SM Chetan Kumar if (ipc_pcie_resources_request(ipc_pcie)) 299*7e98d785SM Chetan Kumar goto resources_req_fail; 300*7e98d785SM Chetan Kumar 301*7e98d785SM Chetan Kumar /* Establish the link to the imem layer. */ 302*7e98d785SM Chetan Kumar ipc_pcie->imem = ipc_imem_init(ipc_pcie, pci->device, 303*7e98d785SM Chetan Kumar ipc_pcie->scratchpad, ipc_pcie->dev); 304*7e98d785SM Chetan Kumar if (!ipc_pcie->imem) { 305*7e98d785SM Chetan Kumar dev_err(ipc_pcie->dev, "failed to init imem"); 306*7e98d785SM Chetan Kumar goto imem_init_fail; 307*7e98d785SM Chetan Kumar } 308*7e98d785SM Chetan Kumar 309*7e98d785SM Chetan Kumar return 0; 310*7e98d785SM Chetan Kumar 311*7e98d785SM Chetan Kumar imem_init_fail: 312*7e98d785SM Chetan Kumar ipc_pcie_resources_release(ipc_pcie); 313*7e98d785SM Chetan Kumar resources_req_fail: 314*7e98d785SM Chetan Kumar pci_disable_device(pci); 315*7e98d785SM Chetan Kumar pci_enable_fail: 316*7e98d785SM Chetan Kumar kfree(ipc_pcie); 317*7e98d785SM Chetan Kumar ret_fail: 318*7e98d785SM Chetan Kumar return -EIO; 319*7e98d785SM Chetan Kumar } 320*7e98d785SM Chetan Kumar 321*7e98d785SM Chetan Kumar static const struct pci_device_id iosm_ipc_ids[] = { 322*7e98d785SM Chetan Kumar { PCI_DEVICE(PCI_VENDOR_ID_INTEL, INTEL_CP_DEVICE_7560_ID) }, 323*7e98d785SM Chetan Kumar {} 324*7e98d785SM Chetan Kumar }; 325*7e98d785SM Chetan Kumar 326*7e98d785SM Chetan Kumar /* Enter sleep in s2idle case 327*7e98d785SM Chetan Kumar */ 328*7e98d785SM Chetan Kumar static int __maybe_unused ipc_pcie_suspend_s2idle(struct iosm_pcie *ipc_pcie) 329*7e98d785SM Chetan Kumar { 330*7e98d785SM Chetan Kumar ipc_cp_irq_sleep_control(ipc_pcie, IPC_MEM_DEV_PM_FORCE_SLEEP); 331*7e98d785SM Chetan Kumar 332*7e98d785SM Chetan Kumar /* Complete all memory stores before setting bit */ 333*7e98d785SM Chetan Kumar smp_mb__before_atomic(); 334*7e98d785SM Chetan Kumar 335*7e98d785SM Chetan Kumar set_bit(0, &ipc_pcie->suspend); 336*7e98d785SM Chetan Kumar 337*7e98d785SM Chetan Kumar /* Complete all memory stores after setting bit */ 338*7e98d785SM Chetan Kumar smp_mb__after_atomic(); 339*7e98d785SM Chetan Kumar 340*7e98d785SM Chetan Kumar ipc_imem_pm_s2idle_sleep(ipc_pcie->imem, true); 341*7e98d785SM Chetan Kumar 342*7e98d785SM Chetan Kumar return 0; 343*7e98d785SM Chetan Kumar } 344*7e98d785SM Chetan Kumar 345*7e98d785SM Chetan Kumar /* Resume from sleep in s2idle case 346*7e98d785SM Chetan Kumar */ 347*7e98d785SM Chetan Kumar static int __maybe_unused ipc_pcie_resume_s2idle(struct iosm_pcie *ipc_pcie) 348*7e98d785SM Chetan Kumar { 349*7e98d785SM Chetan Kumar ipc_cp_irq_sleep_control(ipc_pcie, IPC_MEM_DEV_PM_FORCE_ACTIVE); 350*7e98d785SM Chetan Kumar 351*7e98d785SM Chetan Kumar ipc_imem_pm_s2idle_sleep(ipc_pcie->imem, false); 352*7e98d785SM Chetan Kumar 353*7e98d785SM Chetan Kumar /* Complete all memory stores before clearing bit. */ 354*7e98d785SM Chetan Kumar smp_mb__before_atomic(); 355*7e98d785SM Chetan Kumar 356*7e98d785SM Chetan Kumar clear_bit(0, &ipc_pcie->suspend); 357*7e98d785SM Chetan Kumar 358*7e98d785SM Chetan Kumar /* Complete all memory stores after clearing bit. */ 359*7e98d785SM Chetan Kumar smp_mb__after_atomic(); 360*7e98d785SM Chetan Kumar return 0; 361*7e98d785SM Chetan Kumar } 362*7e98d785SM Chetan Kumar 363*7e98d785SM Chetan Kumar int __maybe_unused ipc_pcie_suspend(struct iosm_pcie *ipc_pcie) 364*7e98d785SM Chetan Kumar { 365*7e98d785SM Chetan Kumar struct pci_dev *pdev; 366*7e98d785SM Chetan Kumar int ret; 367*7e98d785SM Chetan Kumar 368*7e98d785SM Chetan Kumar pdev = ipc_pcie->pci; 369*7e98d785SM Chetan Kumar 370*7e98d785SM Chetan Kumar /* Execute D3 one time. */ 371*7e98d785SM Chetan Kumar if (pdev->current_state != PCI_D0) { 372*7e98d785SM Chetan Kumar dev_dbg(ipc_pcie->dev, "done for PM=%d", pdev->current_state); 373*7e98d785SM Chetan Kumar return 0; 374*7e98d785SM Chetan Kumar } 375*7e98d785SM Chetan Kumar 376*7e98d785SM Chetan Kumar /* The HAL shall ask the shared memory layer whether D3 is allowed. */ 377*7e98d785SM Chetan Kumar ipc_imem_pm_suspend(ipc_pcie->imem); 378*7e98d785SM Chetan Kumar 379*7e98d785SM Chetan Kumar /* Save the PCI configuration space of a device before suspending. */ 380*7e98d785SM Chetan Kumar ret = pci_save_state(pdev); 381*7e98d785SM Chetan Kumar 382*7e98d785SM Chetan Kumar if (ret) { 383*7e98d785SM Chetan Kumar dev_err(ipc_pcie->dev, "pci_save_state error=%d", ret); 384*7e98d785SM Chetan Kumar return ret; 385*7e98d785SM Chetan Kumar } 386*7e98d785SM Chetan Kumar 387*7e98d785SM Chetan Kumar /* Set the power state of a PCI device. 388*7e98d785SM Chetan Kumar * Transition a device to a new power state, using the device's PCI PM 389*7e98d785SM Chetan Kumar * registers. 390*7e98d785SM Chetan Kumar */ 391*7e98d785SM Chetan Kumar ret = pci_set_power_state(pdev, PCI_D3cold); 392*7e98d785SM Chetan Kumar 393*7e98d785SM Chetan Kumar if (ret) { 394*7e98d785SM Chetan Kumar dev_err(ipc_pcie->dev, "pci_set_power_state error=%d", ret); 395*7e98d785SM Chetan Kumar return ret; 396*7e98d785SM Chetan Kumar } 397*7e98d785SM Chetan Kumar 398*7e98d785SM Chetan Kumar dev_dbg(ipc_pcie->dev, "SUSPEND done"); 399*7e98d785SM Chetan Kumar return ret; 400*7e98d785SM Chetan Kumar } 401*7e98d785SM Chetan Kumar 402*7e98d785SM Chetan Kumar int __maybe_unused ipc_pcie_resume(struct iosm_pcie *ipc_pcie) 403*7e98d785SM Chetan Kumar { 404*7e98d785SM Chetan Kumar int ret; 405*7e98d785SM Chetan Kumar 406*7e98d785SM Chetan Kumar /* Set the power state of a PCI device. 407*7e98d785SM Chetan Kumar * Transition a device to a new power state, using the device's PCI PM 408*7e98d785SM Chetan Kumar * registers. 409*7e98d785SM Chetan Kumar */ 410*7e98d785SM Chetan Kumar ret = pci_set_power_state(ipc_pcie->pci, PCI_D0); 411*7e98d785SM Chetan Kumar 412*7e98d785SM Chetan Kumar if (ret) { 413*7e98d785SM Chetan Kumar dev_err(ipc_pcie->dev, "pci_set_power_state error=%d", ret); 414*7e98d785SM Chetan Kumar return ret; 415*7e98d785SM Chetan Kumar } 416*7e98d785SM Chetan Kumar 417*7e98d785SM Chetan Kumar pci_restore_state(ipc_pcie->pci); 418*7e98d785SM Chetan Kumar 419*7e98d785SM Chetan Kumar /* The HAL shall inform the shared memory layer that the device is 420*7e98d785SM Chetan Kumar * active. 421*7e98d785SM Chetan Kumar */ 422*7e98d785SM Chetan Kumar ipc_imem_pm_resume(ipc_pcie->imem); 423*7e98d785SM Chetan Kumar 424*7e98d785SM Chetan Kumar dev_dbg(ipc_pcie->dev, "RESUME done"); 425*7e98d785SM Chetan Kumar return ret; 426*7e98d785SM Chetan Kumar } 427*7e98d785SM Chetan Kumar 428*7e98d785SM Chetan Kumar static int __maybe_unused ipc_pcie_suspend_cb(struct device *dev) 429*7e98d785SM Chetan Kumar { 430*7e98d785SM Chetan Kumar struct iosm_pcie *ipc_pcie; 431*7e98d785SM Chetan Kumar struct pci_dev *pdev; 432*7e98d785SM Chetan Kumar 433*7e98d785SM Chetan Kumar pdev = to_pci_dev(dev); 434*7e98d785SM Chetan Kumar 435*7e98d785SM Chetan Kumar ipc_pcie = pci_get_drvdata(pdev); 436*7e98d785SM Chetan Kumar 437*7e98d785SM Chetan Kumar switch (ipc_pcie->d3l2_support) { 438*7e98d785SM Chetan Kumar case IPC_PCIE_D0L12: 439*7e98d785SM Chetan Kumar ipc_pcie_suspend_s2idle(ipc_pcie); 440*7e98d785SM Chetan Kumar break; 441*7e98d785SM Chetan Kumar case IPC_PCIE_D3L2: 442*7e98d785SM Chetan Kumar ipc_pcie_suspend(ipc_pcie); 443*7e98d785SM Chetan Kumar break; 444*7e98d785SM Chetan Kumar } 445*7e98d785SM Chetan Kumar 446*7e98d785SM Chetan Kumar return 0; 447*7e98d785SM Chetan Kumar } 448*7e98d785SM Chetan Kumar 449*7e98d785SM Chetan Kumar static int __maybe_unused ipc_pcie_resume_cb(struct device *dev) 450*7e98d785SM Chetan Kumar { 451*7e98d785SM Chetan Kumar struct iosm_pcie *ipc_pcie; 452*7e98d785SM Chetan Kumar struct pci_dev *pdev; 453*7e98d785SM Chetan Kumar 454*7e98d785SM Chetan Kumar pdev = to_pci_dev(dev); 455*7e98d785SM Chetan Kumar 456*7e98d785SM Chetan Kumar ipc_pcie = pci_get_drvdata(pdev); 457*7e98d785SM Chetan Kumar 458*7e98d785SM Chetan Kumar switch (ipc_pcie->d3l2_support) { 459*7e98d785SM Chetan Kumar case IPC_PCIE_D0L12: 460*7e98d785SM Chetan Kumar ipc_pcie_resume_s2idle(ipc_pcie); 461*7e98d785SM Chetan Kumar break; 462*7e98d785SM Chetan Kumar case IPC_PCIE_D3L2: 463*7e98d785SM Chetan Kumar ipc_pcie_resume(ipc_pcie); 464*7e98d785SM Chetan Kumar break; 465*7e98d785SM Chetan Kumar } 466*7e98d785SM Chetan Kumar 467*7e98d785SM Chetan Kumar return 0; 468*7e98d785SM Chetan Kumar } 469*7e98d785SM Chetan Kumar 470*7e98d785SM Chetan Kumar static SIMPLE_DEV_PM_OPS(iosm_ipc_pm, ipc_pcie_suspend_cb, ipc_pcie_resume_cb); 471*7e98d785SM Chetan Kumar 472*7e98d785SM Chetan Kumar static struct pci_driver iosm_ipc_driver = { 473*7e98d785SM Chetan Kumar .name = KBUILD_MODNAME, 474*7e98d785SM Chetan Kumar .probe = ipc_pcie_probe, 475*7e98d785SM Chetan Kumar .remove = ipc_pcie_remove, 476*7e98d785SM Chetan Kumar .driver = { 477*7e98d785SM Chetan Kumar .pm = &iosm_ipc_pm, 478*7e98d785SM Chetan Kumar }, 479*7e98d785SM Chetan Kumar .id_table = iosm_ipc_ids, 480*7e98d785SM Chetan Kumar }; 481*7e98d785SM Chetan Kumar 482*7e98d785SM Chetan Kumar int ipc_pcie_addr_map(struct iosm_pcie *ipc_pcie, unsigned char *data, 483*7e98d785SM Chetan Kumar size_t size, dma_addr_t *mapping, int direction) 484*7e98d785SM Chetan Kumar { 485*7e98d785SM Chetan Kumar if (ipc_pcie->pci) { 486*7e98d785SM Chetan Kumar *mapping = dma_map_single(&ipc_pcie->pci->dev, data, size, 487*7e98d785SM Chetan Kumar direction); 488*7e98d785SM Chetan Kumar if (dma_mapping_error(&ipc_pcie->pci->dev, *mapping)) { 489*7e98d785SM Chetan Kumar dev_err(ipc_pcie->dev, "dma mapping failed"); 490*7e98d785SM Chetan Kumar return -EINVAL; 491*7e98d785SM Chetan Kumar } 492*7e98d785SM Chetan Kumar } 493*7e98d785SM Chetan Kumar return 0; 494*7e98d785SM Chetan Kumar } 495*7e98d785SM Chetan Kumar 496*7e98d785SM Chetan Kumar void ipc_pcie_addr_unmap(struct iosm_pcie *ipc_pcie, size_t size, 497*7e98d785SM Chetan Kumar dma_addr_t mapping, int direction) 498*7e98d785SM Chetan Kumar { 499*7e98d785SM Chetan Kumar if (!mapping) 500*7e98d785SM Chetan Kumar return; 501*7e98d785SM Chetan Kumar if (ipc_pcie->pci) 502*7e98d785SM Chetan Kumar dma_unmap_single(&ipc_pcie->pci->dev, mapping, size, direction); 503*7e98d785SM Chetan Kumar } 504*7e98d785SM Chetan Kumar 505*7e98d785SM Chetan Kumar struct sk_buff *ipc_pcie_alloc_local_skb(struct iosm_pcie *ipc_pcie, 506*7e98d785SM Chetan Kumar gfp_t flags, size_t size) 507*7e98d785SM Chetan Kumar { 508*7e98d785SM Chetan Kumar struct sk_buff *skb; 509*7e98d785SM Chetan Kumar 510*7e98d785SM Chetan Kumar if (!ipc_pcie || !size) { 511*7e98d785SM Chetan Kumar pr_err("invalid pcie object or size"); 512*7e98d785SM Chetan Kumar return NULL; 513*7e98d785SM Chetan Kumar } 514*7e98d785SM Chetan Kumar 515*7e98d785SM Chetan Kumar skb = __netdev_alloc_skb(NULL, size, flags); 516*7e98d785SM Chetan Kumar if (!skb) 517*7e98d785SM Chetan Kumar return NULL; 518*7e98d785SM Chetan Kumar 519*7e98d785SM Chetan Kumar IPC_CB(skb)->op_type = (u8)UL_DEFAULT; 520*7e98d785SM Chetan Kumar IPC_CB(skb)->mapping = 0; 521*7e98d785SM Chetan Kumar 522*7e98d785SM Chetan Kumar return skb; 523*7e98d785SM Chetan Kumar } 524*7e98d785SM Chetan Kumar 525*7e98d785SM Chetan Kumar struct sk_buff *ipc_pcie_alloc_skb(struct iosm_pcie *ipc_pcie, size_t size, 526*7e98d785SM Chetan Kumar gfp_t flags, dma_addr_t *mapping, 527*7e98d785SM Chetan Kumar int direction, size_t headroom) 528*7e98d785SM Chetan Kumar { 529*7e98d785SM Chetan Kumar struct sk_buff *skb = ipc_pcie_alloc_local_skb(ipc_pcie, flags, 530*7e98d785SM Chetan Kumar size + headroom); 531*7e98d785SM Chetan Kumar if (!skb) 532*7e98d785SM Chetan Kumar return NULL; 533*7e98d785SM Chetan Kumar 534*7e98d785SM Chetan Kumar if (headroom) 535*7e98d785SM Chetan Kumar skb_reserve(skb, headroom); 536*7e98d785SM Chetan Kumar 537*7e98d785SM Chetan Kumar if (ipc_pcie_addr_map(ipc_pcie, skb->data, size, mapping, direction)) { 538*7e98d785SM Chetan Kumar dev_kfree_skb(skb); 539*7e98d785SM Chetan Kumar return NULL; 540*7e98d785SM Chetan Kumar } 541*7e98d785SM Chetan Kumar 542*7e98d785SM Chetan Kumar BUILD_BUG_ON(sizeof(*IPC_CB(skb)) > sizeof(skb->cb)); 543*7e98d785SM Chetan Kumar 544*7e98d785SM Chetan Kumar /* Store the mapping address in skb scratch pad for later usage */ 545*7e98d785SM Chetan Kumar IPC_CB(skb)->mapping = *mapping; 546*7e98d785SM Chetan Kumar IPC_CB(skb)->direction = direction; 547*7e98d785SM Chetan Kumar IPC_CB(skb)->len = size; 548*7e98d785SM Chetan Kumar 549*7e98d785SM Chetan Kumar return skb; 550*7e98d785SM Chetan Kumar } 551*7e98d785SM Chetan Kumar 552*7e98d785SM Chetan Kumar void ipc_pcie_kfree_skb(struct iosm_pcie *ipc_pcie, struct sk_buff *skb) 553*7e98d785SM Chetan Kumar { 554*7e98d785SM Chetan Kumar if (!skb) 555*7e98d785SM Chetan Kumar return; 556*7e98d785SM Chetan Kumar 557*7e98d785SM Chetan Kumar ipc_pcie_addr_unmap(ipc_pcie, IPC_CB(skb)->len, IPC_CB(skb)->mapping, 558*7e98d785SM Chetan Kumar IPC_CB(skb)->direction); 559*7e98d785SM Chetan Kumar IPC_CB(skb)->mapping = 0; 560*7e98d785SM Chetan Kumar dev_kfree_skb(skb); 561*7e98d785SM Chetan Kumar } 562*7e98d785SM Chetan Kumar 563*7e98d785SM Chetan Kumar static int __init iosm_ipc_driver_init(void) 564*7e98d785SM Chetan Kumar { 565*7e98d785SM Chetan Kumar if (pci_register_driver(&iosm_ipc_driver)) { 566*7e98d785SM Chetan Kumar pr_err("registering of IOSM PCIe driver failed"); 567*7e98d785SM Chetan Kumar return -1; 568*7e98d785SM Chetan Kumar } 569*7e98d785SM Chetan Kumar 570*7e98d785SM Chetan Kumar return 0; 571*7e98d785SM Chetan Kumar } 572*7e98d785SM Chetan Kumar 573*7e98d785SM Chetan Kumar static void __exit iosm_ipc_driver_exit(void) 574*7e98d785SM Chetan Kumar { 575*7e98d785SM Chetan Kumar pci_unregister_driver(&iosm_ipc_driver); 576*7e98d785SM Chetan Kumar } 577*7e98d785SM Chetan Kumar 578*7e98d785SM Chetan Kumar module_init(iosm_ipc_driver_init); 579*7e98d785SM Chetan Kumar module_exit(iosm_ipc_driver_exit); 580