Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.0-rc3 278 lines 6.5 kB view raw
1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2/* 3 * Copyright 2014-2016 Freescale Semiconductor Inc. 4 * Copyright NXP 2016 5 * 6 */ 7 8#include <linux/types.h> 9#include <linux/init.h> 10#include <linux/module.h> 11#include <linux/platform_device.h> 12#include <linux/interrupt.h> 13#include <linux/msi.h> 14#include <linux/dma-mapping.h> 15#include <linux/delay.h> 16#include <linux/io.h> 17 18#include <linux/fsl/mc.h> 19#include <soc/fsl/dpaa2-io.h> 20 21#include "qbman-portal.h" 22#include "dpio.h" 23#include "dpio-cmd.h" 24 25MODULE_LICENSE("Dual BSD/GPL"); 26MODULE_AUTHOR("Freescale Semiconductor, Inc"); 27MODULE_DESCRIPTION("DPIO Driver"); 28 29struct dpio_priv { 30 struct dpaa2_io *io; 31}; 32 33static irqreturn_t dpio_irq_handler(int irq_num, void *arg) 34{ 35 struct device *dev = (struct device *)arg; 36 struct dpio_priv *priv = dev_get_drvdata(dev); 37 38 return dpaa2_io_irq(priv->io); 39} 40 41static void unregister_dpio_irq_handlers(struct fsl_mc_device *dpio_dev) 42{ 43 struct fsl_mc_device_irq *irq; 44 45 irq = dpio_dev->irqs[0]; 46 47 /* clear the affinity hint */ 48 irq_set_affinity_hint(irq->msi_desc->irq, NULL); 49} 50 51static int register_dpio_irq_handlers(struct fsl_mc_device *dpio_dev, int cpu) 52{ 53 int error; 54 struct fsl_mc_device_irq *irq; 55 cpumask_t mask; 56 57 irq = dpio_dev->irqs[0]; 58 error = devm_request_irq(&dpio_dev->dev, 59 irq->msi_desc->irq, 60 dpio_irq_handler, 61 0, 62 dev_name(&dpio_dev->dev), 63 &dpio_dev->dev); 64 if (error < 0) { 65 dev_err(&dpio_dev->dev, 66 "devm_request_irq() failed: %d\n", 67 error); 68 return error; 69 } 70 71 /* set the affinity hint */ 72 cpumask_clear(&mask); 73 cpumask_set_cpu(cpu, &mask); 74 if (irq_set_affinity_hint(irq->msi_desc->irq, &mask)) 75 dev_err(&dpio_dev->dev, 76 "irq_set_affinity failed irq %d cpu %d\n", 77 irq->msi_desc->irq, cpu); 78 79 return 0; 80} 81 82static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) 83{ 84 struct dpio_attr dpio_attrs; 85 struct dpaa2_io_desc desc; 86 struct dpio_priv *priv; 87 int err = -ENOMEM; 88 struct device *dev = &dpio_dev->dev; 89 static int next_cpu = -1; 90 91 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 92 if (!priv) 93 goto err_priv_alloc; 94 95 dev_set_drvdata(dev, priv); 96 97 err = fsl_mc_portal_allocate(dpio_dev, 0, &dpio_dev->mc_io); 98 if (err) { 99 dev_dbg(dev, "MC portal allocation failed\n"); 100 err = -EPROBE_DEFER; 101 goto err_priv_alloc; 102 } 103 104 err = dpio_open(dpio_dev->mc_io, 0, dpio_dev->obj_desc.id, 105 &dpio_dev->mc_handle); 106 if (err) { 107 dev_err(dev, "dpio_open() failed\n"); 108 goto err_open; 109 } 110 111 err = dpio_get_attributes(dpio_dev->mc_io, 0, dpio_dev->mc_handle, 112 &dpio_attrs); 113 if (err) { 114 dev_err(dev, "dpio_get_attributes() failed %d\n", err); 115 goto err_get_attr; 116 } 117 desc.qman_version = dpio_attrs.qbman_version; 118 119 err = dpio_enable(dpio_dev->mc_io, 0, dpio_dev->mc_handle); 120 if (err) { 121 dev_err(dev, "dpio_enable() failed %d\n", err); 122 goto err_get_attr; 123 } 124 125 /* initialize DPIO descriptor */ 126 desc.receives_notifications = dpio_attrs.num_priorities ? 1 : 0; 127 desc.has_8prio = dpio_attrs.num_priorities == 8 ? 1 : 0; 128 desc.dpio_id = dpio_dev->obj_desc.id; 129 130 /* get the cpu to use for the affinity hint */ 131 if (next_cpu == -1) 132 next_cpu = cpumask_first(cpu_online_mask); 133 else 134 next_cpu = cpumask_next(next_cpu, cpu_online_mask); 135 136 if (!cpu_possible(next_cpu)) { 137 dev_err(dev, "probe failed. Number of DPIOs exceeds NR_CPUS.\n"); 138 err = -ERANGE; 139 goto err_allocate_irqs; 140 } 141 desc.cpu = next_cpu; 142 143 /* 144 * Set the CENA regs to be the cache inhibited area of the portal to 145 * avoid coherency issues if a user migrates to another core. 146 */ 147 desc.regs_cena = devm_memremap(dev, dpio_dev->regions[1].start, 148 resource_size(&dpio_dev->regions[1]), 149 MEMREMAP_WC); 150 if (IS_ERR(desc.regs_cena)) { 151 dev_err(dev, "devm_memremap failed\n"); 152 err = PTR_ERR(desc.regs_cena); 153 goto err_allocate_irqs; 154 } 155 156 desc.regs_cinh = devm_ioremap(dev, dpio_dev->regions[1].start, 157 resource_size(&dpio_dev->regions[1])); 158 if (!desc.regs_cinh) { 159 err = -ENOMEM; 160 dev_err(dev, "devm_ioremap failed\n"); 161 goto err_allocate_irqs; 162 } 163 164 err = fsl_mc_allocate_irqs(dpio_dev); 165 if (err) { 166 dev_err(dev, "fsl_mc_allocate_irqs failed. err=%d\n", err); 167 goto err_allocate_irqs; 168 } 169 170 err = register_dpio_irq_handlers(dpio_dev, desc.cpu); 171 if (err) 172 goto err_register_dpio_irq; 173 174 priv->io = dpaa2_io_create(&desc); 175 if (!priv->io) { 176 dev_err(dev, "dpaa2_io_create failed\n"); 177 err = -ENOMEM; 178 goto err_dpaa2_io_create; 179 } 180 181 dev_info(dev, "probed\n"); 182 dev_dbg(dev, " receives_notifications = %d\n", 183 desc.receives_notifications); 184 dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle); 185 fsl_mc_portal_free(dpio_dev->mc_io); 186 187 return 0; 188 189err_dpaa2_io_create: 190 unregister_dpio_irq_handlers(dpio_dev); 191err_register_dpio_irq: 192 fsl_mc_free_irqs(dpio_dev); 193err_allocate_irqs: 194 dpio_disable(dpio_dev->mc_io, 0, dpio_dev->mc_handle); 195err_get_attr: 196 dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle); 197err_open: 198 fsl_mc_portal_free(dpio_dev->mc_io); 199err_priv_alloc: 200 return err; 201} 202 203/* Tear down interrupts for a given DPIO object */ 204static void dpio_teardown_irqs(struct fsl_mc_device *dpio_dev) 205{ 206 unregister_dpio_irq_handlers(dpio_dev); 207 fsl_mc_free_irqs(dpio_dev); 208} 209 210static int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev) 211{ 212 struct device *dev; 213 struct dpio_priv *priv; 214 int err; 215 216 dev = &dpio_dev->dev; 217 priv = dev_get_drvdata(dev); 218 219 dpaa2_io_down(priv->io); 220 221 dpio_teardown_irqs(dpio_dev); 222 223 err = fsl_mc_portal_allocate(dpio_dev, 0, &dpio_dev->mc_io); 224 if (err) { 225 dev_err(dev, "MC portal allocation failed\n"); 226 goto err_mcportal; 227 } 228 229 err = dpio_open(dpio_dev->mc_io, 0, dpio_dev->obj_desc.id, 230 &dpio_dev->mc_handle); 231 if (err) { 232 dev_err(dev, "dpio_open() failed\n"); 233 goto err_open; 234 } 235 236 dpio_disable(dpio_dev->mc_io, 0, dpio_dev->mc_handle); 237 238 dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle); 239 240 fsl_mc_portal_free(dpio_dev->mc_io); 241 242 return 0; 243 244err_open: 245 fsl_mc_portal_free(dpio_dev->mc_io); 246err_mcportal: 247 return err; 248} 249 250static const struct fsl_mc_device_id dpaa2_dpio_match_id_table[] = { 251 { 252 .vendor = FSL_MC_VENDOR_FREESCALE, 253 .obj_type = "dpio", 254 }, 255 { .vendor = 0x0 } 256}; 257 258static struct fsl_mc_driver dpaa2_dpio_driver = { 259 .driver = { 260 .name = KBUILD_MODNAME, 261 .owner = THIS_MODULE, 262 }, 263 .probe = dpaa2_dpio_probe, 264 .remove = dpaa2_dpio_remove, 265 .match_id_table = dpaa2_dpio_match_id_table 266}; 267 268static int dpio_driver_init(void) 269{ 270 return fsl_mc_driver_register(&dpaa2_dpio_driver); 271} 272 273static void dpio_driver_exit(void) 274{ 275 fsl_mc_driver_unregister(&dpaa2_dpio_driver); 276} 277module_init(dpio_driver_init); 278module_exit(dpio_driver_exit);