brintos

brintos / linux-shallow public Read only

0
0
Text · 3.6 KiB · 149ec09 Raw
166 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013 - 2024 Intel Corporation4 */5 6#include <linux/auxiliary_bus.h>7#include <linux/device.h>8#include <linux/dma-mapping.h>9#include <linux/err.h>10#include <linux/list.h>11#include <linux/mutex.h>12#include <linux/pci.h>13#include <linux/pm_domain.h>14#include <linux/pm_runtime.h>15#include <linux/slab.h>16 17#include "ipu6.h"18#include "ipu6-bus.h"19#include "ipu6-buttress.h"20#include "ipu6-dma.h"21 22static int bus_pm_runtime_suspend(struct device *dev)23{24	struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);25	int ret;26 27	ret = pm_generic_runtime_suspend(dev);28	if (ret)29		return ret;30 31	ret = ipu6_buttress_power(dev, adev->ctrl, false);32	if (!ret)33		return 0;34 35	dev_err(dev, "power down failed!\n");36 37	/* Powering down failed, attempt to resume device now */38	ret = pm_generic_runtime_resume(dev);39	if (!ret)40		return -EBUSY;41 42	return -EIO;43}44 45static int bus_pm_runtime_resume(struct device *dev)46{47	struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);48	int ret;49 50	ret = ipu6_buttress_power(dev, adev->ctrl, true);51	if (ret)52		return ret;53 54	ret = pm_generic_runtime_resume(dev);55	if (ret)56		goto out_err;57 58	return 0;59 60out_err:61	ipu6_buttress_power(dev, adev->ctrl, false);62 63	return -EBUSY;64}65 66static struct dev_pm_domain ipu6_bus_pm_domain = {67	.ops = {68		.runtime_suspend = bus_pm_runtime_suspend,69		.runtime_resume = bus_pm_runtime_resume,70	},71};72 73static DEFINE_MUTEX(ipu6_bus_mutex);74 75static void ipu6_bus_release(struct device *dev)76{77	struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);78 79	kfree(adev->pdata);80	kfree(adev);81}82 83struct ipu6_bus_device *84ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,85			   void *pdata, struct ipu6_buttress_ctrl *ctrl,86			   char *name)87{88	struct auxiliary_device *auxdev;89	struct ipu6_bus_device *adev;90	struct ipu6_device *isp = pci_get_drvdata(pdev);91	int ret;92 93	adev = kzalloc(sizeof(*adev), GFP_KERNEL);94	if (!adev)95		return ERR_PTR(-ENOMEM);96 97	adev->dma_mask = DMA_BIT_MASK(isp->secure_mode ? IPU6_MMU_ADDR_BITS :98				      IPU6_MMU_ADDR_BITS_NON_SECURE);99	adev->isp = isp;100	adev->ctrl = ctrl;101	adev->pdata = pdata;102	auxdev = &adev->auxdev;103	auxdev->name = name;104	auxdev->id = (pci_domain_nr(pdev->bus) << 16) |105		      PCI_DEVID(pdev->bus->number, pdev->devfn);106 107	auxdev->dev.parent = parent;108	auxdev->dev.release = ipu6_bus_release;109	auxdev->dev.dma_ops = &ipu6_dma_ops;110	auxdev->dev.dma_mask = &adev->dma_mask;111	auxdev->dev.dma_parms = pdev->dev.dma_parms;112	auxdev->dev.coherent_dma_mask = adev->dma_mask;113 114	ret = auxiliary_device_init(auxdev);115	if (ret < 0) {116		dev_err(&isp->pdev->dev, "auxiliary device init failed (%d)\n",117			ret);118		kfree(adev);119		return ERR_PTR(ret);120	}121 122	dev_pm_domain_set(&auxdev->dev, &ipu6_bus_pm_domain);123 124	pm_runtime_forbid(&adev->auxdev.dev);125	pm_runtime_enable(&adev->auxdev.dev);126 127	return adev;128}129 130int ipu6_bus_add_device(struct ipu6_bus_device *adev)131{132	struct auxiliary_device *auxdev = &adev->auxdev;133	int ret;134 135	ret = auxiliary_device_add(auxdev);136	if (ret) {137		auxiliary_device_uninit(auxdev);138		return ret;139	}140 141	mutex_lock(&ipu6_bus_mutex);142	list_add(&adev->list, &adev->isp->devices);143	mutex_unlock(&ipu6_bus_mutex);144 145	pm_runtime_allow(&auxdev->dev);146 147	return 0;148}149 150void ipu6_bus_del_devices(struct pci_dev *pdev)151{152	struct ipu6_device *isp = pci_get_drvdata(pdev);153	struct ipu6_bus_device *adev, *save;154 155	mutex_lock(&ipu6_bus_mutex);156 157	list_for_each_entry_safe(adev, save, &isp->devices, list) {158		pm_runtime_disable(&adev->auxdev.dev);159		list_del(&adev->list);160		auxiliary_device_delete(&adev->auxdev);161		auxiliary_device_uninit(&adev->auxdev);162	}163 164	mutex_unlock(&ipu6_bus_mutex);165}166