diff options
Diffstat (limited to 'drivers/misc')
50 files changed, 1192 insertions, 772 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index ee9402324a23..b841180c7c74 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
| @@ -51,16 +51,6 @@ config AD525X_DPOT_SPI | |||
| 51 | To compile this driver as a module, choose M here: the | 51 | To compile this driver as a module, choose M here: the |
| 52 | module will be called ad525x_dpot-spi. | 52 | module will be called ad525x_dpot-spi. |
| 53 | 53 | ||
| 54 | config ATMEL_PWM | ||
| 55 | tristate "Atmel AT32/AT91 PWM support" | ||
| 56 | depends on HAVE_CLK | ||
| 57 | depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 | ||
| 58 | help | ||
| 59 | This option enables device driver support for the PWM channels | ||
| 60 | on certain Atmel processors. Pulse Width Modulation is used for | ||
| 61 | purposes including software controlled power-efficient backlights | ||
| 62 | on LCD displays, motor control, and waveform generation. | ||
| 63 | |||
| 64 | config ATMEL_TCLIB | 54 | config ATMEL_TCLIB |
| 65 | bool "Atmel AT32/AT91 Timer/Counter Library" | 55 | bool "Atmel AT32/AT91 Timer/Counter Library" |
| 66 | depends on (AVR32 || ARCH_AT91) | 56 | depends on (AVR32 || ARCH_AT91) |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index d59ce1261b38..5497d026e651 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
| @@ -7,7 +7,6 @@ obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o | |||
| 7 | obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o | 7 | obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o |
| 8 | obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o | 8 | obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o |
| 9 | obj-$(CONFIG_INTEL_MID_PTI) += pti.o | 9 | obj-$(CONFIG_INTEL_MID_PTI) += pti.o |
| 10 | obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o | ||
| 11 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o | 10 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o |
| 12 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o | 11 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o |
| 13 | obj-$(CONFIG_BMP085) += bmp085.o | 12 | obj-$(CONFIG_BMP085) += bmp085.o |
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 22de13727641..60843a275abd 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c | |||
| @@ -83,10 +83,17 @@ EXPORT_SYMBOL(ssc_free); | |||
| 83 | 83 | ||
| 84 | static struct atmel_ssc_platform_data at91rm9200_config = { | 84 | static struct atmel_ssc_platform_data at91rm9200_config = { |
| 85 | .use_dma = 0, | 85 | .use_dma = 0, |
| 86 | .has_fslen_ext = 0, | ||
| 87 | }; | ||
| 88 | |||
| 89 | static struct atmel_ssc_platform_data at91sam9rl_config = { | ||
| 90 | .use_dma = 0, | ||
| 91 | .has_fslen_ext = 1, | ||
| 86 | }; | 92 | }; |
| 87 | 93 | ||
| 88 | static struct atmel_ssc_platform_data at91sam9g45_config = { | 94 | static struct atmel_ssc_platform_data at91sam9g45_config = { |
| 89 | .use_dma = 1, | 95 | .use_dma = 1, |
| 96 | .has_fslen_ext = 1, | ||
| 90 | }; | 97 | }; |
| 91 | 98 | ||
| 92 | static const struct platform_device_id atmel_ssc_devtypes[] = { | 99 | static const struct platform_device_id atmel_ssc_devtypes[] = { |
| @@ -94,6 +101,9 @@ static const struct platform_device_id atmel_ssc_devtypes[] = { | |||
| 94 | .name = "at91rm9200_ssc", | 101 | .name = "at91rm9200_ssc", |
| 95 | .driver_data = (unsigned long) &at91rm9200_config, | 102 | .driver_data = (unsigned long) &at91rm9200_config, |
| 96 | }, { | 103 | }, { |
| 104 | .name = "at91sam9rl_ssc", | ||
| 105 | .driver_data = (unsigned long) &at91sam9rl_config, | ||
| 106 | }, { | ||
| 97 | .name = "at91sam9g45_ssc", | 107 | .name = "at91sam9g45_ssc", |
| 98 | .driver_data = (unsigned long) &at91sam9g45_config, | 108 | .driver_data = (unsigned long) &at91sam9g45_config, |
| 99 | }, { | 109 | }, { |
| @@ -107,6 +117,9 @@ static const struct of_device_id atmel_ssc_dt_ids[] = { | |||
| 107 | .compatible = "atmel,at91rm9200-ssc", | 117 | .compatible = "atmel,at91rm9200-ssc", |
| 108 | .data = &at91rm9200_config, | 118 | .data = &at91rm9200_config, |
| 109 | }, { | 119 | }, { |
| 120 | .compatible = "atmel,at91sam9rl-ssc", | ||
| 121 | .data = &at91sam9rl_config, | ||
| 122 | }, { | ||
| 110 | .compatible = "atmel,at91sam9g45-ssc", | 123 | .compatible = "atmel,at91sam9g45-ssc", |
| 111 | .data = &at91sam9g45_config, | 124 | .data = &at91sam9g45_config, |
| 112 | }, { | 125 | }, { |
diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c deleted file mode 100644 index a6dc56e1bc58..000000000000 --- a/drivers/misc/atmel_pwm.c +++ /dev/null | |||
| @@ -1,402 +0,0 @@ | |||
| 1 | #include <linux/module.h> | ||
| 2 | #include <linux/clk.h> | ||
| 3 | #include <linux/err.h> | ||
| 4 | #include <linux/slab.h> | ||
| 5 | #include <linux/io.h> | ||
| 6 | #include <linux/interrupt.h> | ||
| 7 | #include <linux/platform_device.h> | ||
| 8 | #include <linux/atmel_pwm.h> | ||
| 9 | |||
| 10 | |||
| 11 | /* | ||
| 12 | * This is a simple driver for the PWM controller found in various newer | ||
| 13 | * Atmel SOCs, including the AVR32 series and the AT91sam9263. | ||
| 14 | * | ||
| 15 | * Chips with current Linux ports have only 4 PWM channels, out of max 32. | ||
| 16 | * AT32UC3A and AT32UC3B chips have 7 channels (but currently no Linux). | ||
| 17 | * Docs are inconsistent about the width of the channel counter registers; | ||
| 18 | * it's at least 16 bits, but several places say 20 bits. | ||
| 19 | */ | ||
| 20 | #define PWM_NCHAN 4 /* max 32 */ | ||
| 21 | |||
| 22 | struct pwm { | ||
| 23 | spinlock_t lock; | ||
| 24 | struct platform_device *pdev; | ||
| 25 | u32 mask; | ||
| 26 | int irq; | ||
| 27 | void __iomem *base; | ||
| 28 | struct clk *clk; | ||
| 29 | struct pwm_channel *channel[PWM_NCHAN]; | ||
| 30 | void (*handler[PWM_NCHAN])(struct pwm_channel *); | ||
| 31 | }; | ||
| 32 | |||
| 33 | |||
| 34 | /* global PWM controller registers */ | ||
| 35 | #define PWM_MR 0x00 | ||
| 36 | #define PWM_ENA 0x04 | ||
| 37 | #define PWM_DIS 0x08 | ||
| 38 | #define PWM_SR 0x0c | ||
| 39 | #define PWM_IER 0x10 | ||
| 40 | #define PWM_IDR 0x14 | ||
| 41 | #define PWM_IMR 0x18 | ||
| 42 | #define PWM_ISR 0x1c | ||
| 43 | |||
| 44 | static inline void pwm_writel(const struct pwm *p, unsigned offset, u32 val) | ||
| 45 | { | ||
| 46 | __raw_writel(val, p->base + offset); | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline u32 pwm_readl(const struct pwm *p, unsigned offset) | ||
| 50 | { | ||
| 51 | return __raw_readl(p->base + offset); | ||
| 52 | } | ||
| 53 | |||
| 54 | static inline void __iomem *pwmc_regs(const struct pwm *p, int index) | ||
| 55 | { | ||
| 56 | return p->base + 0x200 + index * 0x20; | ||
| 57 | } | ||
| 58 | |||
| 59 | static struct pwm *pwm; | ||
| 60 | |||
| 61 | static void pwm_dumpregs(struct pwm_channel *ch, char *tag) | ||
| 62 | { | ||
| 63 | struct device *dev = &pwm->pdev->dev; | ||
| 64 | |||
| 65 | dev_dbg(dev, "%s: mr %08x, sr %08x, imr %08x\n", | ||
| 66 | tag, | ||
| 67 | pwm_readl(pwm, PWM_MR), | ||
| 68 | pwm_readl(pwm, PWM_SR), | ||
| 69 | pwm_readl(pwm, PWM_IMR)); | ||
| 70 | dev_dbg(dev, | ||
| 71 | "pwm ch%d - mr %08x, dty %u, prd %u, cnt %u\n", | ||
| 72 | ch->index, | ||
| 73 | pwm_channel_readl(ch, PWM_CMR), | ||
| 74 | pwm_channel_readl(ch, PWM_CDTY), | ||
| 75 | pwm_channel_readl(ch, PWM_CPRD), | ||
| 76 | pwm_channel_readl(ch, PWM_CCNT)); | ||
| 77 | } | ||
| 78 | |||
| 79 | |||
| 80 | /** | ||
| 81 | * pwm_channel_alloc - allocate an unused PWM channel | ||
| 82 | * @index: identifies the channel | ||
| 83 | * @ch: structure to be initialized | ||
| 84 | * | ||
| 85 | * Drivers allocate PWM channels according to the board's wiring, and | ||
| 86 | * matching board-specific setup code. Returns zero or negative errno. | ||
| 87 | */ | ||
| 88 | int pwm_channel_alloc(int index, struct pwm_channel *ch) | ||
| 89 | { | ||
| 90 | unsigned long flags; | ||
| 91 | int status = 0; | ||
| 92 | |||
| 93 | if (!pwm) | ||
| 94 | return -EPROBE_DEFER; | ||
| 95 | |||
| 96 | if (!(pwm->mask & 1 << index)) | ||
| 97 | return -ENODEV; | ||
| 98 | |||
| 99 | if (index < 0 || index >= PWM_NCHAN || !ch) | ||
| 100 | return -EINVAL; | ||
| 101 | memset(ch, 0, sizeof *ch); | ||
| 102 | |||
| 103 | spin_lock_irqsave(&pwm->lock, flags); | ||
| 104 | if (pwm->channel[index]) | ||
| 105 | status = -EBUSY; | ||
| 106 | else { | ||
| 107 | clk_enable(pwm->clk); | ||
| 108 | |||
| 109 | ch->regs = pwmc_regs(pwm, index); | ||
| 110 | ch->index = index; | ||
| 111 | |||
| 112 | /* REVISIT: ap7000 seems to go 2x as fast as we expect!! */ | ||
| 113 | ch->mck = clk_get_rate(pwm->clk); | ||
| 114 | |||
| 115 | pwm->channel[index] = ch; | ||
| 116 | pwm->handler[index] = NULL; | ||
| 117 | |||
| 118 | /* channel and irq are always disabled when we return */ | ||
| 119 | pwm_writel(pwm, PWM_DIS, 1 << index); | ||
| 120 | pwm_writel(pwm, PWM_IDR, 1 << index); | ||
| 121 | } | ||
| 122 | spin_unlock_irqrestore(&pwm->lock, flags); | ||
| 123 | return status; | ||
| 124 | } | ||
| 125 | EXPORT_SYMBOL(pwm_channel_alloc); | ||
| 126 | |||
| 127 | static int pwmcheck(struct pwm_channel *ch) | ||
| 128 | { | ||
| 129 | int index; | ||
| 130 | |||
| 131 | if (!pwm) | ||
| 132 | return -ENODEV; | ||
| 133 | if (!ch) | ||
| 134 | return -EINVAL; | ||
| 135 | index = ch->index; | ||
| 136 | if (index < 0 || index >= PWM_NCHAN || pwm->channel[index] != ch) | ||
| 137 | return -EINVAL; | ||
| 138 | |||
| 139 | return index; | ||
| 140 | } | ||
| 141 | |||
| 142 | /** | ||
| 143 | * pwm_channel_free - release a previously allocated channel | ||
| 144 | * @ch: the channel being released | ||
| 145 | * | ||
| 146 | * The channel is completely shut down (counter and IRQ disabled), | ||
| 147 | * and made available for re-use. Returns zero, or negative errno. | ||
| 148 | */ | ||
| 149 | int pwm_channel_free(struct pwm_channel *ch) | ||
| 150 | { | ||
| 151 | unsigned long flags; | ||
| 152 | int t; | ||
| 153 | |||
| 154 | spin_lock_irqsave(&pwm->lock, flags); | ||
| 155 | t = pwmcheck(ch); | ||
| 156 | if (t >= 0) { | ||
| 157 | pwm->channel[t] = NULL; | ||
| 158 | pwm->handler[t] = NULL; | ||
| 159 | |||
| 160 | /* channel and irq are always disabled when we return */ | ||
| 161 | pwm_writel(pwm, PWM_DIS, 1 << t); | ||
| 162 | pwm_writel(pwm, PWM_IDR, 1 << t); | ||
| 163 | |||
| 164 | clk_disable(pwm->clk); | ||
| 165 | t = 0; | ||
| 166 | } | ||
| 167 | spin_unlock_irqrestore(&pwm->lock, flags); | ||
| 168 | return t; | ||
| 169 | } | ||
| 170 | EXPORT_SYMBOL(pwm_channel_free); | ||
| 171 | |||
| 172 | int __pwm_channel_onoff(struct pwm_channel *ch, int enabled) | ||
| 173 | { | ||
| 174 | unsigned long flags; | ||
| 175 | int t; | ||
| 176 | |||
| 177 | /* OMITTED FUNCTIONALITY: starting several channels in synch */ | ||
| 178 | |||
| 179 | spin_lock_irqsave(&pwm->lock, flags); | ||
| 180 | t = pwmcheck(ch); | ||
| 181 | if (t >= 0) { | ||
| 182 | pwm_writel(pwm, enabled ? PWM_ENA : PWM_DIS, 1 << t); | ||
| 183 | t = 0; | ||
| 184 | pwm_dumpregs(ch, enabled ? "enable" : "disable"); | ||
| 185 | } | ||
| 186 | spin_unlock_irqrestore(&pwm->lock, flags); | ||
| 187 | |||
| 188 | return t; | ||
| 189 | } | ||
| 190 | EXPORT_SYMBOL(__pwm_channel_onoff); | ||
| 191 | |||
| 192 | /** | ||
| 193 | * pwm_clk_alloc - allocate and configure CLKA or CLKB | ||
| 194 | * @prescale: from 0..10, the power of two used to divide MCK | ||
| 195 | * @div: from 1..255, the linear divisor to use | ||
| 196 | * | ||
| 197 | * Returns PWM_CPR_CLKA, PWM_CPR_CLKB, or negative errno. The allocated | ||
| 198 | * clock will run with a period of (2^prescale * div) / MCK, or twice as | ||
| 199 | * long if center aligned PWM output is used. The clock must later be | ||
| 200 | * deconfigured using pwm_clk_free(). | ||
| 201 | */ | ||
| 202 | int pwm_clk_alloc(unsigned prescale, unsigned div) | ||
| 203 | { | ||
| 204 | unsigned long flags; | ||
| 205 | u32 mr; | ||
| 206 | u32 val = (prescale << 8) | div; | ||
| 207 | int ret = -EBUSY; | ||
| 208 | |||
| 209 | if (prescale >= 10 || div == 0 || div > 255) | ||
| 210 | return -EINVAL; | ||
| 211 | |||
| 212 | spin_lock_irqsave(&pwm->lock, flags); | ||
| 213 | mr = pwm_readl(pwm, PWM_MR); | ||
| 214 | if ((mr & 0xffff) == 0) { | ||
| 215 | mr |= val; | ||
| 216 | ret = PWM_CPR_CLKA; | ||
| 217 | } else if ((mr & (0xffff << 16)) == 0) { | ||
| 218 | mr |= val << 16; | ||
| 219 | ret = PWM_CPR_CLKB; | ||
| 220 | } | ||
| 221 | if (ret > 0) | ||
| 222 | pwm_writel(pwm, PWM_MR, mr); | ||
| 223 | spin_unlock_irqrestore(&pwm->lock, flags); | ||
| 224 | return ret; | ||
| 225 | } | ||
| 226 | EXPORT_SYMBOL(pwm_clk_alloc); | ||
| 227 | |||
| 228 | /** | ||
| 229 | * pwm_clk_free - deconfigure and release CLKA or CLKB | ||
| 230 | * | ||
| 231 | * Reverses the effect of pwm_clk_alloc(). | ||
| 232 | */ | ||
| 233 | void pwm_clk_free(unsigned clk) | ||
| 234 | { | ||
| 235 | unsigned long flags; | ||
| 236 | u32 mr; | ||
| 237 | |||
| 238 | spin_lock_irqsave(&pwm->lock, flags); | ||
| 239 | mr = pwm_readl(pwm, PWM_MR); | ||
| 240 | if (clk == PWM_CPR_CLKA) | ||
| 241 | pwm_writel(pwm, PWM_MR, mr & ~(0xffff << 0)); | ||
| 242 | if (clk == PWM_CPR_CLKB) | ||
| 243 | pwm_writel(pwm, PWM_MR, mr & ~(0xffff << 16)); | ||
| 244 | spin_unlock_irqrestore(&pwm->lock, flags); | ||
| 245 | } | ||
| 246 | EXPORT_SYMBOL(pwm_clk_free); | ||
| 247 | |||
| 248 | /** | ||
| 249 | * pwm_channel_handler - manage channel's IRQ handler | ||
| 250 | * @ch: the channel | ||
| 251 | * @handler: the handler to use, possibly NULL | ||
| 252 | * | ||
| 253 | * If the handler is non-null, the handler will be called after every | ||
| 254 | * period of this PWM channel. If the handler is null, this channel | ||
| 255 | * won't generate an IRQ. | ||
| 256 | */ | ||
| 257 | int pwm_channel_handler(struct pwm_channel *ch, | ||
| 258 | void (*handler)(struct pwm_channel *ch)) | ||
| 259 | { | ||
| 260 | unsigned long flags; | ||
| 261 | int t; | ||
| 262 | |||
| 263 | spin_lock_irqsave(&pwm->lock, flags); | ||
| 264 | t = pwmcheck(ch); | ||
| 265 | if (t >= 0) { | ||
| 266 | pwm->handler[t] = handler; | ||
| 267 | pwm_writel(pwm, handler ? PWM_IER : PWM_IDR, 1 << t); | ||
| 268 | t = 0; | ||
| 269 | } | ||
| 270 | spin_unlock_irqrestore(&pwm->lock, flags); | ||
| 271 | |||
| 272 | return t; | ||
| 273 | } | ||
| 274 | EXPORT_SYMBOL(pwm_channel_handler); | ||
| 275 | |||
| 276 | static irqreturn_t pwm_irq(int id, void *_pwm) | ||
| 277 | { | ||
| 278 | struct pwm *p = _pwm; | ||
| 279 | irqreturn_t handled = IRQ_NONE; | ||
| 280 | u32 irqstat; | ||
| 281 | int index; | ||
| 282 | |||
| 283 | spin_lock(&p->lock); | ||
| 284 | |||
| 285 | /* ack irqs, then handle them */ | ||
| 286 | irqstat = pwm_readl(pwm, PWM_ISR); | ||
| 287 | |||
| 288 | while (irqstat) { | ||
| 289 | struct pwm_channel *ch; | ||
| 290 | void (*handler)(struct pwm_channel *ch); | ||
| 291 | |||
| 292 | index = ffs(irqstat) - 1; | ||
| 293 | irqstat &= ~(1 << index); | ||
| 294 | ch = pwm->channel[index]; | ||
| 295 | handler = pwm->handler[index]; | ||
| 296 | if (handler && ch) { | ||
| 297 | spin_unlock(&p->lock); | ||
| 298 | handler(ch); | ||
| 299 | spin_lock(&p->lock); | ||
| 300 | handled = IRQ_HANDLED; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | spin_unlock(&p->lock); | ||
| 305 | return handled; | ||
| 306 | } | ||
| 307 | |||
| 308 | static int __init pwm_probe(struct platform_device *pdev) | ||
| 309 | { | ||
| 310 | struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 311 | int irq = platform_get_irq(pdev, 0); | ||
| 312 | u32 *mp = pdev->dev.platform_data; | ||
| 313 | struct pwm *p; | ||
| 314 | int status = -EIO; | ||
| 315 | |||
| 316 | if (pwm) | ||
| 317 | return -EBUSY; | ||
| 318 | if (!r || irq < 0 || !mp || !*mp) | ||
| 319 | return -ENODEV; | ||
| 320 | if (*mp & ~((1<<PWM_NCHAN)-1)) { | ||
| 321 | dev_warn(&pdev->dev, "mask 0x%x ... more than %d channels\n", | ||
| 322 | *mp, PWM_NCHAN); | ||
| 323 | return -EINVAL; | ||
| 324 | } | ||
| 325 | |||
| 326 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
| 327 | if (!p) | ||
| 328 | return -ENOMEM; | ||
| 329 | |||
| 330 | spin_lock_init(&p->lock); | ||
| 331 | p->pdev = pdev; | ||
| 332 | p->mask = *mp; | ||
| 333 | p->irq = irq; | ||
| 334 | p->base = ioremap(r->start, resource_size(r)); | ||
| 335 | if (!p->base) | ||
| 336 | goto fail; | ||
| 337 | p->clk = clk_get(&pdev->dev, "pwm_clk"); | ||
| 338 | if (IS_ERR(p->clk)) { | ||
| 339 | status = PTR_ERR(p->clk); | ||
| 340 | p->clk = NULL; | ||
| 341 | goto fail; | ||
| 342 | } | ||
| 343 | |||
| 344 | status = request_irq(irq, pwm_irq, 0, pdev->name, p); | ||
| 345 | if (status < 0) | ||
| 346 | goto fail; | ||
| 347 | |||
| 348 | pwm = p; | ||
| 349 | platform_set_drvdata(pdev, p); | ||
| 350 | |||
| 351 | return 0; | ||
| 352 | |||
| 353 | fail: | ||
| 354 | if (p->clk) | ||
| 355 | clk_put(p->clk); | ||
| 356 | if (p->base) | ||
| 357 | iounmap(p->base); | ||
| 358 | |||
| 359 | kfree(p); | ||
| 360 | return status; | ||
| 361 | } | ||
| 362 | |||
| 363 | static int __exit pwm_remove(struct platform_device *pdev) | ||
| 364 | { | ||
| 365 | struct pwm *p = platform_get_drvdata(pdev); | ||
| 366 | |||
| 367 | if (p != pwm) | ||
| 368 | return -EINVAL; | ||
| 369 | |||
| 370 | clk_enable(pwm->clk); | ||
| 371 | pwm_writel(pwm, PWM_DIS, (1 << PWM_NCHAN) - 1); | ||
| 372 | pwm_writel(pwm, PWM_IDR, (1 << PWM_NCHAN) - 1); | ||
| 373 | clk_disable(pwm->clk); | ||
| 374 | |||
| 375 | pwm = NULL; | ||
| 376 | |||
| 377 | free_irq(p->irq, p); | ||
| 378 | clk_put(p->clk); | ||
| 379 | iounmap(p->base); | ||
| 380 | kfree(p); | ||
| 381 | |||
| 382 | return 0; | ||
| 383 | } | ||
| 384 | |||
| 385 | static struct platform_driver atmel_pwm_driver = { | ||
| 386 | .driver = { | ||
| 387 | .name = "atmel_pwm", | ||
| 388 | .owner = THIS_MODULE, | ||
| 389 | }, | ||
| 390 | .remove = __exit_p(pwm_remove), | ||
| 391 | |||
| 392 | /* NOTE: PWM can keep running in AVR32 "idle" and "frozen" states; | ||
| 393 | * and all AT91sam9263 states, albeit at reduced clock rate if | ||
| 394 | * MCK becomes the slow clock (i.e. what Linux labels STR). | ||
| 395 | */ | ||
| 396 | }; | ||
| 397 | |||
| 398 | module_platform_driver_probe(atmel_pwm_driver, pwm_probe); | ||
| 399 | |||
| 400 | MODULE_DESCRIPTION("Driver for AT32/AT91 PWM module"); | ||
| 401 | MODULE_LICENSE("GPL"); | ||
| 402 | MODULE_ALIAS("platform:atmel_pwm"); | ||
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index 99a04686e45f..7b55f8a152d4 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c | |||
| @@ -1185,7 +1185,7 @@ static int bh1770_probe(struct i2c_client *client, | |||
| 1185 | struct bh1770_chip *chip; | 1185 | struct bh1770_chip *chip; |
| 1186 | int err; | 1186 | int err; |
| 1187 | 1187 | ||
| 1188 | chip = kzalloc(sizeof *chip, GFP_KERNEL); | 1188 | chip = devm_kzalloc(&client->dev, sizeof *chip, GFP_KERNEL); |
| 1189 | if (!chip) | 1189 | if (!chip) |
| 1190 | return -ENOMEM; | 1190 | return -ENOMEM; |
| 1191 | 1191 | ||
| @@ -1198,8 +1198,7 @@ static int bh1770_probe(struct i2c_client *client, | |||
| 1198 | 1198 | ||
| 1199 | if (client->dev.platform_data == NULL) { | 1199 | if (client->dev.platform_data == NULL) { |
| 1200 | dev_err(&client->dev, "platform data is mandatory\n"); | 1200 | dev_err(&client->dev, "platform data is mandatory\n"); |
| 1201 | err = -EINVAL; | 1201 | return -EINVAL; |
| 1202 | goto fail1; | ||
| 1203 | } | 1202 | } |
| 1204 | 1203 | ||
| 1205 | chip->pdata = client->dev.platform_data; | 1204 | chip->pdata = client->dev.platform_data; |
| @@ -1224,24 +1223,24 @@ static int bh1770_probe(struct i2c_client *client, | |||
| 1224 | chip->regs[0].supply = reg_vcc; | 1223 | chip->regs[0].supply = reg_vcc; |
| 1225 | chip->regs[1].supply = reg_vleds; | 1224 | chip->regs[1].supply = reg_vleds; |
| 1226 | 1225 | ||
| 1227 | err = regulator_bulk_get(&client->dev, | 1226 | err = devm_regulator_bulk_get(&client->dev, |
| 1228 | ARRAY_SIZE(chip->regs), chip->regs); | 1227 | ARRAY_SIZE(chip->regs), chip->regs); |
| 1229 | if (err < 0) { | 1228 | if (err < 0) { |
| 1230 | dev_err(&client->dev, "Cannot get regulators\n"); | 1229 | dev_err(&client->dev, "Cannot get regulators\n"); |
| 1231 | goto fail1; | 1230 | return err; |
| 1232 | } | 1231 | } |
| 1233 | 1232 | ||
| 1234 | err = regulator_bulk_enable(ARRAY_SIZE(chip->regs), | 1233 | err = regulator_bulk_enable(ARRAY_SIZE(chip->regs), |
| 1235 | chip->regs); | 1234 | chip->regs); |
| 1236 | if (err < 0) { | 1235 | if (err < 0) { |
| 1237 | dev_err(&client->dev, "Cannot enable regulators\n"); | 1236 | dev_err(&client->dev, "Cannot enable regulators\n"); |
| 1238 | goto fail2; | 1237 | return err; |
| 1239 | } | 1238 | } |
| 1240 | 1239 | ||
| 1241 | usleep_range(BH1770_STARTUP_DELAY, BH1770_STARTUP_DELAY * 2); | 1240 | usleep_range(BH1770_STARTUP_DELAY, BH1770_STARTUP_DELAY * 2); |
| 1242 | err = bh1770_detect(chip); | 1241 | err = bh1770_detect(chip); |
| 1243 | if (err < 0) | 1242 | if (err < 0) |
| 1244 | goto fail3; | 1243 | goto fail0; |
| 1245 | 1244 | ||
| 1246 | /* Start chip */ | 1245 | /* Start chip */ |
| 1247 | bh1770_chip_on(chip); | 1246 | bh1770_chip_on(chip); |
| @@ -1252,14 +1251,14 @@ static int bh1770_probe(struct i2c_client *client, | |||
| 1252 | if (chip->lux_corr == 0) { | 1251 | if (chip->lux_corr == 0) { |
| 1253 | dev_err(&client->dev, "Improper correction values\n"); | 1252 | dev_err(&client->dev, "Improper correction values\n"); |
| 1254 | err = -EINVAL; | 1253 | err = -EINVAL; |
| 1255 | goto fail3; | 1254 | goto fail0; |
| 1256 | } | 1255 | } |
| 1257 | 1256 | ||
| 1258 | if (chip->pdata->setup_resources) { | 1257 | if (chip->pdata->setup_resources) { |
| 1259 | err = chip->pdata->setup_resources(); | 1258 | err = chip->pdata->setup_resources(); |
| 1260 | if (err) { | 1259 | if (err) { |
| 1261 | err = -EINVAL; | 1260 | err = -EINVAL; |
| 1262 | goto fail3; | 1261 | goto fail0; |
| 1263 | } | 1262 | } |
| 1264 | } | 1263 | } |
| 1265 | 1264 | ||
| @@ -1267,7 +1266,7 @@ static int bh1770_probe(struct i2c_client *client, | |||
| 1267 | &bh1770_attribute_group); | 1266 | &bh1770_attribute_group); |
| 1268 | if (err < 0) { | 1267 | if (err < 0) { |
| 1269 | dev_err(&chip->client->dev, "Sysfs registration failed\n"); | 1268 | dev_err(&chip->client->dev, "Sysfs registration failed\n"); |
| 1270 | goto fail4; | 1269 | goto fail1; |
| 1271 | } | 1270 | } |
| 1272 | 1271 | ||
| 1273 | /* | 1272 | /* |
| @@ -1283,22 +1282,18 @@ static int bh1770_probe(struct i2c_client *client, | |||
| 1283 | if (err) { | 1282 | if (err) { |
| 1284 | dev_err(&client->dev, "could not get IRQ %d\n", | 1283 | dev_err(&client->dev, "could not get IRQ %d\n", |
| 1285 | client->irq); | 1284 | client->irq); |
| 1286 | goto fail5; | 1285 | goto fail2; |
| 1287 | } | 1286 | } |
| 1288 | regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs); | 1287 | regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs); |
| 1289 | return err; | 1288 | return err; |
| 1290 | fail5: | 1289 | fail2: |
| 1291 | sysfs_remove_group(&chip->client->dev.kobj, | 1290 | sysfs_remove_group(&chip->client->dev.kobj, |
| 1292 | &bh1770_attribute_group); | 1291 | &bh1770_attribute_group); |
| 1293 | fail4: | 1292 | fail1: |
| 1294 | if (chip->pdata->release_resources) | 1293 | if (chip->pdata->release_resources) |
| 1295 | chip->pdata->release_resources(); | 1294 | chip->pdata->release_resources(); |
| 1296 | fail3: | 1295 | fail0: |
| 1297 | regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs); | 1296 | regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs); |
| 1298 | fail2: | ||
| 1299 | regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs); | ||
| 1300 | fail1: | ||
| 1301 | kfree(chip); | ||
| 1302 | return err; | 1297 | return err; |
| 1303 | } | 1298 | } |
| 1304 | 1299 | ||
| @@ -1322,8 +1317,6 @@ static int bh1770_remove(struct i2c_client *client) | |||
| 1322 | pm_runtime_disable(&client->dev); | 1317 | pm_runtime_disable(&client->dev); |
| 1323 | pm_runtime_set_suspended(&client->dev); | 1318 | pm_runtime_set_suspended(&client->dev); |
| 1324 | 1319 | ||
| 1325 | regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs); | ||
| 1326 | kfree(chip); | ||
| 1327 | return 0; | 1320 | return 0; |
| 1328 | } | 1321 | } |
| 1329 | 1322 | ||
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c index 48ea33d15a79..4c4a59b25537 100644 --- a/drivers/misc/bh1780gli.c +++ b/drivers/misc/bh1780gli.c | |||
| @@ -149,50 +149,35 @@ static int bh1780_probe(struct i2c_client *client, | |||
| 149 | const struct i2c_device_id *id) | 149 | const struct i2c_device_id *id) |
| 150 | { | 150 | { |
| 151 | int ret; | 151 | int ret; |
| 152 | struct bh1780_data *ddata = NULL; | 152 | struct bh1780_data *ddata; |
| 153 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 153 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
| 154 | 154 | ||
| 155 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) { | 155 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) |
| 156 | ret = -EIO; | 156 | return -EIO; |
| 157 | goto err_op_failed; | ||
| 158 | } | ||
| 159 | 157 | ||
| 160 | ddata = kzalloc(sizeof(struct bh1780_data), GFP_KERNEL); | 158 | ddata = devm_kzalloc(&client->dev, sizeof(struct bh1780_data), |
| 161 | if (ddata == NULL) { | 159 | GFP_KERNEL); |
| 162 | ret = -ENOMEM; | 160 | if (ddata == NULL) |
| 163 | goto err_op_failed; | 161 | return -ENOMEM; |
| 164 | } | ||
| 165 | 162 | ||
| 166 | ddata->client = client; | 163 | ddata->client = client; |
| 167 | i2c_set_clientdata(client, ddata); | 164 | i2c_set_clientdata(client, ddata); |
| 168 | 165 | ||
| 169 | ret = bh1780_read(ddata, BH1780_REG_PARTID, "PART ID"); | 166 | ret = bh1780_read(ddata, BH1780_REG_PARTID, "PART ID"); |
| 170 | if (ret < 0) | 167 | if (ret < 0) |
| 171 | goto err_op_failed; | 168 | return ret; |
| 172 | 169 | ||
| 173 | dev_info(&client->dev, "Ambient Light Sensor, Rev : %d\n", | 170 | dev_info(&client->dev, "Ambient Light Sensor, Rev : %d\n", |
| 174 | (ret & BH1780_REVMASK)); | 171 | (ret & BH1780_REVMASK)); |
| 175 | 172 | ||
| 176 | mutex_init(&ddata->lock); | 173 | mutex_init(&ddata->lock); |
| 177 | 174 | ||
| 178 | ret = sysfs_create_group(&client->dev.kobj, &bh1780_attr_group); | 175 | return sysfs_create_group(&client->dev.kobj, &bh1780_attr_group); |
| 179 | if (ret) | ||
| 180 | goto err_op_failed; | ||
| 181 | |||
| 182 | return 0; | ||
| 183 | |||
| 184 | err_op_failed: | ||
| 185 | kfree(ddata); | ||
| 186 | return ret; | ||
| 187 | } | 176 | } |
| 188 | 177 | ||
| 189 | static int bh1780_remove(struct i2c_client *client) | 178 | static int bh1780_remove(struct i2c_client *client) |
| 190 | { | 179 | { |
| 191 | struct bh1780_data *ddata; | ||
| 192 | |||
| 193 | ddata = i2c_get_clientdata(client); | ||
| 194 | sysfs_remove_group(&client->dev.kobj, &bh1780_attr_group); | 180 | sysfs_remove_group(&client->dev.kobj, &bh1780_attr_group); |
| 195 | kfree(ddata); | ||
| 196 | 181 | ||
| 197 | return 0; | 182 | return 0; |
| 198 | } | 183 | } |
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c index 14d90eae605b..55e913b7eb11 100644 --- a/drivers/misc/carma/carma-fpga.c +++ b/drivers/misc/carma/carma-fpga.c | |||
| @@ -954,10 +954,7 @@ static int data_debugfs_init(struct fpga_device *priv) | |||
| 954 | { | 954 | { |
| 955 | priv->dbg_entry = debugfs_create_file(drv_name, S_IRUGO, NULL, priv, | 955 | priv->dbg_entry = debugfs_create_file(drv_name, S_IRUGO, NULL, priv, |
| 956 | &data_debug_fops); | 956 | &data_debug_fops); |
| 957 | if (IS_ERR(priv->dbg_entry)) | 957 | return PTR_ERR_OR_ZERO(priv->dbg_entry); |
| 958 | return PTR_ERR(priv->dbg_entry); | ||
| 959 | |||
| 960 | return 0; | ||
| 961 | } | 958 | } |
| 962 | 959 | ||
| 963 | static void data_debugfs_exit(struct fpga_device *priv) | 960 | static void data_debugfs_exit(struct fpga_device *priv) |
diff --git a/drivers/misc/dummy-irq.c b/drivers/misc/dummy-irq.c index 4d0db15df115..acbbe0390be4 100644 --- a/drivers/misc/dummy-irq.c +++ b/drivers/misc/dummy-irq.c | |||
| @@ -61,3 +61,4 @@ MODULE_LICENSE("GPL"); | |||
| 61 | MODULE_AUTHOR("Jiri Kosina"); | 61 | MODULE_AUTHOR("Jiri Kosina"); |
| 62 | module_param(irq, uint, 0444); | 62 | module_param(irq, uint, 0444); |
| 63 | MODULE_PARM_DESC(irq, "The IRQ to register for"); | 63 | MODULE_PARM_DESC(irq, "The IRQ to register for"); |
| 64 | MODULE_DESCRIPTION("Dummy IRQ handler driver"); | ||
diff --git a/drivers/misc/fuse/Makefile b/drivers/misc/fuse/Makefile new file mode 100644 index 000000000000..0679c4febc89 --- /dev/null +++ b/drivers/misc/fuse/Makefile | |||
| @@ -0,0 +1 @@ | |||
| obj-$(CONFIG_ARCH_TEGRA) += tegra/ | |||
diff --git a/drivers/misc/genwqe/Kconfig b/drivers/misc/genwqe/Kconfig index 6069d8cd79d7..4c0a033cbfdb 100644 --- a/drivers/misc/genwqe/Kconfig +++ b/drivers/misc/genwqe/Kconfig | |||
| @@ -11,3 +11,9 @@ menuconfig GENWQE | |||
| 11 | Enables PCIe card driver for IBM GenWQE accelerators. | 11 | Enables PCIe card driver for IBM GenWQE accelerators. |
| 12 | The user-space interface is described in | 12 | The user-space interface is described in |
| 13 | include/linux/genwqe/genwqe_card.h. | 13 | include/linux/genwqe/genwqe_card.h. |
| 14 | |||
| 15 | config GENWQE_PLATFORM_ERROR_RECOVERY | ||
| 16 | int "Use platform recovery procedures (0=off, 1=on)" | ||
| 17 | depends on GENWQE | ||
| 18 | default 1 if PPC64 | ||
| 19 | default 0 | ||
diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c index 74d51c9bb858..43bbabc96b6c 100644 --- a/drivers/misc/genwqe/card_base.c +++ b/drivers/misc/genwqe/card_base.c | |||
| @@ -38,7 +38,6 @@ | |||
| 38 | #include <linux/notifier.h> | 38 | #include <linux/notifier.h> |
| 39 | #include <linux/device.h> | 39 | #include <linux/device.h> |
| 40 | #include <linux/log2.h> | 40 | #include <linux/log2.h> |
| 41 | #include <linux/genwqe/genwqe_card.h> | ||
| 42 | 41 | ||
| 43 | #include "card_base.h" | 42 | #include "card_base.h" |
| 44 | #include "card_ddcb.h" | 43 | #include "card_ddcb.h" |
| @@ -58,7 +57,7 @@ static struct dentry *debugfs_genwqe; | |||
| 58 | static struct genwqe_dev *genwqe_devices[GENWQE_CARD_NO_MAX]; | 57 | static struct genwqe_dev *genwqe_devices[GENWQE_CARD_NO_MAX]; |
| 59 | 58 | ||
| 60 | /* PCI structure for identifying device by PCI vendor and device ID */ | 59 | /* PCI structure for identifying device by PCI vendor and device ID */ |
| 61 | static DEFINE_PCI_DEVICE_TABLE(genwqe_device_table) = { | 60 | static const struct pci_device_id genwqe_device_table[] = { |
| 62 | { .vendor = PCI_VENDOR_ID_IBM, | 61 | { .vendor = PCI_VENDOR_ID_IBM, |
| 63 | .device = PCI_DEVICE_GENWQE, | 62 | .device = PCI_DEVICE_GENWQE, |
| 64 | .subvendor = PCI_SUBVENDOR_ID_IBM, | 63 | .subvendor = PCI_SUBVENDOR_ID_IBM, |
| @@ -140,6 +139,12 @@ static struct genwqe_dev *genwqe_dev_alloc(void) | |||
| 140 | cd->class_genwqe = class_genwqe; | 139 | cd->class_genwqe = class_genwqe; |
| 141 | cd->debugfs_genwqe = debugfs_genwqe; | 140 | cd->debugfs_genwqe = debugfs_genwqe; |
| 142 | 141 | ||
| 142 | /* | ||
| 143 | * This comes from kernel config option and can be overritten via | ||
| 144 | * debugfs. | ||
| 145 | */ | ||
| 146 | cd->use_platform_recovery = CONFIG_GENWQE_PLATFORM_ERROR_RECOVERY; | ||
| 147 | |||
| 143 | init_waitqueue_head(&cd->queue_waitq); | 148 | init_waitqueue_head(&cd->queue_waitq); |
| 144 | 149 | ||
| 145 | spin_lock_init(&cd->file_lock); | 150 | spin_lock_init(&cd->file_lock); |
| @@ -761,6 +766,124 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd) | |||
| 761 | } | 766 | } |
| 762 | 767 | ||
| 763 | /** | 768 | /** |
| 769 | * genwqe_pci_fundamental_reset() - trigger a PCIe fundamental reset on the slot | ||
| 770 | * | ||
| 771 | * Note: pci_set_pcie_reset_state() is not implemented on all archs, so this | ||
| 772 | * reset method will not work in all cases. | ||
| 773 | * | ||
| 774 | * Return: 0 on success or error code from pci_set_pcie_reset_state() | ||
| 775 | */ | ||
| 776 | static int genwqe_pci_fundamental_reset(struct pci_dev *pci_dev) | ||
| 777 | { | ||
| 778 | int rc; | ||
| 779 | |||
| 780 | /* | ||
| 781 | * lock pci config space access from userspace, | ||
| 782 | * save state and issue PCIe fundamental reset | ||
| 783 | */ | ||
| 784 | pci_cfg_access_lock(pci_dev); | ||
| 785 | pci_save_state(pci_dev); | ||
| 786 | rc = pci_set_pcie_reset_state(pci_dev, pcie_warm_reset); | ||
| 787 | if (!rc) { | ||
| 788 | /* keep PCIe reset asserted for 250ms */ | ||
| 789 | msleep(250); | ||
| 790 | pci_set_pcie_reset_state(pci_dev, pcie_deassert_reset); | ||
| 791 | /* Wait for 2s to reload flash and train the link */ | ||
| 792 | msleep(2000); | ||
| 793 | } | ||
| 794 | pci_restore_state(pci_dev); | ||
| 795 | pci_cfg_access_unlock(pci_dev); | ||
| 796 | return rc; | ||
| 797 | } | ||
| 798 | |||
| 799 | |||
| 800 | static int genwqe_platform_recovery(struct genwqe_dev *cd) | ||
| 801 | { | ||
| 802 | struct pci_dev *pci_dev = cd->pci_dev; | ||
| 803 | int rc; | ||
| 804 | |||
| 805 | dev_info(&pci_dev->dev, | ||
| 806 | "[%s] resetting card for error recovery\n", __func__); | ||
| 807 | |||
| 808 | /* Clear out error injection flags */ | ||
| 809 | cd->err_inject &= ~(GENWQE_INJECT_HARDWARE_FAILURE | | ||
| 810 | GENWQE_INJECT_GFIR_FATAL | | ||
| 811 | GENWQE_INJECT_GFIR_INFO); | ||
| 812 | |||
| 813 | genwqe_stop(cd); | ||
| 814 | |||
| 815 | /* Try recoverying the card with fundamental reset */ | ||
| 816 | rc = genwqe_pci_fundamental_reset(pci_dev); | ||
| 817 | if (!rc) { | ||
| 818 | rc = genwqe_start(cd); | ||
| 819 | if (!rc) | ||
| 820 | dev_info(&pci_dev->dev, | ||
| 821 | "[%s] card recovered\n", __func__); | ||
| 822 | else | ||
| 823 | dev_err(&pci_dev->dev, | ||
| 824 | "[%s] err: cannot start card services! (err=%d)\n", | ||
| 825 | __func__, rc); | ||
| 826 | } else { | ||
| 827 | dev_err(&pci_dev->dev, | ||
| 828 | "[%s] card reset failed\n", __func__); | ||
| 829 | } | ||
| 830 | |||
| 831 | return rc; | ||
| 832 | } | ||
| 833 | |||
| 834 | /* | ||
| 835 | * genwqe_reload_bistream() - reload card bitstream | ||
| 836 | * | ||
| 837 | * Set the appropriate register and call fundamental reset to reaload the card | ||
| 838 | * bitstream. | ||
| 839 | * | ||
| 840 | * Return: 0 on success, error code otherwise | ||
| 841 | */ | ||
| 842 | static int genwqe_reload_bistream(struct genwqe_dev *cd) | ||
| 843 | { | ||
| 844 | struct pci_dev *pci_dev = cd->pci_dev; | ||
| 845 | int rc; | ||
| 846 | |||
| 847 | dev_info(&pci_dev->dev, | ||
| 848 | "[%s] resetting card for bitstream reload\n", | ||
| 849 | __func__); | ||
| 850 | |||
| 851 | genwqe_stop(cd); | ||
| 852 | |||
| 853 | /* | ||
| 854 | * Cause a CPLD reprogram with the 'next_bitstream' | ||
| 855 | * partition on PCIe hot or fundamental reset | ||
| 856 | */ | ||
| 857 | __genwqe_writeq(cd, IO_SLC_CFGREG_SOFTRESET, | ||
| 858 | (cd->softreset & 0xcull) | 0x70ull); | ||
| 859 | |||
| 860 | rc = genwqe_pci_fundamental_reset(pci_dev); | ||
| 861 | if (rc) { | ||
| 862 | /* | ||
| 863 | * A fundamental reset failure can be caused | ||
| 864 | * by lack of support on the arch, so we just | ||
| 865 | * log the error and try to start the card | ||
| 866 | * again. | ||
| 867 | */ | ||
| 868 | dev_err(&pci_dev->dev, | ||
| 869 | "[%s] err: failed to reset card for bitstream reload\n", | ||
| 870 | __func__); | ||
| 871 | } | ||
| 872 | |||
| 873 | rc = genwqe_start(cd); | ||
| 874 | if (rc) { | ||
| 875 | dev_err(&pci_dev->dev, | ||
| 876 | "[%s] err: cannot start card services! (err=%d)\n", | ||
| 877 | __func__, rc); | ||
| 878 | return rc; | ||
| 879 | } | ||
| 880 | dev_info(&pci_dev->dev, | ||
| 881 | "[%s] card reloaded\n", __func__); | ||
| 882 | return 0; | ||
| 883 | } | ||
| 884 | |||
| 885 | |||
| 886 | /** | ||
| 764 | * genwqe_health_thread() - Health checking thread | 887 | * genwqe_health_thread() - Health checking thread |
| 765 | * | 888 | * |
| 766 | * This thread is only started for the PF of the card. | 889 | * This thread is only started for the PF of the card. |
| @@ -786,6 +909,7 @@ static int genwqe_health_thread(void *data) | |||
| 786 | struct pci_dev *pci_dev = cd->pci_dev; | 909 | struct pci_dev *pci_dev = cd->pci_dev; |
| 787 | u64 gfir, gfir_masked, slu_unitcfg, app_unitcfg; | 910 | u64 gfir, gfir_masked, slu_unitcfg, app_unitcfg; |
| 788 | 911 | ||
| 912 | health_thread_begin: | ||
| 789 | while (!kthread_should_stop()) { | 913 | while (!kthread_should_stop()) { |
| 790 | rc = wait_event_interruptible_timeout(cd->health_waitq, | 914 | rc = wait_event_interruptible_timeout(cd->health_waitq, |
| 791 | (genwqe_health_check_cond(cd, &gfir) || | 915 | (genwqe_health_check_cond(cd, &gfir) || |
| @@ -846,6 +970,13 @@ static int genwqe_health_thread(void *data) | |||
| 846 | } | 970 | } |
| 847 | } | 971 | } |
| 848 | 972 | ||
| 973 | if (cd->card_state == GENWQE_CARD_RELOAD_BITSTREAM) { | ||
| 974 | /* Userspace requested card bitstream reload */ | ||
| 975 | rc = genwqe_reload_bistream(cd); | ||
| 976 | if (rc) | ||
| 977 | goto fatal_error; | ||
| 978 | } | ||
| 979 | |||
| 849 | cd->last_gfir = gfir; | 980 | cd->last_gfir = gfir; |
| 850 | cond_resched(); | 981 | cond_resched(); |
| 851 | } | 982 | } |
| @@ -853,6 +984,28 @@ static int genwqe_health_thread(void *data) | |||
| 853 | return 0; | 984 | return 0; |
| 854 | 985 | ||
| 855 | fatal_error: | 986 | fatal_error: |
| 987 | if (cd->use_platform_recovery) { | ||
| 988 | /* | ||
| 989 | * Since we use raw accessors, EEH errors won't be detected | ||
| 990 | * by the platform until we do a non-raw MMIO or config space | ||
| 991 | * read | ||
| 992 | */ | ||
| 993 | readq(cd->mmio + IO_SLC_CFGREG_GFIR); | ||
| 994 | |||
| 995 | /* We do nothing if the card is going over PCI recovery */ | ||
| 996 | if (pci_channel_offline(pci_dev)) | ||
| 997 | return -EIO; | ||
| 998 | |||
| 999 | /* | ||
| 1000 | * If it's supported by the platform, we try a fundamental reset | ||
| 1001 | * to recover from a fatal error. Otherwise, we continue to wait | ||
| 1002 | * for an external recovery procedure to take care of it. | ||
| 1003 | */ | ||
| 1004 | rc = genwqe_platform_recovery(cd); | ||
| 1005 | if (!rc) | ||
| 1006 | goto health_thread_begin; | ||
| 1007 | } | ||
| 1008 | |||
| 856 | dev_err(&pci_dev->dev, | 1009 | dev_err(&pci_dev->dev, |
| 857 | "[%s] card unusable. Please trigger unbind!\n", __func__); | 1010 | "[%s] card unusable. Please trigger unbind!\n", __func__); |
| 858 | 1011 | ||
| @@ -958,6 +1111,9 @@ static int genwqe_pci_setup(struct genwqe_dev *cd) | |||
| 958 | pci_set_master(pci_dev); | 1111 | pci_set_master(pci_dev); |
| 959 | pci_enable_pcie_error_reporting(pci_dev); | 1112 | pci_enable_pcie_error_reporting(pci_dev); |
| 960 | 1113 | ||
| 1114 | /* EEH recovery requires PCIe fundamental reset */ | ||
| 1115 | pci_dev->needs_freset = 1; | ||
| 1116 | |||
| 961 | /* request complete BAR-0 space (length = 0) */ | 1117 | /* request complete BAR-0 space (length = 0) */ |
| 962 | cd->mmio_len = pci_resource_len(pci_dev, 0); | 1118 | cd->mmio_len = pci_resource_len(pci_dev, 0); |
| 963 | cd->mmio = pci_iomap(pci_dev, 0, 0); | 1119 | cd->mmio = pci_iomap(pci_dev, 0, 0); |
| @@ -1096,23 +1252,40 @@ static pci_ers_result_t genwqe_err_error_detected(struct pci_dev *pci_dev, | |||
| 1096 | 1252 | ||
| 1097 | dev_err(&pci_dev->dev, "[%s] state=%d\n", __func__, state); | 1253 | dev_err(&pci_dev->dev, "[%s] state=%d\n", __func__, state); |
| 1098 | 1254 | ||
| 1099 | if (pci_dev == NULL) | ||
| 1100 | return PCI_ERS_RESULT_NEED_RESET; | ||
| 1101 | |||
| 1102 | cd = dev_get_drvdata(&pci_dev->dev); | 1255 | cd = dev_get_drvdata(&pci_dev->dev); |
| 1103 | if (cd == NULL) | 1256 | if (cd == NULL) |
| 1104 | return PCI_ERS_RESULT_NEED_RESET; | 1257 | return PCI_ERS_RESULT_DISCONNECT; |
| 1105 | 1258 | ||
| 1106 | switch (state) { | 1259 | /* Stop the card */ |
| 1107 | case pci_channel_io_normal: | 1260 | genwqe_health_check_stop(cd); |
| 1108 | return PCI_ERS_RESULT_CAN_RECOVER; | 1261 | genwqe_stop(cd); |
| 1109 | case pci_channel_io_frozen: | 1262 | |
| 1110 | return PCI_ERS_RESULT_NEED_RESET; | 1263 | /* |
| 1111 | case pci_channel_io_perm_failure: | 1264 | * On permanent failure, the PCI code will call device remove |
| 1265 | * after the return of this function. | ||
| 1266 | * genwqe_stop() can be called twice. | ||
| 1267 | */ | ||
| 1268 | if (state == pci_channel_io_perm_failure) { | ||
| 1112 | return PCI_ERS_RESULT_DISCONNECT; | 1269 | return PCI_ERS_RESULT_DISCONNECT; |
| 1270 | } else { | ||
| 1271 | genwqe_pci_remove(cd); | ||
| 1272 | return PCI_ERS_RESULT_NEED_RESET; | ||
| 1113 | } | 1273 | } |
| 1274 | } | ||
| 1275 | |||
| 1276 | static pci_ers_result_t genwqe_err_slot_reset(struct pci_dev *pci_dev) | ||
| 1277 | { | ||
| 1278 | int rc; | ||
| 1279 | struct genwqe_dev *cd = dev_get_drvdata(&pci_dev->dev); | ||
| 1114 | 1280 | ||
| 1115 | return PCI_ERS_RESULT_NEED_RESET; | 1281 | rc = genwqe_pci_setup(cd); |
| 1282 | if (!rc) { | ||
| 1283 | return PCI_ERS_RESULT_RECOVERED; | ||
| 1284 | } else { | ||
| 1285 | dev_err(&pci_dev->dev, | ||
| 1286 | "err: problems with PCI setup (err=%d)\n", rc); | ||
| 1287 | return PCI_ERS_RESULT_DISCONNECT; | ||
| 1288 | } | ||
| 1116 | } | 1289 | } |
| 1117 | 1290 | ||
| 1118 | static pci_ers_result_t genwqe_err_result_none(struct pci_dev *dev) | 1291 | static pci_ers_result_t genwqe_err_result_none(struct pci_dev *dev) |
| @@ -1120,8 +1293,22 @@ static pci_ers_result_t genwqe_err_result_none(struct pci_dev *dev) | |||
| 1120 | return PCI_ERS_RESULT_NONE; | 1293 | return PCI_ERS_RESULT_NONE; |
| 1121 | } | 1294 | } |
| 1122 | 1295 | ||
| 1123 | static void genwqe_err_resume(struct pci_dev *dev) | 1296 | static void genwqe_err_resume(struct pci_dev *pci_dev) |
| 1124 | { | 1297 | { |
| 1298 | int rc; | ||
| 1299 | struct genwqe_dev *cd = dev_get_drvdata(&pci_dev->dev); | ||
| 1300 | |||
| 1301 | rc = genwqe_start(cd); | ||
| 1302 | if (!rc) { | ||
| 1303 | rc = genwqe_health_check_start(cd); | ||
| 1304 | if (rc) | ||
| 1305 | dev_err(&pci_dev->dev, | ||
| 1306 | "err: cannot start health checking! (err=%d)\n", | ||
| 1307 | rc); | ||
| 1308 | } else { | ||
| 1309 | dev_err(&pci_dev->dev, | ||
| 1310 | "err: cannot start card services! (err=%d)\n", rc); | ||
| 1311 | } | ||
| 1125 | } | 1312 | } |
| 1126 | 1313 | ||
| 1127 | static int genwqe_sriov_configure(struct pci_dev *dev, int numvfs) | 1314 | static int genwqe_sriov_configure(struct pci_dev *dev, int numvfs) |
| @@ -1144,7 +1331,7 @@ static struct pci_error_handlers genwqe_err_handler = { | |||
| 1144 | .error_detected = genwqe_err_error_detected, | 1331 | .error_detected = genwqe_err_error_detected, |
| 1145 | .mmio_enabled = genwqe_err_result_none, | 1332 | .mmio_enabled = genwqe_err_result_none, |
| 1146 | .link_reset = genwqe_err_result_none, | 1333 | .link_reset = genwqe_err_result_none, |
| 1147 | .slot_reset = genwqe_err_result_none, | 1334 | .slot_reset = genwqe_err_slot_reset, |
| 1148 | .resume = genwqe_err_resume, | 1335 | .resume = genwqe_err_resume, |
| 1149 | }; | 1336 | }; |
| 1150 | 1337 | ||
diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h index 0e608a288603..67abd8cb2247 100644 --- a/drivers/misc/genwqe/card_base.h +++ b/drivers/misc/genwqe/card_base.h | |||
| @@ -291,6 +291,8 @@ struct genwqe_dev { | |||
| 291 | struct task_struct *health_thread; | 291 | struct task_struct *health_thread; |
| 292 | wait_queue_head_t health_waitq; | 292 | wait_queue_head_t health_waitq; |
| 293 | 293 | ||
| 294 | int use_platform_recovery; /* use platform recovery mechanisms */ | ||
| 295 | |||
| 294 | /* char device */ | 296 | /* char device */ |
| 295 | dev_t devnum_genwqe; /* major/minor num card */ | 297 | dev_t devnum_genwqe; /* major/minor num card */ |
| 296 | struct class *class_genwqe; /* reference to class object */ | 298 | struct class *class_genwqe; /* reference to class object */ |
diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c index c8046db2d5a2..dc9851a5540e 100644 --- a/drivers/misc/genwqe/card_ddcb.c +++ b/drivers/misc/genwqe/card_ddcb.c | |||
| @@ -1118,7 +1118,21 @@ static irqreturn_t genwqe_pf_isr(int irq, void *dev_id) | |||
| 1118 | * safer, but slower for the good-case ... See above. | 1118 | * safer, but slower for the good-case ... See above. |
| 1119 | */ | 1119 | */ |
| 1120 | gfir = __genwqe_readq(cd, IO_SLC_CFGREG_GFIR); | 1120 | gfir = __genwqe_readq(cd, IO_SLC_CFGREG_GFIR); |
| 1121 | if ((gfir & GFIR_ERR_TRIGGER) != 0x0) { | 1121 | if (((gfir & GFIR_ERR_TRIGGER) != 0x0) && |
| 1122 | !pci_channel_offline(pci_dev)) { | ||
| 1123 | |||
| 1124 | if (cd->use_platform_recovery) { | ||
| 1125 | /* | ||
| 1126 | * Since we use raw accessors, EEH errors won't be | ||
| 1127 | * detected by the platform until we do a non-raw | ||
| 1128 | * MMIO or config space read | ||
| 1129 | */ | ||
| 1130 | readq(cd->mmio + IO_SLC_CFGREG_GFIR); | ||
| 1131 | |||
| 1132 | /* Don't do anything if the PCI channel is frozen */ | ||
| 1133 | if (pci_channel_offline(pci_dev)) | ||
| 1134 | goto exit; | ||
| 1135 | } | ||
| 1122 | 1136 | ||
| 1123 | wake_up_interruptible(&cd->health_waitq); | 1137 | wake_up_interruptible(&cd->health_waitq); |
| 1124 | 1138 | ||
| @@ -1126,12 +1140,12 @@ static irqreturn_t genwqe_pf_isr(int irq, void *dev_id) | |||
| 1126 | * By default GFIRs causes recovery actions. This | 1140 | * By default GFIRs causes recovery actions. This |
| 1127 | * count is just for debug when recovery is masked. | 1141 | * count is just for debug when recovery is masked. |
| 1128 | */ | 1142 | */ |
| 1129 | printk_ratelimited(KERN_ERR | 1143 | dev_err_ratelimited(&pci_dev->dev, |
| 1130 | "%s %s: [%s] GFIR=%016llx\n", | 1144 | "[%s] GFIR=%016llx\n", |
| 1131 | GENWQE_DEVNAME, dev_name(&pci_dev->dev), | 1145 | __func__, gfir); |
| 1132 | __func__, gfir); | ||
| 1133 | } | 1146 | } |
| 1134 | 1147 | ||
| 1148 | exit: | ||
| 1135 | return IRQ_HANDLED; | 1149 | return IRQ_HANDLED; |
| 1136 | } | 1150 | } |
| 1137 | 1151 | ||
| @@ -1237,9 +1251,7 @@ int genwqe_setup_service_layer(struct genwqe_dev *cd) | |||
| 1237 | } | 1251 | } |
| 1238 | 1252 | ||
| 1239 | rc = genwqe_set_interrupt_capability(cd, GENWQE_MSI_IRQS); | 1253 | rc = genwqe_set_interrupt_capability(cd, GENWQE_MSI_IRQS); |
| 1240 | if (rc > 0) | 1254 | if (rc) { |
| 1241 | rc = genwqe_set_interrupt_capability(cd, rc); | ||
| 1242 | if (rc != 0) { | ||
| 1243 | rc = -ENODEV; | 1255 | rc = -ENODEV; |
| 1244 | goto stop_kthread; | 1256 | goto stop_kthread; |
| 1245 | } | 1257 | } |
diff --git a/drivers/misc/genwqe/card_debugfs.c b/drivers/misc/genwqe/card_debugfs.c index 0a33ade64109..c9b4d6d0eb99 100644 --- a/drivers/misc/genwqe/card_debugfs.c +++ b/drivers/misc/genwqe/card_debugfs.c | |||
| @@ -485,6 +485,13 @@ int genwqe_init_debugfs(struct genwqe_dev *cd) | |||
| 485 | goto err1; | 485 | goto err1; |
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | file = debugfs_create_u32("use_platform_recovery", 0666, root, | ||
| 489 | &cd->use_platform_recovery); | ||
| 490 | if (!file) { | ||
| 491 | ret = -ENOMEM; | ||
| 492 | goto err1; | ||
| 493 | } | ||
| 494 | |||
| 488 | cd->debugfs_root = root; | 495 | cd->debugfs_root = root; |
| 489 | return 0; | 496 | return 0; |
| 490 | err1: | 497 | err1: |
diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c index 1d2f163a1906..aae42555e2ca 100644 --- a/drivers/misc/genwqe/card_dev.c +++ b/drivers/misc/genwqe/card_dev.c | |||
| @@ -1048,10 +1048,15 @@ static long genwqe_ioctl(struct file *filp, unsigned int cmd, | |||
| 1048 | int rc = 0; | 1048 | int rc = 0; |
| 1049 | struct genwqe_file *cfile = (struct genwqe_file *)filp->private_data; | 1049 | struct genwqe_file *cfile = (struct genwqe_file *)filp->private_data; |
| 1050 | struct genwqe_dev *cd = cfile->cd; | 1050 | struct genwqe_dev *cd = cfile->cd; |
| 1051 | struct pci_dev *pci_dev = cd->pci_dev; | ||
| 1051 | struct genwqe_reg_io __user *io; | 1052 | struct genwqe_reg_io __user *io; |
| 1052 | u64 val; | 1053 | u64 val; |
| 1053 | u32 reg_offs; | 1054 | u32 reg_offs; |
| 1054 | 1055 | ||
| 1056 | /* Return -EIO if card hit EEH */ | ||
| 1057 | if (pci_channel_offline(pci_dev)) | ||
| 1058 | return -EIO; | ||
| 1059 | |||
| 1055 | if (_IOC_TYPE(cmd) != GENWQE_IOC_CODE) | 1060 | if (_IOC_TYPE(cmd) != GENWQE_IOC_CODE) |
| 1056 | return -EINVAL; | 1061 | return -EINVAL; |
| 1057 | 1062 | ||
diff --git a/drivers/misc/genwqe/card_sysfs.c b/drivers/misc/genwqe/card_sysfs.c index a72a99266c3c..7232e40a3ad9 100644 --- a/drivers/misc/genwqe/card_sysfs.c +++ b/drivers/misc/genwqe/card_sysfs.c | |||
| @@ -223,6 +223,30 @@ static ssize_t next_bitstream_store(struct device *dev, | |||
| 223 | } | 223 | } |
| 224 | static DEVICE_ATTR_RW(next_bitstream); | 224 | static DEVICE_ATTR_RW(next_bitstream); |
| 225 | 225 | ||
| 226 | static ssize_t reload_bitstream_store(struct device *dev, | ||
| 227 | struct device_attribute *attr, | ||
| 228 | const char *buf, size_t count) | ||
| 229 | { | ||
| 230 | int reload; | ||
| 231 | struct genwqe_dev *cd = dev_get_drvdata(dev); | ||
| 232 | |||
| 233 | if (kstrtoint(buf, 0, &reload) < 0) | ||
| 234 | return -EINVAL; | ||
| 235 | |||
| 236 | if (reload == 0x1) { | ||
| 237 | if (cd->card_state == GENWQE_CARD_UNUSED || | ||
| 238 | cd->card_state == GENWQE_CARD_USED) | ||
| 239 | cd->card_state = GENWQE_CARD_RELOAD_BITSTREAM; | ||
| 240 | else | ||
| 241 | return -EIO; | ||
| 242 | } else { | ||
| 243 | return -EINVAL; | ||
| 244 | } | ||
| 245 | |||
| 246 | return count; | ||
| 247 | } | ||
| 248 | static DEVICE_ATTR_WO(reload_bitstream); | ||
| 249 | |||
| 226 | /* | 250 | /* |
| 227 | * Create device_attribute structures / params: name, mode, show, store | 251 | * Create device_attribute structures / params: name, mode, show, store |
| 228 | * additional flag if valid in VF | 252 | * additional flag if valid in VF |
| @@ -239,6 +263,7 @@ static struct attribute *genwqe_attributes[] = { | |||
| 239 | &dev_attr_status.attr, | 263 | &dev_attr_status.attr, |
| 240 | &dev_attr_freerunning_timer.attr, | 264 | &dev_attr_freerunning_timer.attr, |
| 241 | &dev_attr_queue_working_time.attr, | 265 | &dev_attr_queue_working_time.attr, |
| 266 | &dev_attr_reload_bitstream.attr, | ||
| 242 | NULL, | 267 | NULL, |
| 243 | }; | 268 | }; |
| 244 | 269 | ||
diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index 62cc6bb3f62e..a6400f09229c 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c | |||
| @@ -53,12 +53,17 @@ | |||
| 53 | */ | 53 | */ |
| 54 | int __genwqe_writeq(struct genwqe_dev *cd, u64 byte_offs, u64 val) | 54 | int __genwqe_writeq(struct genwqe_dev *cd, u64 byte_offs, u64 val) |
| 55 | { | 55 | { |
| 56 | struct pci_dev *pci_dev = cd->pci_dev; | ||
| 57 | |||
| 56 | if (cd->err_inject & GENWQE_INJECT_HARDWARE_FAILURE) | 58 | if (cd->err_inject & GENWQE_INJECT_HARDWARE_FAILURE) |
| 57 | return -EIO; | 59 | return -EIO; |
| 58 | 60 | ||
| 59 | if (cd->mmio == NULL) | 61 | if (cd->mmio == NULL) |
| 60 | return -EIO; | 62 | return -EIO; |
| 61 | 63 | ||
| 64 | if (pci_channel_offline(pci_dev)) | ||
| 65 | return -EIO; | ||
| 66 | |||
| 62 | __raw_writeq((__force u64)cpu_to_be64(val), cd->mmio + byte_offs); | 67 | __raw_writeq((__force u64)cpu_to_be64(val), cd->mmio + byte_offs); |
| 63 | return 0; | 68 | return 0; |
| 64 | } | 69 | } |
| @@ -99,12 +104,17 @@ u64 __genwqe_readq(struct genwqe_dev *cd, u64 byte_offs) | |||
| 99 | */ | 104 | */ |
| 100 | int __genwqe_writel(struct genwqe_dev *cd, u64 byte_offs, u32 val) | 105 | int __genwqe_writel(struct genwqe_dev *cd, u64 byte_offs, u32 val) |
| 101 | { | 106 | { |
| 107 | struct pci_dev *pci_dev = cd->pci_dev; | ||
| 108 | |||
| 102 | if (cd->err_inject & GENWQE_INJECT_HARDWARE_FAILURE) | 109 | if (cd->err_inject & GENWQE_INJECT_HARDWARE_FAILURE) |
| 103 | return -EIO; | 110 | return -EIO; |
| 104 | 111 | ||
| 105 | if (cd->mmio == NULL) | 112 | if (cd->mmio == NULL) |
| 106 | return -EIO; | 113 | return -EIO; |
| 107 | 114 | ||
| 115 | if (pci_channel_offline(pci_dev)) | ||
| 116 | return -EIO; | ||
| 117 | |||
| 108 | __raw_writel((__force u32)cpu_to_be32(val), cd->mmio + byte_offs); | 118 | __raw_writel((__force u32)cpu_to_be32(val), cd->mmio + byte_offs); |
| 109 | return 0; | 119 | return 0; |
| 110 | } | 120 | } |
| @@ -718,10 +728,12 @@ int genwqe_set_interrupt_capability(struct genwqe_dev *cd, int count) | |||
| 718 | int rc; | 728 | int rc; |
| 719 | struct pci_dev *pci_dev = cd->pci_dev; | 729 | struct pci_dev *pci_dev = cd->pci_dev; |
| 720 | 730 | ||
| 721 | rc = pci_enable_msi_exact(pci_dev, count); | 731 | rc = pci_enable_msi_range(pci_dev, 1, count); |
| 722 | if (rc == 0) | 732 | if (rc < 0) |
| 723 | cd->flags |= GENWQE_FLAG_MSI_ENABLED; | 733 | return rc; |
| 724 | return rc; | 734 | |
| 735 | cd->flags |= GENWQE_FLAG_MSI_ENABLED; | ||
| 736 | return 0; | ||
| 725 | } | 737 | } |
| 726 | 738 | ||
| 727 | /** | 739 | /** |
diff --git a/drivers/misc/genwqe/genwqe_driver.h b/drivers/misc/genwqe/genwqe_driver.h index cd5263163a6e..a506e9aa2d57 100644 --- a/drivers/misc/genwqe/genwqe_driver.h +++ b/drivers/misc/genwqe/genwqe_driver.h | |||
| @@ -36,7 +36,7 @@ | |||
| 36 | #include <asm/byteorder.h> | 36 | #include <asm/byteorder.h> |
| 37 | #include <linux/genwqe/genwqe_card.h> | 37 | #include <linux/genwqe/genwqe_card.h> |
| 38 | 38 | ||
| 39 | #define DRV_VERS_STRING "2.0.15" | 39 | #define DRV_VERS_STRING "2.0.21" |
| 40 | 40 | ||
| 41 | /* | 41 | /* |
| 42 | * Static minor number assignement, until we decide/implement | 42 | * Static minor number assignement, until we decide/implement |
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 06f6ad29ceff..3336ddca45ac 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c | |||
| @@ -145,7 +145,6 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) | |||
| 145 | union ioc4_int_out int_out; | 145 | union ioc4_int_out int_out; |
| 146 | union ioc4_gpcr gpcr; | 146 | union ioc4_gpcr gpcr; |
| 147 | unsigned int state, last_state = 1; | 147 | unsigned int state, last_state = 1; |
| 148 | struct timespec start_ts, end_ts; | ||
| 149 | uint64_t start, end, period; | 148 | uint64_t start, end, period; |
| 150 | unsigned int count = 0; | 149 | unsigned int count = 0; |
| 151 | 150 | ||
| @@ -174,10 +173,10 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) | |||
| 174 | if (!last_state && state) { | 173 | if (!last_state && state) { |
| 175 | count++; | 174 | count++; |
| 176 | if (count == IOC4_CALIBRATE_END) { | 175 | if (count == IOC4_CALIBRATE_END) { |
| 177 | ktime_get_ts(&end_ts); | 176 | end = ktime_get_ns(); |
| 178 | break; | 177 | break; |
| 179 | } else if (count == IOC4_CALIBRATE_DISCARD) | 178 | } else if (count == IOC4_CALIBRATE_DISCARD) |
| 180 | ktime_get_ts(&start_ts); | 179 | start = ktime_get_ns(); |
| 181 | } | 180 | } |
| 182 | last_state = state; | 181 | last_state = state; |
| 183 | } while (1); | 182 | } while (1); |
| @@ -192,8 +191,6 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) | |||
| 192 | * by which the IOC4 generates the square wave, to get the | 191 | * by which the IOC4 generates the square wave, to get the |
| 193 | * period of an IOC4 INT_OUT count. | 192 | * period of an IOC4 INT_OUT count. |
| 194 | */ | 193 | */ |
| 195 | end = end_ts.tv_sec * NSEC_PER_SEC + end_ts.tv_nsec; | ||
| 196 | start = start_ts.tv_sec * NSEC_PER_SEC + start_ts.tv_nsec; | ||
| 197 | period = (end - start) / | 194 | period = (end - start) / |
| 198 | (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1)); | 195 | (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1)); |
| 199 | 196 | ||
diff --git a/drivers/misc/lattice-ecp3-config.c b/drivers/misc/lattice-ecp3-config.c index 0a1565e63c71..7ffdb589841e 100644 --- a/drivers/misc/lattice-ecp3-config.c +++ b/drivers/misc/lattice-ecp3-config.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/spi/spi.h> | 15 | #include <linux/spi/spi.h> |
| 16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
| 17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
| 18 | #include <asm/unaligned.h> | ||
| 18 | 19 | ||
| 19 | #define FIRMWARE_NAME "lattice-ecp3.bit" | 20 | #define FIRMWARE_NAME "lattice-ecp3.bit" |
| 20 | 21 | ||
| @@ -91,8 +92,8 @@ static void firmware_load(const struct firmware *fw, void *context) | |||
| 91 | /* Trying to speak with the FPGA via SPI... */ | 92 | /* Trying to speak with the FPGA via SPI... */ |
| 92 | txbuf[0] = FPGA_CMD_READ_ID; | 93 | txbuf[0] = FPGA_CMD_READ_ID; |
| 93 | ret = spi_write_then_read(spi, txbuf, 8, rxbuf, rx_len); | 94 | ret = spi_write_then_read(spi, txbuf, 8, rxbuf, rx_len); |
| 94 | dev_dbg(&spi->dev, "FPGA JTAG ID=%08x\n", *(u32 *)&rxbuf[4]); | 95 | jedec_id = get_unaligned_be32(&rxbuf[4]); |
| 95 | jedec_id = *(u32 *)&rxbuf[4]; | 96 | dev_dbg(&spi->dev, "FPGA JTAG ID=%08x\n", jedec_id); |
| 96 | 97 | ||
| 97 | for (i = 0; i < ARRAY_SIZE(ecp3_dev); i++) { | 98 | for (i = 0; i < ARRAY_SIZE(ecp3_dev); i++) { |
| 98 | if (jedec_id == ecp3_dev[i].jedec_id) | 99 | if (jedec_id == ecp3_dev[i].jedec_id) |
| @@ -109,7 +110,8 @@ static void firmware_load(const struct firmware *fw, void *context) | |||
| 109 | 110 | ||
| 110 | txbuf[0] = FPGA_CMD_READ_STATUS; | 111 | txbuf[0] = FPGA_CMD_READ_STATUS; |
| 111 | ret = spi_write_then_read(spi, txbuf, 8, rxbuf, rx_len); | 112 | ret = spi_write_then_read(spi, txbuf, 8, rxbuf, rx_len); |
| 112 | dev_dbg(&spi->dev, "FPGA Status=%08x\n", *(u32 *)&rxbuf[4]); | 113 | status = get_unaligned_be32(&rxbuf[4]); |
| 114 | dev_dbg(&spi->dev, "FPGA Status=%08x\n", status); | ||
| 113 | 115 | ||
| 114 | buffer = kzalloc(fw->size + 8, GFP_KERNEL); | 116 | buffer = kzalloc(fw->size + 8, GFP_KERNEL); |
| 115 | if (!buffer) { | 117 | if (!buffer) { |
| @@ -141,7 +143,7 @@ static void firmware_load(const struct firmware *fw, void *context) | |||
| 141 | for (i = 0; i < FPGA_CLEAR_LOOP_COUNT; i++) { | 143 | for (i = 0; i < FPGA_CLEAR_LOOP_COUNT; i++) { |
| 142 | txbuf[0] = FPGA_CMD_READ_STATUS; | 144 | txbuf[0] = FPGA_CMD_READ_STATUS; |
| 143 | ret = spi_write_then_read(spi, txbuf, 8, rxbuf, rx_len); | 145 | ret = spi_write_then_read(spi, txbuf, 8, rxbuf, rx_len); |
| 144 | status = *(u32 *)&rxbuf[4]; | 146 | status = get_unaligned_be32(&rxbuf[4]); |
| 145 | if (status == FPGA_STATUS_CLEARED) | 147 | if (status == FPGA_STATUS_CLEARED) |
| 146 | break; | 148 | break; |
| 147 | 149 | ||
| @@ -164,8 +166,8 @@ static void firmware_load(const struct firmware *fw, void *context) | |||
| 164 | 166 | ||
| 165 | txbuf[0] = FPGA_CMD_READ_STATUS; | 167 | txbuf[0] = FPGA_CMD_READ_STATUS; |
| 166 | ret = spi_write_then_read(spi, txbuf, 8, rxbuf, rx_len); | 168 | ret = spi_write_then_read(spi, txbuf, 8, rxbuf, rx_len); |
| 167 | dev_dbg(&spi->dev, "FPGA Status=%08x\n", *(u32 *)&rxbuf[4]); | 169 | status = get_unaligned_be32(&rxbuf[4]); |
| 168 | status = *(u32 *)&rxbuf[4]; | 170 | dev_dbg(&spi->dev, "FPGA Status=%08x\n", status); |
| 169 | 171 | ||
| 170 | /* Check result */ | 172 | /* Check result */ |
| 171 | if (status & FPGA_STATUS_DONE) | 173 | if (status & FPGA_STATUS_DONE) |
| @@ -196,7 +198,7 @@ static int lattice_ecp3_probe(struct spi_device *spi) | |||
| 196 | spi_set_drvdata(spi, data); | 198 | spi_set_drvdata(spi, data); |
| 197 | 199 | ||
| 198 | init_completion(&data->fw_loaded); | 200 | init_completion(&data->fw_loaded); |
| 199 | err = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, | 201 | err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, |
| 200 | FIRMWARE_NAME, &spi->dev, | 202 | FIRMWARE_NAME, &spi->dev, |
| 201 | GFP_KERNEL, spi, firmware_load); | 203 | GFP_KERNEL, spi, firmware_load); |
| 202 | if (err) { | 204 | if (err) { |
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index d66a2f24f6b3..b5abe34120b8 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c | |||
| @@ -870,3 +870,4 @@ module_init(lkdtm_module_init); | |||
| 870 | module_exit(lkdtm_module_exit); | 870 | module_exit(lkdtm_module_exit); |
| 871 | 871 | ||
| 872 | MODULE_LICENSE("GPL"); | 872 | MODULE_LICENSE("GPL"); |
| 873 | MODULE_DESCRIPTION("Kprobe module for testing crash dumps"); | ||
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 59d20c599b16..2da05c0e113d 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
| @@ -459,7 +459,7 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
| 459 | { | 459 | { |
| 460 | struct mei_device *dev; | 460 | struct mei_device *dev; |
| 461 | struct mei_cl_cb *cb; | 461 | struct mei_cl_cb *cb; |
| 462 | int rets, err; | 462 | int rets; |
| 463 | 463 | ||
| 464 | if (WARN_ON(!cl || !cl->dev)) | 464 | if (WARN_ON(!cl || !cl->dev)) |
| 465 | return -ENODEV; | 465 | return -ENODEV; |
| @@ -491,6 +491,7 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
| 491 | cl_err(dev, cl, "failed to disconnect.\n"); | 491 | cl_err(dev, cl, "failed to disconnect.\n"); |
| 492 | goto free; | 492 | goto free; |
| 493 | } | 493 | } |
| 494 | cl->timer_count = MEI_CONNECT_TIMEOUT; | ||
| 494 | mdelay(10); /* Wait for hardware disconnection ready */ | 495 | mdelay(10); /* Wait for hardware disconnection ready */ |
| 495 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); | 496 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); |
| 496 | } else { | 497 | } else { |
| @@ -500,23 +501,18 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
| 500 | } | 501 | } |
| 501 | mutex_unlock(&dev->device_lock); | 502 | mutex_unlock(&dev->device_lock); |
| 502 | 503 | ||
| 503 | err = wait_event_timeout(dev->wait_recvd_msg, | 504 | wait_event_timeout(dev->wait_recvd_msg, |
| 504 | MEI_FILE_DISCONNECTED == cl->state, | 505 | MEI_FILE_DISCONNECTED == cl->state, |
| 505 | mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); | 506 | mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); |
| 506 | 507 | ||
| 507 | mutex_lock(&dev->device_lock); | 508 | mutex_lock(&dev->device_lock); |
| 509 | |||
| 508 | if (MEI_FILE_DISCONNECTED == cl->state) { | 510 | if (MEI_FILE_DISCONNECTED == cl->state) { |
| 509 | rets = 0; | 511 | rets = 0; |
| 510 | cl_dbg(dev, cl, "successfully disconnected from FW client.\n"); | 512 | cl_dbg(dev, cl, "successfully disconnected from FW client.\n"); |
| 511 | } else { | 513 | } else { |
| 512 | rets = -ENODEV; | 514 | cl_dbg(dev, cl, "timeout on disconnect from FW client.\n"); |
| 513 | if (MEI_FILE_DISCONNECTED != cl->state) | 515 | rets = -ETIME; |
| 514 | cl_err(dev, cl, "wrong status client disconnect.\n"); | ||
| 515 | |||
| 516 | if (err) | ||
| 517 | cl_dbg(dev, cl, "wait failed disconnect err=%d\n", err); | ||
| 518 | |||
| 519 | cl_err(dev, cl, "failed to disconnect from FW client.\n"); | ||
| 520 | } | 516 | } |
| 521 | 517 | ||
| 522 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | 518 | mei_io_list_flush(&dev->ctrl_rd_list, cl); |
| @@ -605,6 +601,7 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file) | |||
| 605 | cl->timer_count = MEI_CONNECT_TIMEOUT; | 601 | cl->timer_count = MEI_CONNECT_TIMEOUT; |
| 606 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); | 602 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); |
| 607 | } else { | 603 | } else { |
| 604 | cl->state = MEI_FILE_INITIALIZING; | ||
| 608 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | 605 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); |
| 609 | } | 606 | } |
| 610 | 607 | ||
| @@ -616,6 +613,7 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file) | |||
| 616 | mutex_lock(&dev->device_lock); | 613 | mutex_lock(&dev->device_lock); |
| 617 | 614 | ||
| 618 | if (cl->state != MEI_FILE_CONNECTED) { | 615 | if (cl->state != MEI_FILE_CONNECTED) { |
| 616 | cl->state = MEI_FILE_DISCONNECTED; | ||
| 619 | /* something went really wrong */ | 617 | /* something went really wrong */ |
| 620 | if (!cl->status) | 618 | if (!cl->status) |
| 621 | cl->status = -EFAULT; | 619 | cl->status = -EFAULT; |
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index a7856c0ac576..c5feafdd58a8 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h | |||
| @@ -115,6 +115,7 @@ | |||
| 115 | #define MEI_DEV_ID_LPT_HR 0x8CBA /* Lynx Point H Refresh */ | 115 | #define MEI_DEV_ID_LPT_HR 0x8CBA /* Lynx Point H Refresh */ |
| 116 | 116 | ||
| 117 | #define MEI_DEV_ID_WPT_LP 0x9CBA /* Wildcat Point LP */ | 117 | #define MEI_DEV_ID_WPT_LP 0x9CBA /* Wildcat Point LP */ |
| 118 | #define MEI_DEV_ID_WPT_LP_2 0x9CBB /* Wildcat Point LP 2 */ | ||
| 118 | 119 | ||
| 119 | /* Host Firmware Status Registers in PCI Config Space */ | 120 | /* Host Firmware Status Registers in PCI Config Space */ |
| 120 | #define PCI_CFG_HFS_1 0x40 | 121 | #define PCI_CFG_HFS_1 0x40 |
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 6a2d272cea43..a9a0d08f758e 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c | |||
| @@ -710,64 +710,10 @@ end: | |||
| 710 | return IRQ_HANDLED; | 710 | return IRQ_HANDLED; |
| 711 | } | 711 | } |
| 712 | 712 | ||
| 713 | /** | ||
| 714 | * mei_me_fw_status - retrieve fw status from the pci config space | ||
| 715 | * | ||
| 716 | * @dev: the device structure | ||
| 717 | * @fw_status: fw status registers storage | ||
| 718 | * | ||
| 719 | * returns 0 on success an error code otherwise | ||
| 720 | */ | ||
| 721 | static int mei_me_fw_status(struct mei_device *dev, | ||
| 722 | struct mei_fw_status *fw_status) | ||
| 723 | { | ||
| 724 | const u32 pci_cfg_reg[] = {PCI_CFG_HFS_1, PCI_CFG_HFS_2}; | ||
| 725 | int i; | ||
| 726 | |||
| 727 | if (!fw_status) | ||
| 728 | return -EINVAL; | ||
| 729 | |||
| 730 | switch (dev->pdev->device) { | ||
| 731 | case MEI_DEV_ID_IBXPK_1: | ||
| 732 | case MEI_DEV_ID_IBXPK_2: | ||
| 733 | case MEI_DEV_ID_CPT_1: | ||
| 734 | case MEI_DEV_ID_PBG_1: | ||
| 735 | case MEI_DEV_ID_PPT_1: | ||
| 736 | case MEI_DEV_ID_PPT_2: | ||
| 737 | case MEI_DEV_ID_PPT_3: | ||
| 738 | case MEI_DEV_ID_LPT_H: | ||
| 739 | case MEI_DEV_ID_LPT_W: | ||
| 740 | case MEI_DEV_ID_LPT_LP: | ||
| 741 | case MEI_DEV_ID_LPT_HR: | ||
| 742 | case MEI_DEV_ID_WPT_LP: | ||
| 743 | fw_status->count = 2; | ||
| 744 | break; | ||
| 745 | case MEI_DEV_ID_ICH10_1: | ||
| 746 | case MEI_DEV_ID_ICH10_2: | ||
| 747 | case MEI_DEV_ID_ICH10_3: | ||
| 748 | case MEI_DEV_ID_ICH10_4: | ||
| 749 | fw_status->count = 1; | ||
| 750 | break; | ||
| 751 | default: | ||
| 752 | fw_status->count = 0; | ||
| 753 | break; | ||
| 754 | } | ||
| 755 | |||
| 756 | for (i = 0; i < fw_status->count && i < MEI_FW_STATUS_MAX; i++) { | ||
| 757 | int ret; | ||
| 758 | ret = pci_read_config_dword(dev->pdev, | ||
| 759 | pci_cfg_reg[i], &fw_status->status[i]); | ||
| 760 | if (ret) | ||
| 761 | return ret; | ||
| 762 | } | ||
| 763 | return 0; | ||
| 764 | } | ||
| 765 | |||
| 766 | static const struct mei_hw_ops mei_me_hw_ops = { | 713 | static const struct mei_hw_ops mei_me_hw_ops = { |
| 767 | 714 | ||
| 768 | .pg_state = mei_me_pg_state, | 715 | .pg_state = mei_me_pg_state, |
| 769 | 716 | ||
| 770 | .fw_status = mei_me_fw_status, | ||
| 771 | .host_is_ready = mei_me_host_is_ready, | 717 | .host_is_ready = mei_me_host_is_ready, |
| 772 | 718 | ||
| 773 | .hw_is_ready = mei_me_hw_is_ready, | 719 | .hw_is_ready = mei_me_hw_is_ready, |
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c index 93273783dec5..f1cd166094f2 100644 --- a/drivers/misc/mei/hw-txe.c +++ b/drivers/misc/mei/hw-txe.c | |||
| @@ -1042,40 +1042,8 @@ end: | |||
| 1042 | return IRQ_HANDLED; | 1042 | return IRQ_HANDLED; |
| 1043 | } | 1043 | } |
| 1044 | 1044 | ||
| 1045 | |||
| 1046 | /** | ||
| 1047 | * mei_txe_fw_status - retrieve fw status from the pci config space | ||
| 1048 | * | ||
| 1049 | * @dev: the device structure | ||
| 1050 | * @fw_status: fw status registers storage | ||
| 1051 | * | ||
| 1052 | * returns: 0 on success an error code otherwise | ||
| 1053 | */ | ||
| 1054 | static int mei_txe_fw_status(struct mei_device *dev, | ||
| 1055 | struct mei_fw_status *fw_status) | ||
| 1056 | { | ||
| 1057 | const u32 pci_cfg_reg[] = {PCI_CFG_TXE_FW_STS0, PCI_CFG_TXE_FW_STS1}; | ||
| 1058 | int i; | ||
| 1059 | |||
| 1060 | if (!fw_status) | ||
| 1061 | return -EINVAL; | ||
| 1062 | |||
| 1063 | fw_status->count = 2; | ||
| 1064 | |||
| 1065 | for (i = 0; i < fw_status->count && i < MEI_FW_STATUS_MAX; i++) { | ||
| 1066 | int ret; | ||
| 1067 | ret = pci_read_config_dword(dev->pdev, | ||
| 1068 | pci_cfg_reg[i], &fw_status->status[i]); | ||
| 1069 | if (ret) | ||
| 1070 | return ret; | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | return 0; | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | static const struct mei_hw_ops mei_txe_hw_ops = { | 1045 | static const struct mei_hw_ops mei_txe_hw_ops = { |
| 1077 | 1046 | ||
| 1078 | .fw_status = mei_txe_fw_status, | ||
| 1079 | .host_is_ready = mei_txe_host_is_ready, | 1047 | .host_is_ready = mei_txe_host_is_ready, |
| 1080 | 1048 | ||
| 1081 | .pg_state = mei_txe_pg_state, | 1049 | .pg_state = mei_txe_pg_state, |
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 66f0a1a06451..401a3d526cd0 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
| @@ -32,7 +32,6 @@ | |||
| 32 | #include <linux/compat.h> | 32 | #include <linux/compat.h> |
| 33 | #include <linux/jiffies.h> | 33 | #include <linux/jiffies.h> |
| 34 | #include <linux/interrupt.h> | 34 | #include <linux/interrupt.h> |
| 35 | #include <linux/miscdevice.h> | ||
| 36 | 35 | ||
| 37 | #include <linux/mei.h> | 36 | #include <linux/mei.h> |
| 38 | 37 | ||
| @@ -49,19 +48,12 @@ | |||
| 49 | */ | 48 | */ |
| 50 | static int mei_open(struct inode *inode, struct file *file) | 49 | static int mei_open(struct inode *inode, struct file *file) |
| 51 | { | 50 | { |
| 52 | struct miscdevice *misc = file->private_data; | ||
| 53 | struct pci_dev *pdev; | ||
| 54 | struct mei_cl *cl; | ||
| 55 | struct mei_device *dev; | 51 | struct mei_device *dev; |
| 52 | struct mei_cl *cl; | ||
| 56 | 53 | ||
| 57 | int err; | 54 | int err; |
| 58 | 55 | ||
| 59 | if (!misc->parent) | 56 | dev = container_of(inode->i_cdev, struct mei_device, cdev); |
| 60 | return -ENODEV; | ||
| 61 | |||
| 62 | pdev = container_of(misc->parent, struct pci_dev, dev); | ||
| 63 | |||
| 64 | dev = pci_get_drvdata(pdev); | ||
| 65 | if (!dev) | 57 | if (!dev) |
| 66 | return -ENODEV; | 58 | return -ENODEV; |
| 67 | 59 | ||
| @@ -667,46 +659,148 @@ static const struct file_operations mei_fops = { | |||
| 667 | .llseek = no_llseek | 659 | .llseek = no_llseek |
| 668 | }; | 660 | }; |
| 669 | 661 | ||
| 670 | /* | 662 | static struct class *mei_class; |
| 671 | * Misc Device Struct | 663 | static dev_t mei_devt; |
| 664 | #define MEI_MAX_DEVS MINORMASK | ||
| 665 | static DEFINE_MUTEX(mei_minor_lock); | ||
| 666 | static DEFINE_IDR(mei_idr); | ||
| 667 | |||
| 668 | /** | ||
| 669 | * mei_minor_get - obtain next free device minor number | ||
| 670 | * | ||
| 671 | * @dev: device pointer | ||
| 672 | * | ||
| 673 | * returns allocated minor, or -ENOSPC if no free minor left | ||
| 672 | */ | 674 | */ |
| 673 | static struct miscdevice mei_misc_device = { | 675 | static int mei_minor_get(struct mei_device *dev) |
| 674 | .name = "mei", | 676 | { |
| 675 | .fops = &mei_fops, | 677 | int ret; |
| 676 | .minor = MISC_DYNAMIC_MINOR, | 678 | |
| 677 | }; | 679 | mutex_lock(&mei_minor_lock); |
| 680 | ret = idr_alloc(&mei_idr, dev, 0, MEI_MAX_DEVS, GFP_KERNEL); | ||
| 681 | if (ret >= 0) | ||
| 682 | dev->minor = ret; | ||
| 683 | else if (ret == -ENOSPC) | ||
| 684 | dev_err(&dev->pdev->dev, "too many mei devices\n"); | ||
| 678 | 685 | ||
| 686 | mutex_unlock(&mei_minor_lock); | ||
| 687 | return ret; | ||
| 688 | } | ||
| 679 | 689 | ||
| 680 | int mei_register(struct mei_device *dev) | 690 | /** |
| 691 | * mei_minor_free - mark device minor number as free | ||
| 692 | * | ||
| 693 | * @dev: device pointer | ||
| 694 | */ | ||
| 695 | static void mei_minor_free(struct mei_device *dev) | ||
| 681 | { | 696 | { |
| 682 | int ret; | 697 | mutex_lock(&mei_minor_lock); |
| 683 | mei_misc_device.parent = &dev->pdev->dev; | 698 | idr_remove(&mei_idr, dev->minor); |
| 684 | ret = misc_register(&mei_misc_device); | 699 | mutex_unlock(&mei_minor_lock); |
| 685 | if (ret) | 700 | } |
| 701 | |||
| 702 | int mei_register(struct mei_device *dev, struct device *parent) | ||
| 703 | { | ||
| 704 | struct device *clsdev; /* class device */ | ||
| 705 | int ret, devno; | ||
| 706 | |||
| 707 | ret = mei_minor_get(dev); | ||
| 708 | if (ret < 0) | ||
| 686 | return ret; | 709 | return ret; |
| 687 | 710 | ||
| 688 | if (mei_dbgfs_register(dev, mei_misc_device.name)) | 711 | /* Fill in the data structures */ |
| 689 | dev_err(&dev->pdev->dev, "cannot register debugfs\n"); | 712 | devno = MKDEV(MAJOR(mei_devt), dev->minor); |
| 713 | cdev_init(&dev->cdev, &mei_fops); | ||
| 714 | dev->cdev.owner = mei_fops.owner; | ||
| 715 | |||
| 716 | /* Add the device */ | ||
| 717 | ret = cdev_add(&dev->cdev, devno, 1); | ||
| 718 | if (ret) { | ||
| 719 | dev_err(parent, "unable to add device %d:%d\n", | ||
| 720 | MAJOR(mei_devt), dev->minor); | ||
| 721 | goto err_dev_add; | ||
| 722 | } | ||
| 723 | |||
| 724 | clsdev = device_create(mei_class, parent, devno, | ||
| 725 | NULL, "mei%d", dev->minor); | ||
| 726 | |||
| 727 | if (IS_ERR(clsdev)) { | ||
| 728 | dev_err(parent, "unable to create device %d:%d\n", | ||
| 729 | MAJOR(mei_devt), dev->minor); | ||
| 730 | ret = PTR_ERR(clsdev); | ||
| 731 | goto err_dev_create; | ||
| 732 | } | ||
| 733 | |||
| 734 | ret = mei_dbgfs_register(dev, dev_name(clsdev)); | ||
| 735 | if (ret) { | ||
| 736 | dev_err(clsdev, "cannot register debugfs ret = %d\n", ret); | ||
| 737 | goto err_dev_dbgfs; | ||
| 738 | } | ||
| 690 | 739 | ||
| 691 | return 0; | 740 | return 0; |
| 741 | |||
| 742 | err_dev_dbgfs: | ||
| 743 | device_destroy(mei_class, devno); | ||
| 744 | err_dev_create: | ||
| 745 | cdev_del(&dev->cdev); | ||
| 746 | err_dev_add: | ||
| 747 | mei_minor_free(dev); | ||
| 748 | return ret; | ||
| 692 | } | 749 | } |
| 693 | EXPORT_SYMBOL_GPL(mei_register); | 750 | EXPORT_SYMBOL_GPL(mei_register); |
| 694 | 751 | ||
| 695 | void mei_deregister(struct mei_device *dev) | 752 | void mei_deregister(struct mei_device *dev) |
| 696 | { | 753 | { |
| 754 | int devno; | ||
| 755 | |||
| 756 | devno = dev->cdev.dev; | ||
| 757 | cdev_del(&dev->cdev); | ||
| 758 | |||
| 697 | mei_dbgfs_deregister(dev); | 759 | mei_dbgfs_deregister(dev); |
| 698 | misc_deregister(&mei_misc_device); | 760 | |
| 699 | mei_misc_device.parent = NULL; | 761 | device_destroy(mei_class, devno); |
| 762 | |||
| 763 | mei_minor_free(dev); | ||
| 700 | } | 764 | } |
| 701 | EXPORT_SYMBOL_GPL(mei_deregister); | 765 | EXPORT_SYMBOL_GPL(mei_deregister); |
| 702 | 766 | ||
| 703 | static int __init mei_init(void) | 767 | static int __init mei_init(void) |
| 704 | { | 768 | { |
| 705 | return mei_cl_bus_init(); | 769 | int ret; |
| 770 | |||
| 771 | mei_class = class_create(THIS_MODULE, "mei"); | ||
| 772 | if (IS_ERR(mei_class)) { | ||
| 773 | pr_err("couldn't create class\n"); | ||
| 774 | ret = PTR_ERR(mei_class); | ||
| 775 | goto err; | ||
| 776 | } | ||
| 777 | |||
| 778 | ret = alloc_chrdev_region(&mei_devt, 0, MEI_MAX_DEVS, "mei"); | ||
| 779 | if (ret < 0) { | ||
| 780 | pr_err("unable to allocate char dev region\n"); | ||
| 781 | goto err_class; | ||
| 782 | } | ||
| 783 | |||
| 784 | ret = mei_cl_bus_init(); | ||
| 785 | if (ret < 0) { | ||
| 786 | pr_err("unable to initialize bus\n"); | ||
| 787 | goto err_chrdev; | ||
| 788 | } | ||
| 789 | |||
| 790 | return 0; | ||
| 791 | |||
| 792 | err_chrdev: | ||
| 793 | unregister_chrdev_region(mei_devt, MEI_MAX_DEVS); | ||
| 794 | err_class: | ||
| 795 | class_destroy(mei_class); | ||
| 796 | err: | ||
| 797 | return ret; | ||
| 706 | } | 798 | } |
| 707 | 799 | ||
| 708 | static void __exit mei_exit(void) | 800 | static void __exit mei_exit(void) |
| 709 | { | 801 | { |
| 802 | unregister_chrdev_region(mei_devt, MEI_MAX_DEVS); | ||
| 803 | class_destroy(mei_class); | ||
| 710 | mei_cl_bus_exit(); | 804 | mei_cl_bus_exit(); |
| 711 | } | 805 | } |
| 712 | 806 | ||
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 5c7e990e2f22..0b0d6135543b 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
| @@ -227,7 +227,6 @@ struct mei_cl { | |||
| 227 | 227 | ||
| 228 | /** struct mei_hw_ops | 228 | /** struct mei_hw_ops |
| 229 | * | 229 | * |
| 230 | * @fw_status - read FW status from PCI config space | ||
| 231 | * @host_is_ready - query for host readiness | 230 | * @host_is_ready - query for host readiness |
| 232 | 231 | ||
| 233 | * @hw_is_ready - query if hw is ready | 232 | * @hw_is_ready - query if hw is ready |
| @@ -255,8 +254,6 @@ struct mei_cl { | |||
| 255 | */ | 254 | */ |
| 256 | struct mei_hw_ops { | 255 | struct mei_hw_ops { |
| 257 | 256 | ||
| 258 | int (*fw_status)(struct mei_device *dev, | ||
| 259 | struct mei_fw_status *fw_status); | ||
| 260 | bool (*host_is_ready)(struct mei_device *dev); | 257 | bool (*host_is_ready)(struct mei_device *dev); |
| 261 | 258 | ||
| 262 | bool (*hw_is_ready)(struct mei_device *dev); | 259 | bool (*hw_is_ready)(struct mei_device *dev); |
| @@ -400,6 +397,10 @@ struct mei_cfg { | |||
| 400 | /** | 397 | /** |
| 401 | * struct mei_device - MEI private device struct | 398 | * struct mei_device - MEI private device struct |
| 402 | 399 | ||
| 400 | * @pdev - pointer to pci device struct | ||
| 401 | * @cdev - character device | ||
| 402 | * @minor - minor number allocated for device | ||
| 403 | * | ||
| 403 | * @reset_count - limits the number of consecutive resets | 404 | * @reset_count - limits the number of consecutive resets |
| 404 | * @hbm_state - state of host bus message protocol | 405 | * @hbm_state - state of host bus message protocol |
| 405 | * @pg_event - power gating event | 406 | * @pg_event - power gating event |
| @@ -412,6 +413,9 @@ struct mei_cfg { | |||
| 412 | */ | 413 | */ |
| 413 | struct mei_device { | 414 | struct mei_device { |
| 414 | struct pci_dev *pdev; /* pointer to pci device struct */ | 415 | struct pci_dev *pdev; /* pointer to pci device struct */ |
| 416 | struct cdev cdev; | ||
| 417 | int minor; | ||
| 418 | |||
| 415 | /* | 419 | /* |
| 416 | * lists of queues | 420 | * lists of queues |
| 417 | */ | 421 | */ |
| @@ -741,7 +745,7 @@ static inline int mei_dbgfs_register(struct mei_device *dev, const char *name) | |||
| 741 | static inline void mei_dbgfs_deregister(struct mei_device *dev) {} | 745 | static inline void mei_dbgfs_deregister(struct mei_device *dev) {} |
| 742 | #endif /* CONFIG_DEBUG_FS */ | 746 | #endif /* CONFIG_DEBUG_FS */ |
| 743 | 747 | ||
| 744 | int mei_register(struct mei_device *dev); | 748 | int mei_register(struct mei_device *dev, struct device *parent); |
| 745 | void mei_deregister(struct mei_device *dev); | 749 | void mei_deregister(struct mei_device *dev); |
| 746 | 750 | ||
| 747 | #define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d internal=%1d comp=%1d" | 751 | #define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d internal=%1d comp=%1d" |
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c index 3095fc514a65..5ccc23bc7690 100644 --- a/drivers/misc/mei/nfc.c +++ b/drivers/misc/mei/nfc.c | |||
| @@ -342,9 +342,10 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length) | |||
| 342 | ndev = (struct mei_nfc_dev *) cldev->priv_data; | 342 | ndev = (struct mei_nfc_dev *) cldev->priv_data; |
| 343 | dev = ndev->cl->dev; | 343 | dev = ndev->cl->dev; |
| 344 | 344 | ||
| 345 | err = -ENOMEM; | ||
| 345 | mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL); | 346 | mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL); |
| 346 | if (!mei_buf) | 347 | if (!mei_buf) |
| 347 | return -ENOMEM; | 348 | goto out; |
| 348 | 349 | ||
| 349 | hdr = (struct mei_nfc_hci_hdr *) mei_buf; | 350 | hdr = (struct mei_nfc_hci_hdr *) mei_buf; |
| 350 | hdr->cmd = MEI_NFC_CMD_HCI_SEND; | 351 | hdr->cmd = MEI_NFC_CMD_HCI_SEND; |
| @@ -354,12 +355,9 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length) | |||
| 354 | hdr->data_size = length; | 355 | hdr->data_size = length; |
| 355 | 356 | ||
| 356 | memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length); | 357 | memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length); |
| 357 | |||
| 358 | err = __mei_cl_send(ndev->cl, mei_buf, length + MEI_NFC_HEADER_SIZE); | 358 | err = __mei_cl_send(ndev->cl, mei_buf, length + MEI_NFC_HEADER_SIZE); |
| 359 | if (err < 0) | 359 | if (err < 0) |
| 360 | return err; | 360 | goto out; |
| 361 | |||
| 362 | kfree(mei_buf); | ||
| 363 | 361 | ||
| 364 | if (!wait_event_interruptible_timeout(ndev->send_wq, | 362 | if (!wait_event_interruptible_timeout(ndev->send_wq, |
| 365 | ndev->recv_req_id == ndev->req_id, HZ)) { | 363 | ndev->recv_req_id == ndev->req_id, HZ)) { |
| @@ -368,7 +366,8 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length) | |||
| 368 | } else { | 366 | } else { |
| 369 | ndev->req_id++; | 367 | ndev->req_id++; |
| 370 | } | 368 | } |
| 371 | 369 | out: | |
| 370 | kfree(mei_buf); | ||
| 372 | return err; | 371 | return err; |
| 373 | } | 372 | } |
| 374 | 373 | ||
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 1b46c64a649f..a0e9422b55a2 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c | |||
| @@ -31,7 +31,6 @@ | |||
| 31 | #include <linux/compat.h> | 31 | #include <linux/compat.h> |
| 32 | #include <linux/jiffies.h> | 32 | #include <linux/jiffies.h> |
| 33 | #include <linux/interrupt.h> | 33 | #include <linux/interrupt.h> |
| 34 | #include <linux/miscdevice.h> | ||
| 35 | 34 | ||
| 36 | #include <linux/pm_runtime.h> | 35 | #include <linux/pm_runtime.h> |
| 37 | 36 | ||
| @@ -82,6 +81,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { | |||
| 82 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_LP, mei_me_pch_cfg)}, | 81 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_LP, mei_me_pch_cfg)}, |
| 83 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_HR, mei_me_lpt_cfg)}, | 82 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_HR, mei_me_lpt_cfg)}, |
| 84 | {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP, mei_me_pch_cfg)}, | 83 | {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP, mei_me_pch_cfg)}, |
| 84 | {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP_2, mei_me_pch_cfg)}, | ||
| 85 | 85 | ||
| 86 | /* required last entry */ | 86 | /* required last entry */ |
| 87 | {0, } | 87 | {0, } |
| @@ -207,7 +207,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 207 | pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_ME_RPM_TIMEOUT); | 207 | pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_ME_RPM_TIMEOUT); |
| 208 | pm_runtime_use_autosuspend(&pdev->dev); | 208 | pm_runtime_use_autosuspend(&pdev->dev); |
| 209 | 209 | ||
| 210 | err = mei_register(dev); | 210 | err = mei_register(dev, &pdev->dev); |
| 211 | if (err) | 211 | if (err) |
| 212 | goto release_irq; | 212 | goto release_irq; |
| 213 | 213 | ||
| @@ -369,7 +369,7 @@ static int mei_me_pm_runtime_idle(struct device *device) | |||
| 369 | if (!dev) | 369 | if (!dev) |
| 370 | return -ENODEV; | 370 | return -ENODEV; |
| 371 | if (mei_write_is_idle(dev)) | 371 | if (mei_write_is_idle(dev)) |
| 372 | pm_schedule_suspend(device, MEI_ME_RPM_TIMEOUT * 2); | 372 | pm_runtime_autosuspend(device); |
| 373 | 373 | ||
| 374 | return -EBUSY; | 374 | return -EBUSY; |
| 375 | } | 375 | } |
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c index 2343c6236df9..19de57368b7a 100644 --- a/drivers/misc/mei/pci-txe.c +++ b/drivers/misc/mei/pci-txe.c | |||
| @@ -149,7 +149,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 149 | pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT); | 149 | pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT); |
| 150 | pm_runtime_use_autosuspend(&pdev->dev); | 150 | pm_runtime_use_autosuspend(&pdev->dev); |
| 151 | 151 | ||
| 152 | err = mei_register(dev); | 152 | err = mei_register(dev, &pdev->dev); |
| 153 | if (err) | 153 | if (err) |
| 154 | goto release_irq; | 154 | goto release_irq; |
| 155 | 155 | ||
| @@ -306,7 +306,7 @@ static int mei_txe_pm_runtime_idle(struct device *device) | |||
| 306 | if (!dev) | 306 | if (!dev) |
| 307 | return -ENODEV; | 307 | return -ENODEV; |
| 308 | if (mei_write_is_idle(dev)) | 308 | if (mei_write_is_idle(dev)) |
| 309 | pm_schedule_suspend(device, MEI_TXI_RPM_TIMEOUT * 2); | 309 | pm_runtime_autosuspend(device); |
| 310 | 310 | ||
| 311 | return -EBUSY; | 311 | return -EBUSY; |
| 312 | } | 312 | } |
diff --git a/drivers/misc/mic/Kconfig b/drivers/misc/mic/Kconfig index 462a5b1d8651..cc4eef040c14 100644 --- a/drivers/misc/mic/Kconfig +++ b/drivers/misc/mic/Kconfig | |||
| @@ -1,8 +1,25 @@ | |||
| 1 | comment "Intel MIC Bus Driver" | ||
| 2 | |||
| 3 | config INTEL_MIC_BUS | ||
| 4 | tristate "Intel MIC Bus Driver" | ||
| 5 | depends on 64BIT && PCI && X86 && X86_DEV_DMA_OPS | ||
| 6 | help | ||
| 7 | This option is selected by any driver which registers a | ||
| 8 | device or driver on the MIC Bus, such as CONFIG_INTEL_MIC_HOST, | ||
| 9 | CONFIG_INTEL_MIC_CARD, CONFIG_INTEL_MIC_X100_DMA etc. | ||
| 10 | |||
| 11 | If you are building a host/card kernel with an Intel MIC device | ||
| 12 | then say M (recommended) or Y, else say N. If unsure say N. | ||
| 13 | |||
| 14 | More information about the Intel MIC family as well as the Linux | ||
| 15 | OS and tools for MIC to use with this driver are available from | ||
| 16 | <http://software.intel.com/en-us/mic-developer>. | ||
| 17 | |||
| 1 | comment "Intel MIC Host Driver" | 18 | comment "Intel MIC Host Driver" |
| 2 | 19 | ||
| 3 | config INTEL_MIC_HOST | 20 | config INTEL_MIC_HOST |
| 4 | tristate "Intel MIC Host Driver" | 21 | tristate "Intel MIC Host Driver" |
| 5 | depends on 64BIT && PCI && X86 | 22 | depends on 64BIT && PCI && X86 && INTEL_MIC_BUS |
| 6 | select VHOST_RING | 23 | select VHOST_RING |
| 7 | help | 24 | help |
| 8 | This enables Host Driver support for the Intel Many Integrated | 25 | This enables Host Driver support for the Intel Many Integrated |
| @@ -22,7 +39,7 @@ comment "Intel MIC Card Driver" | |||
| 22 | 39 | ||
| 23 | config INTEL_MIC_CARD | 40 | config INTEL_MIC_CARD |
| 24 | tristate "Intel MIC Card Driver" | 41 | tristate "Intel MIC Card Driver" |
| 25 | depends on 64BIT && X86 | 42 | depends on 64BIT && X86 && INTEL_MIC_BUS |
| 26 | select VIRTIO | 43 | select VIRTIO |
| 27 | help | 44 | help |
| 28 | This enables card driver support for the Intel Many Integrated | 45 | This enables card driver support for the Intel Many Integrated |
diff --git a/drivers/misc/mic/Makefile b/drivers/misc/mic/Makefile index 05b34d683a58..e9bf148755e2 100644 --- a/drivers/misc/mic/Makefile +++ b/drivers/misc/mic/Makefile | |||
| @@ -4,3 +4,4 @@ | |||
| 4 | # | 4 | # |
| 5 | obj-$(CONFIG_INTEL_MIC_HOST) += host/ | 5 | obj-$(CONFIG_INTEL_MIC_HOST) += host/ |
| 6 | obj-$(CONFIG_INTEL_MIC_CARD) += card/ | 6 | obj-$(CONFIG_INTEL_MIC_CARD) += card/ |
| 7 | obj-$(CONFIG_INTEL_MIC_BUS) += bus/ | ||
diff --git a/drivers/misc/mic/bus/Makefile b/drivers/misc/mic/bus/Makefile new file mode 100644 index 000000000000..d85c7f2a0af4 --- /dev/null +++ b/drivers/misc/mic/bus/Makefile | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | # | ||
| 2 | # Makefile - Intel MIC Linux driver. | ||
| 3 | # Copyright(c) 2014, Intel Corporation. | ||
| 4 | # | ||
| 5 | obj-$(CONFIG_INTEL_MIC_BUS) += mic_bus.o | ||
diff --git a/drivers/misc/mic/bus/mic_bus.c b/drivers/misc/mic/bus/mic_bus.c new file mode 100644 index 000000000000..961ae90aae47 --- /dev/null +++ b/drivers/misc/mic/bus/mic_bus.c | |||
| @@ -0,0 +1,218 @@ | |||
| 1 | /* | ||
| 2 | * Intel MIC Platform Software Stack (MPSS) | ||
| 3 | * | ||
| 4 | * Copyright(c) 2014 Intel Corporation. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License, version 2, as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * The full GNU General Public License is included in this distribution in | ||
| 16 | * the file called "COPYING". | ||
| 17 | * | ||
| 18 | * Intel MIC Bus driver. | ||
| 19 | * | ||
| 20 | * This implementation is very similar to the the virtio bus driver | ||
| 21 | * implementation @ drivers/virtio/virtio.c | ||
| 22 | */ | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/idr.h> | ||
| 26 | #include <linux/mic_bus.h> | ||
| 27 | |||
| 28 | /* Unique numbering for mbus devices. */ | ||
| 29 | static DEFINE_IDA(mbus_index_ida); | ||
| 30 | |||
| 31 | static ssize_t device_show(struct device *d, | ||
| 32 | struct device_attribute *attr, char *buf) | ||
| 33 | { | ||
| 34 | struct mbus_device *dev = dev_to_mbus(d); | ||
| 35 | return sprintf(buf, "0x%04x\n", dev->id.device); | ||
| 36 | } | ||
| 37 | static DEVICE_ATTR_RO(device); | ||
| 38 | |||
| 39 | static ssize_t vendor_show(struct device *d, | ||
| 40 | struct device_attribute *attr, char *buf) | ||
| 41 | { | ||
| 42 | struct mbus_device *dev = dev_to_mbus(d); | ||
| 43 | return sprintf(buf, "0x%04x\n", dev->id.vendor); | ||
| 44 | } | ||
| 45 | static DEVICE_ATTR_RO(vendor); | ||
| 46 | |||
| 47 | static ssize_t modalias_show(struct device *d, | ||
| 48 | struct device_attribute *attr, char *buf) | ||
| 49 | { | ||
| 50 | struct mbus_device *dev = dev_to_mbus(d); | ||
| 51 | return sprintf(buf, "mbus:d%08Xv%08X\n", | ||
| 52 | dev->id.device, dev->id.vendor); | ||
| 53 | } | ||
| 54 | static DEVICE_ATTR_RO(modalias); | ||
| 55 | |||
| 56 | static struct attribute *mbus_dev_attrs[] = { | ||
| 57 | &dev_attr_device.attr, | ||
| 58 | &dev_attr_vendor.attr, | ||
| 59 | &dev_attr_modalias.attr, | ||
| 60 | NULL, | ||
| 61 | }; | ||
| 62 | ATTRIBUTE_GROUPS(mbus_dev); | ||
| 63 | |||
| 64 | static inline int mbus_id_match(const struct mbus_device *dev, | ||
| 65 | const struct mbus_device_id *id) | ||
| 66 | { | ||
| 67 | if (id->device != dev->id.device && id->device != MBUS_DEV_ANY_ID) | ||
| 68 | return 0; | ||
| 69 | |||
| 70 | return id->vendor == MBUS_DEV_ANY_ID || id->vendor == dev->id.vendor; | ||
| 71 | } | ||
| 72 | |||
| 73 | /* | ||
| 74 | * This looks through all the IDs a driver claims to support. If any of them | ||
| 75 | * match, we return 1 and the kernel will call mbus_dev_probe(). | ||
| 76 | */ | ||
| 77 | static int mbus_dev_match(struct device *dv, struct device_driver *dr) | ||
| 78 | { | ||
| 79 | unsigned int i; | ||
| 80 | struct mbus_device *dev = dev_to_mbus(dv); | ||
| 81 | const struct mbus_device_id *ids; | ||
| 82 | |||
| 83 | ids = drv_to_mbus(dr)->id_table; | ||
| 84 | for (i = 0; ids[i].device; i++) | ||
| 85 | if (mbus_id_match(dev, &ids[i])) | ||
| 86 | return 1; | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | static int mbus_uevent(struct device *dv, struct kobj_uevent_env *env) | ||
| 91 | { | ||
| 92 | struct mbus_device *dev = dev_to_mbus(dv); | ||
| 93 | |||
| 94 | return add_uevent_var(env, "MODALIAS=mbus:d%08Xv%08X", | ||
| 95 | dev->id.device, dev->id.vendor); | ||
| 96 | } | ||
| 97 | |||
| 98 | static int mbus_dev_probe(struct device *d) | ||
| 99 | { | ||
| 100 | int err; | ||
| 101 | struct mbus_device *dev = dev_to_mbus(d); | ||
| 102 | struct mbus_driver *drv = drv_to_mbus(dev->dev.driver); | ||
| 103 | |||
| 104 | err = drv->probe(dev); | ||
| 105 | if (!err) | ||
| 106 | if (drv->scan) | ||
| 107 | drv->scan(dev); | ||
| 108 | return err; | ||
| 109 | } | ||
| 110 | |||
| 111 | static int mbus_dev_remove(struct device *d) | ||
| 112 | { | ||
| 113 | struct mbus_device *dev = dev_to_mbus(d); | ||
| 114 | struct mbus_driver *drv = drv_to_mbus(dev->dev.driver); | ||
| 115 | |||
| 116 | drv->remove(dev); | ||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | |||
| 120 | static struct bus_type mic_bus = { | ||
| 121 | .name = "mic_bus", | ||
| 122 | .match = mbus_dev_match, | ||
| 123 | .dev_groups = mbus_dev_groups, | ||
| 124 | .uevent = mbus_uevent, | ||
| 125 | .probe = mbus_dev_probe, | ||
| 126 | .remove = mbus_dev_remove, | ||
| 127 | }; | ||
| 128 | |||
| 129 | int mbus_register_driver(struct mbus_driver *driver) | ||
| 130 | { | ||
| 131 | driver->driver.bus = &mic_bus; | ||
| 132 | return driver_register(&driver->driver); | ||
| 133 | } | ||
| 134 | EXPORT_SYMBOL_GPL(mbus_register_driver); | ||
| 135 | |||
| 136 | void mbus_unregister_driver(struct mbus_driver *driver) | ||
| 137 | { | ||
| 138 | driver_unregister(&driver->driver); | ||
| 139 | } | ||
| 140 | EXPORT_SYMBOL_GPL(mbus_unregister_driver); | ||
| 141 | |||
| 142 | static void mbus_release_dev(struct device *d) | ||
| 143 | { | ||
| 144 | struct mbus_device *mbdev = dev_to_mbus(d); | ||
| 145 | kfree(mbdev); | ||
| 146 | } | ||
| 147 | |||
| 148 | struct mbus_device * | ||
| 149 | mbus_register_device(struct device *pdev, int id, struct dma_map_ops *dma_ops, | ||
| 150 | struct mbus_hw_ops *hw_ops, void __iomem *mmio_va) | ||
| 151 | { | ||
| 152 | int ret; | ||
| 153 | struct mbus_device *mbdev; | ||
| 154 | |||
| 155 | mbdev = kzalloc(sizeof(*mbdev), GFP_KERNEL); | ||
| 156 | if (!mbdev) | ||
| 157 | return ERR_PTR(-ENOMEM); | ||
| 158 | |||
| 159 | mbdev->mmio_va = mmio_va; | ||
| 160 | mbdev->dev.parent = pdev; | ||
| 161 | mbdev->id.device = id; | ||
| 162 | mbdev->id.vendor = MBUS_DEV_ANY_ID; | ||
| 163 | mbdev->dev.archdata.dma_ops = dma_ops; | ||
| 164 | mbdev->dev.dma_mask = &mbdev->dev.coherent_dma_mask; | ||
| 165 | dma_set_mask(&mbdev->dev, DMA_BIT_MASK(64)); | ||
| 166 | mbdev->dev.release = mbus_release_dev; | ||
| 167 | mbdev->hw_ops = hw_ops; | ||
| 168 | mbdev->dev.bus = &mic_bus; | ||
| 169 | |||
| 170 | /* Assign a unique device index and hence name. */ | ||
| 171 | ret = ida_simple_get(&mbus_index_ida, 0, 0, GFP_KERNEL); | ||
| 172 | if (ret < 0) | ||
| 173 | goto free_mbdev; | ||
| 174 | |||
| 175 | mbdev->index = ret; | ||
| 176 | dev_set_name(&mbdev->dev, "mbus-dev%u", mbdev->index); | ||
| 177 | /* | ||
| 178 | * device_register() causes the bus infrastructure to look for a | ||
| 179 | * matching driver. | ||
| 180 | */ | ||
| 181 | ret = device_register(&mbdev->dev); | ||
| 182 | if (ret) | ||
| 183 | goto ida_remove; | ||
| 184 | return mbdev; | ||
| 185 | ida_remove: | ||
| 186 | ida_simple_remove(&mbus_index_ida, mbdev->index); | ||
| 187 | free_mbdev: | ||
| 188 | kfree(mbdev); | ||
| 189 | return ERR_PTR(ret); | ||
| 190 | } | ||
| 191 | EXPORT_SYMBOL_GPL(mbus_register_device); | ||
| 192 | |||
| 193 | void mbus_unregister_device(struct mbus_device *mbdev) | ||
| 194 | { | ||
| 195 | int index = mbdev->index; /* save for after device release */ | ||
| 196 | |||
| 197 | device_unregister(&mbdev->dev); | ||
| 198 | ida_simple_remove(&mbus_index_ida, index); | ||
| 199 | } | ||
| 200 | EXPORT_SYMBOL_GPL(mbus_unregister_device); | ||
| 201 | |||
| 202 | static int __init mbus_init(void) | ||
| 203 | { | ||
| 204 | return bus_register(&mic_bus); | ||
| 205 | } | ||
| 206 | |||
| 207 | static void __exit mbus_exit(void) | ||
| 208 | { | ||
| 209 | bus_unregister(&mic_bus); | ||
| 210 | ida_destroy(&mbus_index_ida); | ||
| 211 | } | ||
| 212 | |||
| 213 | core_initcall(mbus_init); | ||
| 214 | module_exit(mbus_exit); | ||
| 215 | |||
| 216 | MODULE_AUTHOR("Intel Corporation"); | ||
| 217 | MODULE_DESCRIPTION("Intel(R) MIC Bus driver"); | ||
| 218 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/misc/mic/card/mic_device.c b/drivers/misc/mic/card/mic_device.c index d0980ff96833..83819eee553b 100644 --- a/drivers/misc/mic/card/mic_device.c +++ b/drivers/misc/mic/card/mic_device.c | |||
| @@ -83,8 +83,8 @@ static int mic_shutdown_init(void) | |||
| 83 | int shutdown_db; | 83 | int shutdown_db; |
| 84 | 84 | ||
| 85 | shutdown_db = mic_next_card_db(); | 85 | shutdown_db = mic_next_card_db(); |
| 86 | shutdown_cookie = mic_request_card_irq(mic_shutdown_isr, | 86 | shutdown_cookie = mic_request_card_irq(mic_shutdown_isr, NULL, |
| 87 | "Shutdown", mdrv, shutdown_db); | 87 | "Shutdown", mdrv, shutdown_db); |
| 88 | if (IS_ERR(shutdown_cookie)) | 88 | if (IS_ERR(shutdown_cookie)) |
| 89 | rc = PTR_ERR(shutdown_cookie); | 89 | rc = PTR_ERR(shutdown_cookie); |
| 90 | else | 90 | else |
| @@ -136,7 +136,8 @@ static void mic_dp_uninit(void) | |||
| 136 | /** | 136 | /** |
| 137 | * mic_request_card_irq - request an irq. | 137 | * mic_request_card_irq - request an irq. |
| 138 | * | 138 | * |
| 139 | * @func: The callback function that handles the interrupt. | 139 | * @handler: interrupt handler passed to request_threaded_irq. |
| 140 | * @thread_fn: thread fn. passed to request_threaded_irq. | ||
| 140 | * @name: The ASCII name of the callee requesting the irq. | 141 | * @name: The ASCII name of the callee requesting the irq. |
| 141 | * @data: private data that is returned back when calling the | 142 | * @data: private data that is returned back when calling the |
| 142 | * function handler. | 143 | * function handler. |
| @@ -149,17 +150,19 @@ static void mic_dp_uninit(void) | |||
| 149 | * error code. | 150 | * error code. |
| 150 | * | 151 | * |
| 151 | */ | 152 | */ |
| 152 | struct mic_irq *mic_request_card_irq(irqreturn_t (*func)(int irq, void *data), | 153 | struct mic_irq * |
| 153 | const char *name, void *data, int index) | 154 | mic_request_card_irq(irq_handler_t handler, |
| 155 | irq_handler_t thread_fn, const char *name, | ||
| 156 | void *data, int index) | ||
| 154 | { | 157 | { |
| 155 | int rc = 0; | 158 | int rc = 0; |
| 156 | unsigned long cookie; | 159 | unsigned long cookie; |
| 157 | struct mic_driver *mdrv = g_drv; | 160 | struct mic_driver *mdrv = g_drv; |
| 158 | 161 | ||
| 159 | rc = request_irq(mic_db_to_irq(mdrv, index), func, | 162 | rc = request_threaded_irq(mic_db_to_irq(mdrv, index), handler, |
| 160 | 0, name, data); | 163 | thread_fn, 0, name, data); |
| 161 | if (rc) { | 164 | if (rc) { |
| 162 | dev_err(mdrv->dev, "request_irq failed rc = %d\n", rc); | 165 | dev_err(mdrv->dev, "request_threaded_irq failed rc = %d\n", rc); |
| 163 | goto err; | 166 | goto err; |
| 164 | } | 167 | } |
| 165 | mdrv->irq_info.irq_usage_count[index]++; | 168 | mdrv->irq_info.irq_usage_count[index]++; |
| @@ -172,9 +175,9 @@ err: | |||
| 172 | /** | 175 | /** |
| 173 | * mic_free_card_irq - free irq. | 176 | * mic_free_card_irq - free irq. |
| 174 | * | 177 | * |
| 175 | * @cookie: cookie obtained during a successful call to mic_request_irq | 178 | * @cookie: cookie obtained during a successful call to mic_request_threaded_irq |
| 176 | * @data: private data specified by the calling function during the | 179 | * @data: private data specified by the calling function during the |
| 177 | * mic_request_irq | 180 | * mic_request_threaded_irq |
| 178 | * | 181 | * |
| 179 | * returns: none. | 182 | * returns: none. |
| 180 | */ | 183 | */ |
diff --git a/drivers/misc/mic/card/mic_device.h b/drivers/misc/mic/card/mic_device.h index 306f502be95e..844be8fc9b22 100644 --- a/drivers/misc/mic/card/mic_device.h +++ b/drivers/misc/mic/card/mic_device.h | |||
| @@ -30,6 +30,8 @@ | |||
| 30 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
| 31 | #include <linux/io.h> | 31 | #include <linux/io.h> |
| 32 | #include <linux/irqreturn.h> | 32 | #include <linux/irqreturn.h> |
| 33 | #include <linux/interrupt.h> | ||
| 34 | #include <linux/mic_bus.h> | ||
| 33 | 35 | ||
| 34 | /** | 36 | /** |
| 35 | * struct mic_intr_info - Contains h/w specific interrupt sources info | 37 | * struct mic_intr_info - Contains h/w specific interrupt sources info |
| @@ -70,6 +72,7 @@ struct mic_device { | |||
| 70 | * @hotplug_work: Hot plug work for adding/removing virtio devices. | 72 | * @hotplug_work: Hot plug work for adding/removing virtio devices. |
| 71 | * @irq_info: The OS specific irq information | 73 | * @irq_info: The OS specific irq information |
| 72 | * @intr_info: H/W specific interrupt information. | 74 | * @intr_info: H/W specific interrupt information. |
| 75 | * @dma_mbdev: dma device on the MIC virtual bus. | ||
| 73 | */ | 76 | */ |
| 74 | struct mic_driver { | 77 | struct mic_driver { |
| 75 | char name[20]; | 78 | char name[20]; |
| @@ -80,6 +83,7 @@ struct mic_driver { | |||
| 80 | struct work_struct hotplug_work; | 83 | struct work_struct hotplug_work; |
| 81 | struct mic_irq_info irq_info; | 84 | struct mic_irq_info irq_info; |
| 82 | struct mic_intr_info intr_info; | 85 | struct mic_intr_info intr_info; |
| 86 | struct mbus_device *dma_mbdev; | ||
| 83 | }; | 87 | }; |
| 84 | 88 | ||
| 85 | /** | 89 | /** |
| @@ -116,8 +120,9 @@ mic_mmio_write(struct mic_mw *mw, u32 val, u32 offset) | |||
| 116 | int mic_driver_init(struct mic_driver *mdrv); | 120 | int mic_driver_init(struct mic_driver *mdrv); |
| 117 | void mic_driver_uninit(struct mic_driver *mdrv); | 121 | void mic_driver_uninit(struct mic_driver *mdrv); |
| 118 | int mic_next_card_db(void); | 122 | int mic_next_card_db(void); |
| 119 | struct mic_irq *mic_request_card_irq(irqreturn_t (*func)(int irq, void *data), | 123 | struct mic_irq * |
| 120 | const char *name, void *data, int intr_src); | 124 | mic_request_card_irq(irq_handler_t handler, irq_handler_t thread_fn, |
| 125 | const char *name, void *data, int intr_src); | ||
| 121 | void mic_free_card_irq(struct mic_irq *cookie, void *data); | 126 | void mic_free_card_irq(struct mic_irq *cookie, void *data); |
| 122 | u32 mic_read_spad(struct mic_device *mdev, unsigned int idx); | 127 | u32 mic_read_spad(struct mic_device *mdev, unsigned int idx); |
| 123 | void mic_send_intr(struct mic_device *mdev, int doorbell); | 128 | void mic_send_intr(struct mic_device *mdev, int doorbell); |
diff --git a/drivers/misc/mic/card/mic_virtio.c b/drivers/misc/mic/card/mic_virtio.c index 653799b96bfa..f14b60080c21 100644 --- a/drivers/misc/mic/card/mic_virtio.c +++ b/drivers/misc/mic/card/mic_virtio.c | |||
| @@ -417,7 +417,7 @@ static int mic_add_device(struct mic_device_desc __iomem *d, | |||
| 417 | 417 | ||
| 418 | virtio_db = mic_next_card_db(); | 418 | virtio_db = mic_next_card_db(); |
| 419 | mvdev->virtio_cookie = mic_request_card_irq(mic_virtio_intr_handler, | 419 | mvdev->virtio_cookie = mic_request_card_irq(mic_virtio_intr_handler, |
| 420 | "virtio intr", mvdev, virtio_db); | 420 | NULL, "virtio intr", mvdev, virtio_db); |
| 421 | if (IS_ERR(mvdev->virtio_cookie)) { | 421 | if (IS_ERR(mvdev->virtio_cookie)) { |
| 422 | ret = PTR_ERR(mvdev->virtio_cookie); | 422 | ret = PTR_ERR(mvdev->virtio_cookie); |
| 423 | goto kfree; | 423 | goto kfree; |
| @@ -606,8 +606,9 @@ int mic_devices_init(struct mic_driver *mdrv) | |||
| 606 | mic_scan_devices(mdrv, !REMOVE_DEVICES); | 606 | mic_scan_devices(mdrv, !REMOVE_DEVICES); |
| 607 | 607 | ||
| 608 | config_db = mic_next_card_db(); | 608 | config_db = mic_next_card_db(); |
| 609 | virtio_config_cookie = mic_request_card_irq(mic_extint_handler, | 609 | virtio_config_cookie = mic_request_card_irq(mic_extint_handler, NULL, |
| 610 | "virtio_config_intr", mdrv, config_db); | 610 | "virtio_config_intr", mdrv, |
| 611 | config_db); | ||
| 611 | if (IS_ERR(virtio_config_cookie)) { | 612 | if (IS_ERR(virtio_config_cookie)) { |
| 612 | rc = PTR_ERR(virtio_config_cookie); | 613 | rc = PTR_ERR(virtio_config_cookie); |
| 613 | goto exit; | 614 | goto exit; |
diff --git a/drivers/misc/mic/card/mic_x100.c b/drivers/misc/mic/card/mic_x100.c index 2868945c9a4d..9d57545d64f6 100644 --- a/drivers/misc/mic/card/mic_x100.c +++ b/drivers/misc/mic/card/mic_x100.c | |||
| @@ -148,6 +148,47 @@ void mic_card_unmap(struct mic_device *mdev, void __iomem *addr) | |||
| 148 | iounmap(addr); | 148 | iounmap(addr); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | static inline struct mic_driver *mbdev_to_mdrv(struct mbus_device *mbdev) | ||
| 152 | { | ||
| 153 | return dev_get_drvdata(mbdev->dev.parent); | ||
| 154 | } | ||
| 155 | |||
| 156 | static struct mic_irq * | ||
| 157 | _mic_request_threaded_irq(struct mbus_device *mbdev, | ||
| 158 | irq_handler_t handler, irq_handler_t thread_fn, | ||
| 159 | const char *name, void *data, int intr_src) | ||
| 160 | { | ||
| 161 | int rc = 0; | ||
| 162 | unsigned int irq = intr_src; | ||
| 163 | unsigned long cookie = irq; | ||
| 164 | |||
| 165 | rc = request_threaded_irq(irq, handler, thread_fn, 0, name, data); | ||
| 166 | if (rc) { | ||
| 167 | dev_err(mbdev_to_mdrv(mbdev)->dev, | ||
| 168 | "request_threaded_irq failed rc = %d\n", rc); | ||
| 169 | return ERR_PTR(rc); | ||
| 170 | } | ||
| 171 | return (struct mic_irq *)cookie; | ||
| 172 | } | ||
| 173 | |||
| 174 | static void _mic_free_irq(struct mbus_device *mbdev, | ||
| 175 | struct mic_irq *cookie, void *data) | ||
| 176 | { | ||
| 177 | unsigned long irq = (unsigned long)cookie; | ||
| 178 | free_irq(irq, data); | ||
| 179 | } | ||
| 180 | |||
| 181 | static void _mic_ack_interrupt(struct mbus_device *mbdev, int num) | ||
| 182 | { | ||
| 183 | mic_ack_interrupt(&mbdev_to_mdrv(mbdev)->mdev); | ||
| 184 | } | ||
| 185 | |||
| 186 | static struct mbus_hw_ops mbus_hw_ops = { | ||
| 187 | .request_threaded_irq = _mic_request_threaded_irq, | ||
| 188 | .free_irq = _mic_free_irq, | ||
| 189 | .ack_interrupt = _mic_ack_interrupt, | ||
| 190 | }; | ||
| 191 | |||
| 151 | static int __init mic_probe(struct platform_device *pdev) | 192 | static int __init mic_probe(struct platform_device *pdev) |
| 152 | { | 193 | { |
| 153 | struct mic_driver *mdrv = &g_drv; | 194 | struct mic_driver *mdrv = &g_drv; |
| @@ -159,32 +200,41 @@ static int __init mic_probe(struct platform_device *pdev) | |||
| 159 | 200 | ||
| 160 | mdev->mmio.pa = MIC_X100_MMIO_BASE; | 201 | mdev->mmio.pa = MIC_X100_MMIO_BASE; |
| 161 | mdev->mmio.len = MIC_X100_MMIO_LEN; | 202 | mdev->mmio.len = MIC_X100_MMIO_LEN; |
| 162 | mdev->mmio.va = ioremap(MIC_X100_MMIO_BASE, MIC_X100_MMIO_LEN); | 203 | mdev->mmio.va = devm_ioremap(&pdev->dev, MIC_X100_MMIO_BASE, |
| 204 | MIC_X100_MMIO_LEN); | ||
| 163 | if (!mdev->mmio.va) { | 205 | if (!mdev->mmio.va) { |
| 164 | dev_err(&pdev->dev, "Cannot remap MMIO BAR\n"); | 206 | dev_err(&pdev->dev, "Cannot remap MMIO BAR\n"); |
| 165 | rc = -EIO; | 207 | rc = -EIO; |
| 166 | goto done; | 208 | goto done; |
| 167 | } | 209 | } |
| 168 | mic_hw_intr_init(mdrv); | 210 | mic_hw_intr_init(mdrv); |
| 211 | platform_set_drvdata(pdev, mdrv); | ||
| 212 | mdrv->dma_mbdev = mbus_register_device(mdrv->dev, MBUS_DEV_DMA_MIC, | ||
| 213 | NULL, &mbus_hw_ops, | ||
| 214 | mdrv->mdev.mmio.va); | ||
| 215 | if (IS_ERR(mdrv->dma_mbdev)) { | ||
| 216 | rc = PTR_ERR(mdrv->dma_mbdev); | ||
| 217 | dev_err(&pdev->dev, "mbus_add_device failed rc %d\n", rc); | ||
| 218 | goto done; | ||
| 219 | } | ||
| 169 | rc = mic_driver_init(mdrv); | 220 | rc = mic_driver_init(mdrv); |
| 170 | if (rc) { | 221 | if (rc) { |
| 171 | dev_err(&pdev->dev, "mic_driver_init failed rc %d\n", rc); | 222 | dev_err(&pdev->dev, "mic_driver_init failed rc %d\n", rc); |
| 172 | goto iounmap; | 223 | goto remove_dma; |
| 173 | } | 224 | } |
| 174 | done: | 225 | done: |
| 175 | return rc; | 226 | return rc; |
| 176 | iounmap: | 227 | remove_dma: |
| 177 | iounmap(mdev->mmio.va); | 228 | mbus_unregister_device(mdrv->dma_mbdev); |
| 178 | return rc; | 229 | return rc; |
| 179 | } | 230 | } |
| 180 | 231 | ||
| 181 | static int mic_remove(struct platform_device *pdev) | 232 | static int mic_remove(struct platform_device *pdev) |
| 182 | { | 233 | { |
| 183 | struct mic_driver *mdrv = &g_drv; | 234 | struct mic_driver *mdrv = &g_drv; |
| 184 | struct mic_device *mdev = &mdrv->mdev; | ||
| 185 | 235 | ||
| 186 | mic_driver_uninit(mdrv); | 236 | mic_driver_uninit(mdrv); |
| 187 | iounmap(mdev->mmio.va); | 237 | mbus_unregister_device(mdrv->dma_mbdev); |
| 188 | return 0; | 238 | return 0; |
| 189 | } | 239 | } |
| 190 | 240 | ||
diff --git a/drivers/misc/mic/host/mic_boot.c b/drivers/misc/mic/host/mic_boot.c index b75c6b5cc20f..ff2b0fb1a6be 100644 --- a/drivers/misc/mic/host/mic_boot.c +++ b/drivers/misc/mic/host/mic_boot.c | |||
| @@ -23,11 +23,70 @@ | |||
| 23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
| 24 | 24 | ||
| 25 | #include <linux/mic_common.h> | 25 | #include <linux/mic_common.h> |
| 26 | #include <linux/mic_bus.h> | ||
| 26 | #include "../common/mic_dev.h" | 27 | #include "../common/mic_dev.h" |
| 27 | #include "mic_device.h" | 28 | #include "mic_device.h" |
| 28 | #include "mic_smpt.h" | 29 | #include "mic_smpt.h" |
| 29 | #include "mic_virtio.h" | 30 | #include "mic_virtio.h" |
| 30 | 31 | ||
| 32 | static inline struct mic_device *mbdev_to_mdev(struct mbus_device *mbdev) | ||
| 33 | { | ||
| 34 | return dev_get_drvdata(mbdev->dev.parent); | ||
| 35 | } | ||
| 36 | |||
| 37 | static dma_addr_t | ||
| 38 | mic_dma_map_page(struct device *dev, struct page *page, | ||
| 39 | unsigned long offset, size_t size, enum dma_data_direction dir, | ||
| 40 | struct dma_attrs *attrs) | ||
| 41 | { | ||
| 42 | void *va = phys_to_virt(page_to_phys(page)) + offset; | ||
| 43 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
| 44 | |||
| 45 | return mic_map_single(mdev, va, size); | ||
| 46 | } | ||
| 47 | |||
| 48 | static void | ||
| 49 | mic_dma_unmap_page(struct device *dev, dma_addr_t dma_addr, | ||
| 50 | size_t size, enum dma_data_direction dir, | ||
| 51 | struct dma_attrs *attrs) | ||
| 52 | { | ||
| 53 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
| 54 | mic_unmap_single(mdev, dma_addr, size); | ||
| 55 | } | ||
| 56 | |||
| 57 | static struct dma_map_ops mic_dma_ops = { | ||
| 58 | .map_page = mic_dma_map_page, | ||
| 59 | .unmap_page = mic_dma_unmap_page, | ||
| 60 | }; | ||
| 61 | |||
| 62 | static struct mic_irq * | ||
| 63 | _mic_request_threaded_irq(struct mbus_device *mbdev, | ||
| 64 | irq_handler_t handler, irq_handler_t thread_fn, | ||
| 65 | const char *name, void *data, int intr_src) | ||
| 66 | { | ||
| 67 | return mic_request_threaded_irq(mbdev_to_mdev(mbdev), handler, | ||
| 68 | thread_fn, name, data, | ||
| 69 | intr_src, MIC_INTR_DMA); | ||
| 70 | } | ||
| 71 | |||
| 72 | static void _mic_free_irq(struct mbus_device *mbdev, | ||
| 73 | struct mic_irq *cookie, void *data) | ||
| 74 | { | ||
| 75 | return mic_free_irq(mbdev_to_mdev(mbdev), cookie, data); | ||
| 76 | } | ||
| 77 | |||
| 78 | static void _mic_ack_interrupt(struct mbus_device *mbdev, int num) | ||
| 79 | { | ||
| 80 | struct mic_device *mdev = mbdev_to_mdev(mbdev); | ||
| 81 | mdev->ops->intr_workarounds(mdev); | ||
| 82 | } | ||
| 83 | |||
| 84 | static struct mbus_hw_ops mbus_hw_ops = { | ||
| 85 | .request_threaded_irq = _mic_request_threaded_irq, | ||
| 86 | .free_irq = _mic_free_irq, | ||
| 87 | .ack_interrupt = _mic_ack_interrupt, | ||
| 88 | }; | ||
| 89 | |||
| 31 | /** | 90 | /** |
| 32 | * mic_reset - Reset the MIC device. | 91 | * mic_reset - Reset the MIC device. |
| 33 | * @mdev: pointer to mic_device instance | 92 | * @mdev: pointer to mic_device instance |
| @@ -95,9 +154,21 @@ retry: | |||
| 95 | */ | 154 | */ |
| 96 | goto retry; | 155 | goto retry; |
| 97 | } | 156 | } |
| 157 | mdev->dma_mbdev = mbus_register_device(mdev->sdev->parent, | ||
| 158 | MBUS_DEV_DMA_HOST, &mic_dma_ops, | ||
| 159 | &mbus_hw_ops, mdev->mmio.va); | ||
| 160 | if (IS_ERR(mdev->dma_mbdev)) { | ||
| 161 | rc = PTR_ERR(mdev->dma_mbdev); | ||
| 162 | goto unlock_ret; | ||
| 163 | } | ||
| 164 | mdev->dma_ch = mic_request_dma_chan(mdev); | ||
| 165 | if (!mdev->dma_ch) { | ||
| 166 | rc = -ENXIO; | ||
| 167 | goto dma_remove; | ||
| 168 | } | ||
| 98 | rc = mdev->ops->load_mic_fw(mdev, buf); | 169 | rc = mdev->ops->load_mic_fw(mdev, buf); |
| 99 | if (rc) | 170 | if (rc) |
| 100 | goto unlock_ret; | 171 | goto dma_release; |
| 101 | mic_smpt_restore(mdev); | 172 | mic_smpt_restore(mdev); |
| 102 | mic_intr_restore(mdev); | 173 | mic_intr_restore(mdev); |
| 103 | mdev->intr_ops->enable_interrupts(mdev); | 174 | mdev->intr_ops->enable_interrupts(mdev); |
| @@ -105,6 +176,11 @@ retry: | |||
| 105 | mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); | 176 | mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); |
| 106 | mdev->ops->send_firmware_intr(mdev); | 177 | mdev->ops->send_firmware_intr(mdev); |
| 107 | mic_set_state(mdev, MIC_ONLINE); | 178 | mic_set_state(mdev, MIC_ONLINE); |
| 179 | goto unlock_ret; | ||
| 180 | dma_release: | ||
| 181 | dma_release_channel(mdev->dma_ch); | ||
| 182 | dma_remove: | ||
| 183 | mbus_unregister_device(mdev->dma_mbdev); | ||
| 108 | unlock_ret: | 184 | unlock_ret: |
| 109 | mutex_unlock(&mdev->mic_mutex); | 185 | mutex_unlock(&mdev->mic_mutex); |
| 110 | return rc; | 186 | return rc; |
| @@ -122,6 +198,11 @@ void mic_stop(struct mic_device *mdev, bool force) | |||
| 122 | mutex_lock(&mdev->mic_mutex); | 198 | mutex_lock(&mdev->mic_mutex); |
| 123 | if (MIC_OFFLINE != mdev->state || force) { | 199 | if (MIC_OFFLINE != mdev->state || force) { |
| 124 | mic_virtio_reset_devices(mdev); | 200 | mic_virtio_reset_devices(mdev); |
| 201 | if (mdev->dma_ch) { | ||
| 202 | dma_release_channel(mdev->dma_ch); | ||
| 203 | mdev->dma_ch = NULL; | ||
| 204 | } | ||
| 205 | mbus_unregister_device(mdev->dma_mbdev); | ||
| 125 | mic_bootparam_init(mdev); | 206 | mic_bootparam_init(mdev); |
| 126 | mic_reset(mdev); | 207 | mic_reset(mdev); |
| 127 | if (MIC_RESET_FAILED == mdev->state) | 208 | if (MIC_RESET_FAILED == mdev->state) |
diff --git a/drivers/misc/mic/host/mic_device.h b/drivers/misc/mic/host/mic_device.h index 0398c696d257..016bd15a7bd1 100644 --- a/drivers/misc/mic/host/mic_device.h +++ b/drivers/misc/mic/host/mic_device.h | |||
| @@ -25,6 +25,8 @@ | |||
| 25 | #include <linux/idr.h> | 25 | #include <linux/idr.h> |
| 26 | #include <linux/notifier.h> | 26 | #include <linux/notifier.h> |
| 27 | #include <linux/irqreturn.h> | 27 | #include <linux/irqreturn.h> |
| 28 | #include <linux/dmaengine.h> | ||
| 29 | #include <linux/mic_bus.h> | ||
| 28 | 30 | ||
| 29 | #include "mic_intr.h" | 31 | #include "mic_intr.h" |
| 30 | 32 | ||
| @@ -87,6 +89,8 @@ enum mic_stepping { | |||
| 87 | * @cdev: Character device for MIC. | 89 | * @cdev: Character device for MIC. |
| 88 | * @vdev_list: list of virtio devices. | 90 | * @vdev_list: list of virtio devices. |
| 89 | * @pm_notifier: Handles PM notifications from the OS. | 91 | * @pm_notifier: Handles PM notifications from the OS. |
| 92 | * @dma_mbdev: MIC BUS DMA device. | ||
| 93 | * @dma_ch: DMA channel reserved by this driver for use by virtio devices. | ||
| 90 | */ | 94 | */ |
| 91 | struct mic_device { | 95 | struct mic_device { |
| 92 | struct mic_mw mmio; | 96 | struct mic_mw mmio; |
| @@ -124,6 +128,8 @@ struct mic_device { | |||
| 124 | struct cdev cdev; | 128 | struct cdev cdev; |
| 125 | struct list_head vdev_list; | 129 | struct list_head vdev_list; |
| 126 | struct notifier_block pm_notifier; | 130 | struct notifier_block pm_notifier; |
| 131 | struct mbus_device *dma_mbdev; | ||
| 132 | struct dma_chan *dma_ch; | ||
| 127 | }; | 133 | }; |
| 128 | 134 | ||
| 129 | /** | 135 | /** |
| @@ -144,6 +150,7 @@ struct mic_device { | |||
| 144 | * @load_mic_fw: Load firmware segments required to boot the card | 150 | * @load_mic_fw: Load firmware segments required to boot the card |
| 145 | * into card memory. This includes the kernel, command line, ramdisk etc. | 151 | * into card memory. This includes the kernel, command line, ramdisk etc. |
| 146 | * @get_postcode: Get post code status from firmware. | 152 | * @get_postcode: Get post code status from firmware. |
| 153 | * @dma_filter: DMA filter function to be used. | ||
| 147 | */ | 154 | */ |
| 148 | struct mic_hw_ops { | 155 | struct mic_hw_ops { |
| 149 | u8 aper_bar; | 156 | u8 aper_bar; |
| @@ -159,6 +166,7 @@ struct mic_hw_ops { | |||
| 159 | void (*send_firmware_intr)(struct mic_device *mdev); | 166 | void (*send_firmware_intr)(struct mic_device *mdev); |
| 160 | int (*load_mic_fw)(struct mic_device *mdev, const char *buf); | 167 | int (*load_mic_fw)(struct mic_device *mdev, const char *buf); |
| 161 | u32 (*get_postcode)(struct mic_device *mdev); | 168 | u32 (*get_postcode)(struct mic_device *mdev); |
| 169 | bool (*dma_filter)(struct dma_chan *chan, void *param); | ||
| 162 | }; | 170 | }; |
| 163 | 171 | ||
| 164 | /** | 172 | /** |
| @@ -187,6 +195,22 @@ mic_mmio_write(struct mic_mw *mw, u32 val, u32 offset) | |||
| 187 | iowrite32(val, mw->va + offset); | 195 | iowrite32(val, mw->va + offset); |
| 188 | } | 196 | } |
| 189 | 197 | ||
| 198 | static inline struct dma_chan *mic_request_dma_chan(struct mic_device *mdev) | ||
| 199 | { | ||
| 200 | dma_cap_mask_t mask; | ||
| 201 | struct dma_chan *chan; | ||
| 202 | |||
| 203 | dma_cap_zero(mask); | ||
| 204 | dma_cap_set(DMA_MEMCPY, mask); | ||
| 205 | chan = dma_request_channel(mask, mdev->ops->dma_filter, | ||
| 206 | mdev->sdev->parent); | ||
| 207 | if (chan) | ||
| 208 | return chan; | ||
| 209 | dev_err(mdev->sdev->parent, "%s %d unable to acquire channel\n", | ||
| 210 | __func__, __LINE__); | ||
| 211 | return NULL; | ||
| 212 | } | ||
| 213 | |||
| 190 | void mic_sysfs_init(struct mic_device *mdev); | 214 | void mic_sysfs_init(struct mic_device *mdev); |
| 191 | int mic_start(struct mic_device *mdev, const char *buf); | 215 | int mic_start(struct mic_device *mdev, const char *buf); |
| 192 | void mic_stop(struct mic_device *mdev, bool force); | 216 | void mic_stop(struct mic_device *mdev, bool force); |
diff --git a/drivers/misc/mic/host/mic_intr.c b/drivers/misc/mic/host/mic_intr.c index dbc5afde1392..d686f2846ac7 100644 --- a/drivers/misc/mic/host/mic_intr.c +++ b/drivers/misc/mic/host/mic_intr.c | |||
| @@ -24,28 +24,29 @@ | |||
| 24 | #include "../common/mic_dev.h" | 24 | #include "../common/mic_dev.h" |
| 25 | #include "mic_device.h" | 25 | #include "mic_device.h" |
| 26 | 26 | ||
| 27 | /* | 27 | static irqreturn_t mic_thread_fn(int irq, void *dev) |
| 28 | * mic_invoke_callback - Invoke callback functions registered for | ||
| 29 | * the corresponding source id. | ||
| 30 | * | ||
| 31 | * @mdev: pointer to the mic_device instance | ||
| 32 | * @idx: The interrupt source id. | ||
| 33 | * | ||
| 34 | * Returns none. | ||
| 35 | */ | ||
| 36 | static inline void mic_invoke_callback(struct mic_device *mdev, int idx) | ||
| 37 | { | 28 | { |
| 29 | struct mic_device *mdev = dev; | ||
| 30 | struct mic_intr_info *intr_info = mdev->intr_info; | ||
| 31 | struct mic_irq_info *irq_info = &mdev->irq_info; | ||
| 38 | struct mic_intr_cb *intr_cb; | 32 | struct mic_intr_cb *intr_cb; |
| 39 | struct pci_dev *pdev = container_of(mdev->sdev->parent, | 33 | struct pci_dev *pdev = container_of(mdev->sdev->parent, |
| 40 | struct pci_dev, dev); | 34 | struct pci_dev, dev); |
| 35 | int i; | ||
| 41 | 36 | ||
| 42 | spin_lock(&mdev->irq_info.mic_intr_lock); | 37 | spin_lock(&irq_info->mic_thread_lock); |
| 43 | list_for_each_entry(intr_cb, &mdev->irq_info.cb_list[idx], list) | 38 | for (i = intr_info->intr_start_idx[MIC_INTR_DB]; |
| 44 | if (intr_cb->func) | 39 | i < intr_info->intr_len[MIC_INTR_DB]; i++) |
| 45 | intr_cb->func(pdev->irq, intr_cb->data); | 40 | if (test_and_clear_bit(i, &irq_info->mask)) { |
| 46 | spin_unlock(&mdev->irq_info.mic_intr_lock); | 41 | list_for_each_entry(intr_cb, &irq_info->cb_list[i], |
| 42 | list) | ||
| 43 | if (intr_cb->thread_fn) | ||
| 44 | intr_cb->thread_fn(pdev->irq, | ||
| 45 | intr_cb->data); | ||
| 46 | } | ||
| 47 | spin_unlock(&irq_info->mic_thread_lock); | ||
| 48 | return IRQ_HANDLED; | ||
| 47 | } | 49 | } |
| 48 | |||
| 49 | /** | 50 | /** |
| 50 | * mic_interrupt - Generic interrupt handler for | 51 | * mic_interrupt - Generic interrupt handler for |
| 51 | * MSI and INTx based interrupts. | 52 | * MSI and INTx based interrupts. |
| @@ -53,7 +54,11 @@ static inline void mic_invoke_callback(struct mic_device *mdev, int idx) | |||
| 53 | static irqreturn_t mic_interrupt(int irq, void *dev) | 54 | static irqreturn_t mic_interrupt(int irq, void *dev) |
| 54 | { | 55 | { |
| 55 | struct mic_device *mdev = dev; | 56 | struct mic_device *mdev = dev; |
| 56 | struct mic_intr_info *info = mdev->intr_info; | 57 | struct mic_intr_info *intr_info = mdev->intr_info; |
| 58 | struct mic_irq_info *irq_info = &mdev->irq_info; | ||
| 59 | struct mic_intr_cb *intr_cb; | ||
| 60 | struct pci_dev *pdev = container_of(mdev->sdev->parent, | ||
| 61 | struct pci_dev, dev); | ||
| 57 | u32 mask; | 62 | u32 mask; |
| 58 | int i; | 63 | int i; |
| 59 | 64 | ||
| @@ -61,12 +66,19 @@ static irqreturn_t mic_interrupt(int irq, void *dev) | |||
| 61 | if (!mask) | 66 | if (!mask) |
| 62 | return IRQ_NONE; | 67 | return IRQ_NONE; |
| 63 | 68 | ||
| 64 | for (i = info->intr_start_idx[MIC_INTR_DB]; | 69 | spin_lock(&irq_info->mic_intr_lock); |
| 65 | i < info->intr_len[MIC_INTR_DB]; i++) | 70 | for (i = intr_info->intr_start_idx[MIC_INTR_DB]; |
| 66 | if (mask & BIT(i)) | 71 | i < intr_info->intr_len[MIC_INTR_DB]; i++) |
| 67 | mic_invoke_callback(mdev, i); | 72 | if (mask & BIT(i)) { |
| 68 | 73 | list_for_each_entry(intr_cb, &irq_info->cb_list[i], | |
| 69 | return IRQ_HANDLED; | 74 | list) |
| 75 | if (intr_cb->handler) | ||
| 76 | intr_cb->handler(pdev->irq, | ||
| 77 | intr_cb->data); | ||
| 78 | set_bit(i, &irq_info->mask); | ||
| 79 | } | ||
| 80 | spin_unlock(&irq_info->mic_intr_lock); | ||
| 81 | return IRQ_WAKE_THREAD; | ||
| 70 | } | 82 | } |
| 71 | 83 | ||
| 72 | /* Return the interrupt offset from the index. Index is 0 based. */ | 84 | /* Return the interrupt offset from the index. Index is 0 based. */ |
| @@ -99,14 +111,15 @@ static struct msix_entry *mic_get_available_vector(struct mic_device *mdev) | |||
| 99 | * | 111 | * |
| 100 | * @mdev: pointer to the mic_device instance | 112 | * @mdev: pointer to the mic_device instance |
| 101 | * @idx: The source id to be registered. | 113 | * @idx: The source id to be registered. |
| 102 | * @func: The function to be called when the source id receives | 114 | * @handler: The function to be called when the source id receives |
| 103 | * the interrupt. | 115 | * the interrupt. |
| 116 | * @thread_fn: thread fn. corresponding to the handler | ||
| 104 | * @data: Private data of the requester. | 117 | * @data: Private data of the requester. |
| 105 | * Return the callback structure that was registered or an | 118 | * Return the callback structure that was registered or an |
| 106 | * appropriate error on failure. | 119 | * appropriate error on failure. |
| 107 | */ | 120 | */ |
| 108 | static struct mic_intr_cb *mic_register_intr_callback(struct mic_device *mdev, | 121 | static struct mic_intr_cb *mic_register_intr_callback(struct mic_device *mdev, |
| 109 | u8 idx, irqreturn_t (*func) (int irq, void *dev), | 122 | u8 idx, irq_handler_t handler, irq_handler_t thread_fn, |
| 110 | void *data) | 123 | void *data) |
| 111 | { | 124 | { |
| 112 | struct mic_intr_cb *intr_cb; | 125 | struct mic_intr_cb *intr_cb; |
| @@ -117,7 +130,8 @@ static struct mic_intr_cb *mic_register_intr_callback(struct mic_device *mdev, | |||
| 117 | if (!intr_cb) | 130 | if (!intr_cb) |
| 118 | return ERR_PTR(-ENOMEM); | 131 | return ERR_PTR(-ENOMEM); |
| 119 | 132 | ||
| 120 | intr_cb->func = func; | 133 | intr_cb->handler = handler; |
| 134 | intr_cb->thread_fn = thread_fn; | ||
| 121 | intr_cb->data = data; | 135 | intr_cb->data = data; |
| 122 | intr_cb->cb_id = ida_simple_get(&mdev->irq_info.cb_ida, | 136 | intr_cb->cb_id = ida_simple_get(&mdev->irq_info.cb_ida, |
| 123 | 0, 0, GFP_KERNEL); | 137 | 0, 0, GFP_KERNEL); |
| @@ -126,9 +140,11 @@ static struct mic_intr_cb *mic_register_intr_callback(struct mic_device *mdev, | |||
| 126 | goto ida_fail; | 140 | goto ida_fail; |
| 127 | } | 141 | } |
| 128 | 142 | ||
| 143 | spin_lock(&mdev->irq_info.mic_thread_lock); | ||
| 129 | spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); | 144 | spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); |
| 130 | list_add_tail(&intr_cb->list, &mdev->irq_info.cb_list[idx]); | 145 | list_add_tail(&intr_cb->list, &mdev->irq_info.cb_list[idx]); |
| 131 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); | 146 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); |
| 147 | spin_unlock(&mdev->irq_info.mic_thread_lock); | ||
| 132 | 148 | ||
| 133 | return intr_cb; | 149 | return intr_cb; |
| 134 | ida_fail: | 150 | ida_fail: |
| @@ -152,8 +168,9 @@ static u8 mic_unregister_intr_callback(struct mic_device *mdev, u32 idx) | |||
| 152 | unsigned long flags; | 168 | unsigned long flags; |
| 153 | int i; | 169 | int i; |
| 154 | 170 | ||
| 171 | spin_lock(&mdev->irq_info.mic_thread_lock); | ||
| 172 | spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); | ||
| 155 | for (i = 0; i < MIC_NUM_OFFSETS; i++) { | 173 | for (i = 0; i < MIC_NUM_OFFSETS; i++) { |
| 156 | spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); | ||
| 157 | list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) { | 174 | list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) { |
| 158 | intr_cb = list_entry(pos, struct mic_intr_cb, list); | 175 | intr_cb = list_entry(pos, struct mic_intr_cb, list); |
| 159 | if (intr_cb->cb_id == idx) { | 176 | if (intr_cb->cb_id == idx) { |
| @@ -163,11 +180,13 @@ static u8 mic_unregister_intr_callback(struct mic_device *mdev, u32 idx) | |||
| 163 | kfree(intr_cb); | 180 | kfree(intr_cb); |
| 164 | spin_unlock_irqrestore( | 181 | spin_unlock_irqrestore( |
| 165 | &mdev->irq_info.mic_intr_lock, flags); | 182 | &mdev->irq_info.mic_intr_lock, flags); |
| 183 | spin_unlock(&mdev->irq_info.mic_thread_lock); | ||
| 166 | return i; | 184 | return i; |
| 167 | } | 185 | } |
| 168 | } | 186 | } |
| 169 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); | ||
| 170 | } | 187 | } |
| 188 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); | ||
| 189 | spin_unlock(&mdev->irq_info.mic_thread_lock); | ||
| 171 | return MIC_NUM_OFFSETS; | 190 | return MIC_NUM_OFFSETS; |
| 172 | } | 191 | } |
| 173 | 192 | ||
| @@ -242,6 +261,7 @@ static int mic_setup_callbacks(struct mic_device *mdev) | |||
| 242 | INIT_LIST_HEAD(&mdev->irq_info.cb_list[i]); | 261 | INIT_LIST_HEAD(&mdev->irq_info.cb_list[i]); |
| 243 | ida_init(&mdev->irq_info.cb_ida); | 262 | ida_init(&mdev->irq_info.cb_ida); |
| 244 | spin_lock_init(&mdev->irq_info.mic_intr_lock); | 263 | spin_lock_init(&mdev->irq_info.mic_intr_lock); |
| 264 | spin_lock_init(&mdev->irq_info.mic_thread_lock); | ||
| 245 | return 0; | 265 | return 0; |
| 246 | } | 266 | } |
| 247 | 267 | ||
| @@ -258,14 +278,12 @@ static void mic_release_callbacks(struct mic_device *mdev) | |||
| 258 | struct mic_intr_cb *intr_cb; | 278 | struct mic_intr_cb *intr_cb; |
| 259 | int i; | 279 | int i; |
| 260 | 280 | ||
| 281 | spin_lock(&mdev->irq_info.mic_thread_lock); | ||
| 282 | spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); | ||
| 261 | for (i = 0; i < MIC_NUM_OFFSETS; i++) { | 283 | for (i = 0; i < MIC_NUM_OFFSETS; i++) { |
| 262 | spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); | ||
| 263 | 284 | ||
| 264 | if (list_empty(&mdev->irq_info.cb_list[i])) { | 285 | if (list_empty(&mdev->irq_info.cb_list[i])) |
| 265 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, | ||
| 266 | flags); | ||
| 267 | break; | 286 | break; |
| 268 | } | ||
| 269 | 287 | ||
| 270 | list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) { | 288 | list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) { |
| 271 | intr_cb = list_entry(pos, struct mic_intr_cb, list); | 289 | intr_cb = list_entry(pos, struct mic_intr_cb, list); |
| @@ -274,8 +292,9 @@ static void mic_release_callbacks(struct mic_device *mdev) | |||
| 274 | intr_cb->cb_id); | 292 | intr_cb->cb_id); |
| 275 | kfree(intr_cb); | 293 | kfree(intr_cb); |
| 276 | } | 294 | } |
| 277 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); | ||
| 278 | } | 295 | } |
| 296 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); | ||
| 297 | spin_unlock(&mdev->irq_info.mic_thread_lock); | ||
| 279 | ida_destroy(&mdev->irq_info.cb_ida); | 298 | ida_destroy(&mdev->irq_info.cb_ida); |
| 280 | kfree(mdev->irq_info.cb_list); | 299 | kfree(mdev->irq_info.cb_list); |
| 281 | } | 300 | } |
| @@ -313,7 +332,8 @@ static int mic_setup_msi(struct mic_device *mdev, struct pci_dev *pdev) | |||
| 313 | goto err_nomem2; | 332 | goto err_nomem2; |
| 314 | } | 333 | } |
| 315 | 334 | ||
| 316 | rc = request_irq(pdev->irq, mic_interrupt, 0 , "mic-msi", mdev); | 335 | rc = request_threaded_irq(pdev->irq, mic_interrupt, mic_thread_fn, |
| 336 | 0, "mic-msi", mdev); | ||
| 317 | if (rc) { | 337 | if (rc) { |
| 318 | dev_err(&pdev->dev, "Error allocating MSI interrupt\n"); | 338 | dev_err(&pdev->dev, "Error allocating MSI interrupt\n"); |
| 319 | goto err_irq_req_fail; | 339 | goto err_irq_req_fail; |
| @@ -353,8 +373,8 @@ static int mic_setup_intx(struct mic_device *mdev, struct pci_dev *pdev) | |||
| 353 | goto err_nomem; | 373 | goto err_nomem; |
| 354 | } | 374 | } |
| 355 | 375 | ||
| 356 | rc = request_irq(pdev->irq, mic_interrupt, | 376 | rc = request_threaded_irq(pdev->irq, mic_interrupt, mic_thread_fn, |
| 357 | IRQF_SHARED, "mic-intx", mdev); | 377 | IRQF_SHARED, "mic-intx", mdev); |
| 358 | if (rc) | 378 | if (rc) |
| 359 | goto err; | 379 | goto err; |
| 360 | 380 | ||
| @@ -391,13 +411,14 @@ int mic_next_db(struct mic_device *mdev) | |||
| 391 | #define MK_COOKIE(x, y) ((x) | (y) << COOKIE_ID_SHIFT) | 411 | #define MK_COOKIE(x, y) ((x) | (y) << COOKIE_ID_SHIFT) |
| 392 | 412 | ||
| 393 | /** | 413 | /** |
| 394 | * mic_request_irq - request an irq. mic_mutex needs | 414 | * mic_request_threaded_irq - request an irq. mic_mutex needs |
| 395 | * to be held before calling this function. | 415 | * to be held before calling this function. |
| 396 | * | 416 | * |
| 397 | * @mdev: pointer to mic_device instance | 417 | * @mdev: pointer to mic_device instance |
| 398 | * @func: The callback function that handles the interrupt. | 418 | * @handler: The callback function that handles the interrupt. |
| 399 | * The function needs to call ack_interrupts | 419 | * The function needs to call ack_interrupts |
| 400 | * (mdev->ops->ack_interrupt(mdev)) when handling the interrupts. | 420 | * (mdev->ops->ack_interrupt(mdev)) when handling the interrupts. |
| 421 | * @thread_fn: thread fn required by request_threaded_irq. | ||
| 401 | * @name: The ASCII name of the callee requesting the irq. | 422 | * @name: The ASCII name of the callee requesting the irq. |
| 402 | * @data: private data that is returned back when calling the | 423 | * @data: private data that is returned back when calling the |
| 403 | * function handler. | 424 | * function handler. |
| @@ -412,10 +433,11 @@ int mic_next_db(struct mic_device *mdev) | |||
| 412 | * error code. | 433 | * error code. |
| 413 | * | 434 | * |
| 414 | */ | 435 | */ |
| 415 | struct mic_irq *mic_request_irq(struct mic_device *mdev, | 436 | struct mic_irq * |
| 416 | irqreturn_t (*func)(int irq, void *dev), | 437 | mic_request_threaded_irq(struct mic_device *mdev, |
| 417 | const char *name, void *data, int intr_src, | 438 | irq_handler_t handler, irq_handler_t thread_fn, |
| 418 | enum mic_intr_type type) | 439 | const char *name, void *data, int intr_src, |
| 440 | enum mic_intr_type type) | ||
| 419 | { | 441 | { |
| 420 | u16 offset; | 442 | u16 offset; |
| 421 | int rc = 0; | 443 | int rc = 0; |
| @@ -444,7 +466,8 @@ struct mic_irq *mic_request_irq(struct mic_device *mdev, | |||
| 444 | goto err; | 466 | goto err; |
| 445 | } | 467 | } |
| 446 | 468 | ||
| 447 | rc = request_irq(msix->vector, func, 0, name, data); | 469 | rc = request_threaded_irq(msix->vector, handler, thread_fn, |
| 470 | 0, name, data); | ||
| 448 | if (rc) { | 471 | if (rc) { |
| 449 | dev_dbg(mdev->sdev->parent, | 472 | dev_dbg(mdev->sdev->parent, |
| 450 | "request irq failed rc = %d\n", rc); | 473 | "request irq failed rc = %d\n", rc); |
| @@ -458,8 +481,8 @@ struct mic_irq *mic_request_irq(struct mic_device *mdev, | |||
| 458 | dev_dbg(mdev->sdev->parent, "irq: %d assigned for src: %d\n", | 481 | dev_dbg(mdev->sdev->parent, "irq: %d assigned for src: %d\n", |
| 459 | msix->vector, intr_src); | 482 | msix->vector, intr_src); |
| 460 | } else { | 483 | } else { |
| 461 | intr_cb = mic_register_intr_callback(mdev, | 484 | intr_cb = mic_register_intr_callback(mdev, offset, handler, |
| 462 | offset, func, data); | 485 | thread_fn, data); |
| 463 | if (IS_ERR(intr_cb)) { | 486 | if (IS_ERR(intr_cb)) { |
| 464 | dev_err(mdev->sdev->parent, | 487 | dev_err(mdev->sdev->parent, |
| 465 | "No available callback entries for use\n"); | 488 | "No available callback entries for use\n"); |
| @@ -487,9 +510,9 @@ err: | |||
| 487 | * needs to be held before calling this function. | 510 | * needs to be held before calling this function. |
| 488 | * | 511 | * |
| 489 | * @mdev: pointer to mic_device instance | 512 | * @mdev: pointer to mic_device instance |
| 490 | * @cookie: cookie obtained during a successful call to mic_request_irq | 513 | * @cookie: cookie obtained during a successful call to mic_request_threaded_irq |
| 491 | * @data: private data specified by the calling function during the | 514 | * @data: private data specified by the calling function during the |
| 492 | * mic_request_irq | 515 | * mic_request_threaded_irq |
| 493 | * | 516 | * |
| 494 | * returns: none. | 517 | * returns: none. |
| 495 | */ | 518 | */ |
diff --git a/drivers/misc/mic/host/mic_intr.h b/drivers/misc/mic/host/mic_intr.h index 6091aa97e116..9f783d4ad7f1 100644 --- a/drivers/misc/mic/host/mic_intr.h +++ b/drivers/misc/mic/host/mic_intr.h | |||
| @@ -21,12 +21,15 @@ | |||
| 21 | #ifndef _MIC_INTR_H_ | 21 | #ifndef _MIC_INTR_H_ |
| 22 | #define _MIC_INTR_H_ | 22 | #define _MIC_INTR_H_ |
| 23 | 23 | ||
| 24 | #include <linux/bitops.h> | ||
| 25 | #include <linux/interrupt.h> | ||
| 24 | /* | 26 | /* |
| 25 | * The minimum number of msix vectors required for normal operation. | 27 | * The minimum number of msix vectors required for normal operation. |
| 26 | * 3 for virtio network, console and block devices. | 28 | * 3 for virtio network, console and block devices. |
| 27 | * 1 for card shutdown notifications. | 29 | * 1 for card shutdown notifications. |
| 30 | * 4 for host owned DMA channels. | ||
| 28 | */ | 31 | */ |
| 29 | #define MIC_MIN_MSIX 4 | 32 | #define MIC_MIN_MSIX 8 |
| 30 | #define MIC_NUM_OFFSETS 32 | 33 | #define MIC_NUM_OFFSETS 32 |
| 31 | 34 | ||
| 32 | /** | 35 | /** |
| @@ -68,7 +71,11 @@ struct mic_intr_info { | |||
| 68 | * @num_vectors: The number of MSI/MSI-x vectors that have been allocated. | 71 | * @num_vectors: The number of MSI/MSI-x vectors that have been allocated. |
| 69 | * @cb_ida: callback ID allocator to track the callbacks registered. | 72 | * @cb_ida: callback ID allocator to track the callbacks registered. |
| 70 | * @mic_intr_lock: spinlock to protect the interrupt callback list. | 73 | * @mic_intr_lock: spinlock to protect the interrupt callback list. |
| 74 | * @mic_thread_lock: spinlock to protect the thread callback list. | ||
| 75 | * This lock is used to protect against thread_fn while | ||
| 76 | * mic_intr_lock is used to protect against interrupt handler. | ||
| 71 | * @cb_list: Array of callback lists one for each source. | 77 | * @cb_list: Array of callback lists one for each source. |
| 78 | * @mask: Mask used by the main thread fn to call the underlying thread fns. | ||
| 72 | */ | 79 | */ |
| 73 | struct mic_irq_info { | 80 | struct mic_irq_info { |
| 74 | int next_avail_src; | 81 | int next_avail_src; |
| @@ -77,19 +84,23 @@ struct mic_irq_info { | |||
| 77 | u16 num_vectors; | 84 | u16 num_vectors; |
| 78 | struct ida cb_ida; | 85 | struct ida cb_ida; |
| 79 | spinlock_t mic_intr_lock; | 86 | spinlock_t mic_intr_lock; |
| 87 | spinlock_t mic_thread_lock; | ||
| 80 | struct list_head *cb_list; | 88 | struct list_head *cb_list; |
| 89 | unsigned long mask; | ||
| 81 | }; | 90 | }; |
| 82 | 91 | ||
| 83 | /** | 92 | /** |
| 84 | * struct mic_intr_cb - Interrupt callback structure. | 93 | * struct mic_intr_cb - Interrupt callback structure. |
| 85 | * | 94 | * |
| 86 | * @func: The callback function | 95 | * @handler: The callback function |
| 96 | * @thread_fn: The thread_fn. | ||
| 87 | * @data: Private data of the requester. | 97 | * @data: Private data of the requester. |
| 88 | * @cb_id: The callback id. Identifies this callback. | 98 | * @cb_id: The callback id. Identifies this callback. |
| 89 | * @list: list head pointing to the next callback structure. | 99 | * @list: list head pointing to the next callback structure. |
| 90 | */ | 100 | */ |
| 91 | struct mic_intr_cb { | 101 | struct mic_intr_cb { |
| 92 | irqreturn_t (*func) (int irq, void *data); | 102 | irq_handler_t handler; |
| 103 | irq_handler_t thread_fn; | ||
| 93 | void *data; | 104 | void *data; |
| 94 | int cb_id; | 105 | int cb_id; |
| 95 | struct list_head list; | 106 | struct list_head list; |
| @@ -124,11 +135,11 @@ struct mic_hw_intr_ops { | |||
| 124 | }; | 135 | }; |
| 125 | 136 | ||
| 126 | int mic_next_db(struct mic_device *mdev); | 137 | int mic_next_db(struct mic_device *mdev); |
| 127 | struct mic_irq *mic_request_irq(struct mic_device *mdev, | 138 | struct mic_irq * |
| 128 | irqreturn_t (*func)(int irq, void *data), | 139 | mic_request_threaded_irq(struct mic_device *mdev, |
| 129 | const char *name, void *data, int intr_src, | 140 | irq_handler_t handler, irq_handler_t thread_fn, |
| 130 | enum mic_intr_type type); | 141 | const char *name, void *data, int intr_src, |
| 131 | 142 | enum mic_intr_type type); | |
| 132 | void mic_free_irq(struct mic_device *mdev, | 143 | void mic_free_irq(struct mic_device *mdev, |
| 133 | struct mic_irq *cookie, void *data); | 144 | struct mic_irq *cookie, void *data); |
| 134 | int mic_setup_interrupts(struct mic_device *mdev, struct pci_dev *pdev); | 145 | int mic_setup_interrupts(struct mic_device *mdev, struct pci_dev *pdev); |
diff --git a/drivers/misc/mic/host/mic_main.c b/drivers/misc/mic/host/mic_main.c index c04a021e20c7..ab37a3117d23 100644 --- a/drivers/misc/mic/host/mic_main.c +++ b/drivers/misc/mic/host/mic_main.c | |||
| @@ -38,7 +38,7 @@ | |||
| 38 | 38 | ||
| 39 | static const char mic_driver_name[] = "mic"; | 39 | static const char mic_driver_name[] = "mic"; |
| 40 | 40 | ||
| 41 | static DEFINE_PCI_DEVICE_TABLE(mic_pci_tbl) = { | 41 | static const struct pci_device_id mic_pci_tbl[] = { |
| 42 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2250)}, | 42 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2250)}, |
| 43 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2251)}, | 43 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2251)}, |
| 44 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2252)}, | 44 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2252)}, |
| @@ -389,8 +389,9 @@ static int mic_probe(struct pci_dev *pdev, | |||
| 389 | mutex_lock(&mdev->mic_mutex); | 389 | mutex_lock(&mdev->mic_mutex); |
| 390 | 390 | ||
| 391 | mdev->shutdown_db = mic_next_db(mdev); | 391 | mdev->shutdown_db = mic_next_db(mdev); |
| 392 | mdev->shutdown_cookie = mic_request_irq(mdev, mic_shutdown_db, | 392 | mdev->shutdown_cookie = mic_request_threaded_irq(mdev, mic_shutdown_db, |
| 393 | "shutdown-interrupt", mdev, mdev->shutdown_db, MIC_INTR_DB); | 393 | NULL, "shutdown-interrupt", mdev, |
| 394 | mdev->shutdown_db, MIC_INTR_DB); | ||
| 394 | if (IS_ERR(mdev->shutdown_cookie)) { | 395 | if (IS_ERR(mdev->shutdown_cookie)) { |
| 395 | rc = PTR_ERR(mdev->shutdown_cookie); | 396 | rc = PTR_ERR(mdev->shutdown_cookie); |
| 396 | mutex_unlock(&mdev->mic_mutex); | 397 | mutex_unlock(&mdev->mic_mutex); |
diff --git a/drivers/misc/mic/host/mic_virtio.c b/drivers/misc/mic/host/mic_virtio.c index 7e1ef0ebbb80..a020e4eb435a 100644 --- a/drivers/misc/mic/host/mic_virtio.c +++ b/drivers/misc/mic/host/mic_virtio.c | |||
| @@ -21,60 +21,157 @@ | |||
| 21 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
| 22 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
| 23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
| 24 | 24 | #include <linux/dmaengine.h> | |
| 25 | #include <linux/mic_common.h> | 25 | #include <linux/mic_common.h> |
| 26 | |||
| 26 | #include "../common/mic_dev.h" | 27 | #include "../common/mic_dev.h" |
| 27 | #include "mic_device.h" | 28 | #include "mic_device.h" |
| 28 | #include "mic_smpt.h" | 29 | #include "mic_smpt.h" |
| 29 | #include "mic_virtio.h" | 30 | #include "mic_virtio.h" |
| 30 | 31 | ||
| 31 | /* | 32 | /* |
| 32 | * Initiates the copies across the PCIe bus from card memory to | 33 | * Size of the internal buffer used during DMA's as an intermediate buffer |
| 33 | * a user space buffer. | 34 | * for copy to/from user. |
| 34 | */ | 35 | */ |
| 35 | static int mic_virtio_copy_to_user(struct mic_vdev *mvdev, | 36 | #define MIC_INT_DMA_BUF_SIZE PAGE_ALIGN(64 * 1024ULL) |
| 36 | void __user *ubuf, size_t len, u64 addr) | 37 | |
| 38 | static int mic_sync_dma(struct mic_device *mdev, dma_addr_t dst, | ||
| 39 | dma_addr_t src, size_t len) | ||
| 37 | { | 40 | { |
| 38 | int err; | 41 | int err = 0; |
| 39 | void __iomem *dbuf = mvdev->mdev->aper.va + addr; | 42 | struct dma_async_tx_descriptor *tx; |
| 40 | /* | 43 | struct dma_chan *mic_ch = mdev->dma_ch; |
| 41 | * We are copying from IO below an should ideally use something | 44 | |
| 42 | * like copy_to_user_fromio(..) if it existed. | 45 | if (!mic_ch) { |
| 43 | */ | 46 | err = -EBUSY; |
| 44 | if (copy_to_user(ubuf, (void __force *)dbuf, len)) { | 47 | goto error; |
| 45 | err = -EFAULT; | 48 | } |
| 46 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | 49 | |
| 50 | tx = mic_ch->device->device_prep_dma_memcpy(mic_ch, dst, src, len, | ||
| 51 | DMA_PREP_FENCE); | ||
| 52 | if (!tx) { | ||
| 53 | err = -ENOMEM; | ||
| 54 | goto error; | ||
| 55 | } else { | ||
| 56 | dma_cookie_t cookie = tx->tx_submit(tx); | ||
| 57 | |||
| 58 | err = dma_submit_error(cookie); | ||
| 59 | if (err) | ||
| 60 | goto error; | ||
| 61 | err = dma_sync_wait(mic_ch, cookie); | ||
| 62 | } | ||
| 63 | error: | ||
| 64 | if (err) | ||
| 65 | dev_err(mdev->sdev->parent, "%s %d err %d\n", | ||
| 47 | __func__, __LINE__, err); | 66 | __func__, __LINE__, err); |
| 48 | goto err; | 67 | return err; |
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Initiates the copies across the PCIe bus from card memory to a user | ||
| 72 | * space buffer. When transfers are done using DMA, source/destination | ||
| 73 | * addresses and transfer length must follow the alignment requirements of | ||
| 74 | * the MIC DMA engine. | ||
| 75 | */ | ||
| 76 | static int mic_virtio_copy_to_user(struct mic_vdev *mvdev, void __user *ubuf, | ||
| 77 | size_t len, u64 daddr, size_t dlen, | ||
| 78 | int vr_idx) | ||
| 79 | { | ||
| 80 | struct mic_device *mdev = mvdev->mdev; | ||
| 81 | void __iomem *dbuf = mdev->aper.va + daddr; | ||
| 82 | struct mic_vringh *mvr = &mvdev->mvr[vr_idx]; | ||
| 83 | size_t dma_alignment = 1 << mdev->dma_ch->device->copy_align; | ||
| 84 | size_t dma_offset; | ||
| 85 | size_t partlen; | ||
| 86 | int err; | ||
| 87 | |||
| 88 | dma_offset = daddr - round_down(daddr, dma_alignment); | ||
| 89 | daddr -= dma_offset; | ||
| 90 | len += dma_offset; | ||
| 91 | |||
| 92 | while (len) { | ||
| 93 | partlen = min_t(size_t, len, MIC_INT_DMA_BUF_SIZE); | ||
| 94 | |||
| 95 | err = mic_sync_dma(mdev, mvr->buf_da, daddr, | ||
| 96 | ALIGN(partlen, dma_alignment)); | ||
| 97 | if (err) | ||
| 98 | goto err; | ||
| 99 | |||
| 100 | if (copy_to_user(ubuf, mvr->buf + dma_offset, | ||
| 101 | partlen - dma_offset)) { | ||
| 102 | err = -EFAULT; | ||
| 103 | goto err; | ||
| 104 | } | ||
| 105 | daddr += partlen; | ||
| 106 | ubuf += partlen; | ||
| 107 | dbuf += partlen; | ||
| 108 | mvdev->in_bytes_dma += partlen; | ||
| 109 | mvdev->in_bytes += partlen; | ||
| 110 | len -= partlen; | ||
| 111 | dma_offset = 0; | ||
| 49 | } | 112 | } |
| 50 | mvdev->in_bytes += len; | 113 | return 0; |
| 51 | err = 0; | ||
| 52 | err: | 114 | err: |
| 115 | dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, err); | ||
| 53 | return err; | 116 | return err; |
| 54 | } | 117 | } |
| 55 | 118 | ||
| 56 | /* | 119 | /* |
| 57 | * Initiates copies across the PCIe bus from a user space | 120 | * Initiates copies across the PCIe bus from a user space buffer to card |
| 58 | * buffer to card memory. | 121 | * memory. When transfers are done using DMA, source/destination addresses |
| 122 | * and transfer length must follow the alignment requirements of the MIC | ||
| 123 | * DMA engine. | ||
| 59 | */ | 124 | */ |
| 60 | static int mic_virtio_copy_from_user(struct mic_vdev *mvdev, | 125 | static int mic_virtio_copy_from_user(struct mic_vdev *mvdev, void __user *ubuf, |
| 61 | void __user *ubuf, size_t len, u64 addr) | 126 | size_t len, u64 daddr, size_t dlen, |
| 127 | int vr_idx) | ||
| 62 | { | 128 | { |
| 129 | struct mic_device *mdev = mvdev->mdev; | ||
| 130 | void __iomem *dbuf = mdev->aper.va + daddr; | ||
| 131 | struct mic_vringh *mvr = &mvdev->mvr[vr_idx]; | ||
| 132 | size_t dma_alignment = 1 << mdev->dma_ch->device->copy_align; | ||
| 133 | size_t partlen; | ||
| 63 | int err; | 134 | int err; |
| 64 | void __iomem *dbuf = mvdev->mdev->aper.va + addr; | 135 | |
| 136 | if (daddr & (dma_alignment - 1)) { | ||
| 137 | mvdev->tx_dst_unaligned += len; | ||
| 138 | goto memcpy; | ||
| 139 | } else if (ALIGN(len, dma_alignment) > dlen) { | ||
| 140 | mvdev->tx_len_unaligned += len; | ||
| 141 | goto memcpy; | ||
| 142 | } | ||
| 143 | |||
| 144 | while (len) { | ||
| 145 | partlen = min_t(size_t, len, MIC_INT_DMA_BUF_SIZE); | ||
| 146 | |||
| 147 | if (copy_from_user(mvr->buf, ubuf, partlen)) { | ||
| 148 | err = -EFAULT; | ||
| 149 | goto err; | ||
| 150 | } | ||
| 151 | err = mic_sync_dma(mdev, daddr, mvr->buf_da, | ||
| 152 | ALIGN(partlen, dma_alignment)); | ||
| 153 | if (err) | ||
| 154 | goto err; | ||
| 155 | daddr += partlen; | ||
| 156 | ubuf += partlen; | ||
| 157 | dbuf += partlen; | ||
| 158 | mvdev->out_bytes_dma += partlen; | ||
| 159 | mvdev->out_bytes += partlen; | ||
| 160 | len -= partlen; | ||
| 161 | } | ||
| 162 | memcpy: | ||
| 65 | /* | 163 | /* |
| 66 | * We are copying to IO below and should ideally use something | 164 | * We are copying to IO below and should ideally use something |
| 67 | * like copy_from_user_toio(..) if it existed. | 165 | * like copy_from_user_toio(..) if it existed. |
| 68 | */ | 166 | */ |
| 69 | if (copy_from_user((void __force *)dbuf, ubuf, len)) { | 167 | if (copy_from_user((void __force *)dbuf, ubuf, len)) { |
| 70 | err = -EFAULT; | 168 | err = -EFAULT; |
| 71 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
| 72 | __func__, __LINE__, err); | ||
| 73 | goto err; | 169 | goto err; |
| 74 | } | 170 | } |
| 75 | mvdev->out_bytes += len; | 171 | mvdev->out_bytes += len; |
| 76 | err = 0; | 172 | return 0; |
| 77 | err: | 173 | err: |
| 174 | dev_err(mic_dev(mvdev), "%s %d err %d\n", __func__, __LINE__, err); | ||
| 78 | return err; | 175 | return err; |
| 79 | } | 176 | } |
| 80 | 177 | ||
| @@ -110,7 +207,8 @@ static inline u32 mic_vringh_iov_consumed(struct vringh_kiov *iov) | |||
| 110 | * way to override the VRINGH xfer(..) routines as of v3.10. | 207 | * way to override the VRINGH xfer(..) routines as of v3.10. |
| 111 | */ | 208 | */ |
| 112 | static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov, | 209 | static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov, |
| 113 | void __user *ubuf, size_t len, bool read, size_t *out_len) | 210 | void __user *ubuf, size_t len, bool read, int vr_idx, |
| 211 | size_t *out_len) | ||
| 114 | { | 212 | { |
| 115 | int ret = 0; | 213 | int ret = 0; |
| 116 | size_t partlen, tot_len = 0; | 214 | size_t partlen, tot_len = 0; |
| @@ -118,13 +216,15 @@ static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov, | |||
| 118 | while (len && iov->i < iov->used) { | 216 | while (len && iov->i < iov->used) { |
| 119 | partlen = min(iov->iov[iov->i].iov_len, len); | 217 | partlen = min(iov->iov[iov->i].iov_len, len); |
| 120 | if (read) | 218 | if (read) |
| 121 | ret = mic_virtio_copy_to_user(mvdev, | 219 | ret = mic_virtio_copy_to_user(mvdev, ubuf, partlen, |
| 122 | ubuf, partlen, | 220 | (u64)iov->iov[iov->i].iov_base, |
| 123 | (u64)iov->iov[iov->i].iov_base); | 221 | iov->iov[iov->i].iov_len, |
| 222 | vr_idx); | ||
| 124 | else | 223 | else |
| 125 | ret = mic_virtio_copy_from_user(mvdev, | 224 | ret = mic_virtio_copy_from_user(mvdev, ubuf, partlen, |
| 126 | ubuf, partlen, | 225 | (u64)iov->iov[iov->i].iov_base, |
| 127 | (u64)iov->iov[iov->i].iov_base); | 226 | iov->iov[iov->i].iov_len, |
| 227 | vr_idx); | ||
| 128 | if (ret) { | 228 | if (ret) { |
| 129 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | 229 | dev_err(mic_dev(mvdev), "%s %d err %d\n", |
| 130 | __func__, __LINE__, ret); | 230 | __func__, __LINE__, ret); |
| @@ -192,8 +292,8 @@ static int _mic_virtio_copy(struct mic_vdev *mvdev, | |||
| 192 | ubuf = iov.iov_base; | 292 | ubuf = iov.iov_base; |
| 193 | } | 293 | } |
| 194 | /* Issue all the read descriptors first */ | 294 | /* Issue all the read descriptors first */ |
| 195 | ret = mic_vringh_copy(mvdev, riov, ubuf, len, | 295 | ret = mic_vringh_copy(mvdev, riov, ubuf, len, MIC_VRINGH_READ, |
| 196 | MIC_VRINGH_READ, &out_len); | 296 | copy->vr_idx, &out_len); |
| 197 | if (ret) { | 297 | if (ret) { |
| 198 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | 298 | dev_err(mic_dev(mvdev), "%s %d err %d\n", |
| 199 | __func__, __LINE__, ret); | 299 | __func__, __LINE__, ret); |
| @@ -203,8 +303,8 @@ static int _mic_virtio_copy(struct mic_vdev *mvdev, | |||
| 203 | ubuf += out_len; | 303 | ubuf += out_len; |
| 204 | copy->out_len += out_len; | 304 | copy->out_len += out_len; |
| 205 | /* Issue the write descriptors next */ | 305 | /* Issue the write descriptors next */ |
| 206 | ret = mic_vringh_copy(mvdev, wiov, ubuf, len, | 306 | ret = mic_vringh_copy(mvdev, wiov, ubuf, len, !MIC_VRINGH_READ, |
| 207 | !MIC_VRINGH_READ, &out_len); | 307 | copy->vr_idx, &out_len); |
| 208 | if (ret) { | 308 | if (ret) { |
| 209 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | 309 | dev_err(mic_dev(mvdev), "%s %d err %d\n", |
| 210 | __func__, __LINE__, ret); | 310 | __func__, __LINE__, ret); |
| @@ -589,13 +689,19 @@ int mic_virtio_add_device(struct mic_vdev *mvdev, | |||
| 589 | dev_dbg(mdev->sdev->parent, | 689 | dev_dbg(mdev->sdev->parent, |
| 590 | "%s %d index %d va %p info %p vr_size 0x%x\n", | 690 | "%s %d index %d va %p info %p vr_size 0x%x\n", |
| 591 | __func__, __LINE__, i, vr->va, vr->info, vr_size); | 691 | __func__, __LINE__, i, vr->va, vr->info, vr_size); |
| 692 | mvr->buf = (void *)__get_free_pages(GFP_KERNEL, | ||
| 693 | get_order(MIC_INT_DMA_BUF_SIZE)); | ||
| 694 | mvr->buf_da = mic_map_single(mvdev->mdev, mvr->buf, | ||
| 695 | MIC_INT_DMA_BUF_SIZE); | ||
| 592 | } | 696 | } |
| 593 | 697 | ||
| 594 | snprintf(irqname, sizeof(irqname), "mic%dvirtio%d", mdev->id, | 698 | snprintf(irqname, sizeof(irqname), "mic%dvirtio%d", mdev->id, |
| 595 | mvdev->virtio_id); | 699 | mvdev->virtio_id); |
| 596 | mvdev->virtio_db = mic_next_db(mdev); | 700 | mvdev->virtio_db = mic_next_db(mdev); |
| 597 | mvdev->virtio_cookie = mic_request_irq(mdev, mic_virtio_intr_handler, | 701 | mvdev->virtio_cookie = mic_request_threaded_irq(mdev, |
| 598 | irqname, mvdev, mvdev->virtio_db, MIC_INTR_DB); | 702 | mic_virtio_intr_handler, |
| 703 | NULL, irqname, mvdev, | ||
| 704 | mvdev->virtio_db, MIC_INTR_DB); | ||
| 599 | if (IS_ERR(mvdev->virtio_cookie)) { | 705 | if (IS_ERR(mvdev->virtio_cookie)) { |
| 600 | ret = PTR_ERR(mvdev->virtio_cookie); | 706 | ret = PTR_ERR(mvdev->virtio_cookie); |
| 601 | dev_dbg(mdev->sdev->parent, "request irq failed\n"); | 707 | dev_dbg(mdev->sdev->parent, "request irq failed\n"); |
| @@ -671,6 +777,11 @@ skip_hot_remove: | |||
| 671 | vqconfig = mic_vq_config(mvdev->dd); | 777 | vqconfig = mic_vq_config(mvdev->dd); |
| 672 | for (i = 0; i < mvdev->dd->num_vq; i++) { | 778 | for (i = 0; i < mvdev->dd->num_vq; i++) { |
| 673 | struct mic_vringh *mvr = &mvdev->mvr[i]; | 779 | struct mic_vringh *mvr = &mvdev->mvr[i]; |
| 780 | |||
| 781 | mic_unmap_single(mvdev->mdev, mvr->buf_da, | ||
| 782 | MIC_INT_DMA_BUF_SIZE); | ||
| 783 | free_pages((unsigned long)mvr->buf, | ||
| 784 | get_order(MIC_INT_DMA_BUF_SIZE)); | ||
| 674 | vringh_kiov_cleanup(&mvr->riov); | 785 | vringh_kiov_cleanup(&mvr->riov); |
| 675 | vringh_kiov_cleanup(&mvr->wiov); | 786 | vringh_kiov_cleanup(&mvr->wiov); |
| 676 | mic_unmap_single(mdev, le64_to_cpu(vqconfig[i].address), | 787 | mic_unmap_single(mdev, le64_to_cpu(vqconfig[i].address), |
diff --git a/drivers/misc/mic/host/mic_virtio.h b/drivers/misc/mic/host/mic_virtio.h index 184f3c84805b..d574efb853d9 100644 --- a/drivers/misc/mic/host/mic_virtio.h +++ b/drivers/misc/mic/host/mic_virtio.h | |||
| @@ -46,18 +46,23 @@ | |||
| 46 | * @vrh: The host VRINGH used for accessing the card vrings. | 46 | * @vrh: The host VRINGH used for accessing the card vrings. |
| 47 | * @riov: The VRINGH read kernel IOV. | 47 | * @riov: The VRINGH read kernel IOV. |
| 48 | * @wiov: The VRINGH write kernel IOV. | 48 | * @wiov: The VRINGH write kernel IOV. |
| 49 | * @head: The VRINGH head index address passed to vringh_getdesc_kern(..). | ||
| 50 | * @vr_mutex: Mutex for synchronizing access to the VRING. | 49 | * @vr_mutex: Mutex for synchronizing access to the VRING. |
| 50 | * @buf: Temporary kernel buffer used to copy in/out data | ||
| 51 | * from/to the card via DMA. | ||
| 52 | * @buf_da: dma address of buf. | ||
| 51 | * @mvdev: Back pointer to MIC virtio device for vringh_notify(..). | 53 | * @mvdev: Back pointer to MIC virtio device for vringh_notify(..). |
| 54 | * @head: The VRINGH head index address passed to vringh_getdesc_kern(..). | ||
| 52 | */ | 55 | */ |
| 53 | struct mic_vringh { | 56 | struct mic_vringh { |
| 54 | struct mic_vring vring; | 57 | struct mic_vring vring; |
| 55 | struct vringh vrh; | 58 | struct vringh vrh; |
| 56 | struct vringh_kiov riov; | 59 | struct vringh_kiov riov; |
| 57 | struct vringh_kiov wiov; | 60 | struct vringh_kiov wiov; |
| 58 | u16 head; | ||
| 59 | struct mutex vr_mutex; | 61 | struct mutex vr_mutex; |
| 62 | void *buf; | ||
| 63 | dma_addr_t buf_da; | ||
| 60 | struct mic_vdev *mvdev; | 64 | struct mic_vdev *mvdev; |
| 65 | u16 head; | ||
| 61 | }; | 66 | }; |
| 62 | 67 | ||
| 63 | /** | 68 | /** |
| @@ -69,6 +74,14 @@ struct mic_vringh { | |||
| 69 | * @poll_wake - Used for waking up threads blocked in poll. | 74 | * @poll_wake - Used for waking up threads blocked in poll. |
| 70 | * @out_bytes - Debug stats for number of bytes copied from host to card. | 75 | * @out_bytes - Debug stats for number of bytes copied from host to card. |
| 71 | * @in_bytes - Debug stats for number of bytes copied from card to host. | 76 | * @in_bytes - Debug stats for number of bytes copied from card to host. |
| 77 | * @out_bytes_dma - Debug stats for number of bytes copied from host to card | ||
| 78 | * using DMA. | ||
| 79 | * @in_bytes_dma - Debug stats for number of bytes copied from card to host | ||
| 80 | * using DMA. | ||
| 81 | * @tx_len_unaligned - Debug stats for number of bytes copied to the card where | ||
| 82 | * the transfer length did not have the required DMA alignment. | ||
| 83 | * @tx_dst_unaligned - Debug stats for number of bytes copied where the | ||
| 84 | * destination address on the card did not have the required DMA alignment. | ||
| 72 | * @mvr - Store per VRING data structures. | 85 | * @mvr - Store per VRING data structures. |
| 73 | * @virtio_bh_work - Work struct used to schedule virtio bottom half handling. | 86 | * @virtio_bh_work - Work struct used to schedule virtio bottom half handling. |
| 74 | * @dd - Virtio device descriptor. | 87 | * @dd - Virtio device descriptor. |
| @@ -84,6 +97,10 @@ struct mic_vdev { | |||
| 84 | int poll_wake; | 97 | int poll_wake; |
| 85 | unsigned long out_bytes; | 98 | unsigned long out_bytes; |
| 86 | unsigned long in_bytes; | 99 | unsigned long in_bytes; |
| 100 | unsigned long out_bytes_dma; | ||
| 101 | unsigned long in_bytes_dma; | ||
| 102 | unsigned long tx_len_unaligned; | ||
| 103 | unsigned long tx_dst_unaligned; | ||
| 87 | struct mic_vringh mvr[MIC_MAX_VRINGS]; | 104 | struct mic_vringh mvr[MIC_MAX_VRINGS]; |
| 88 | struct work_struct virtio_bh_work; | 105 | struct work_struct virtio_bh_work; |
| 89 | struct mic_device_desc *dd; | 106 | struct mic_device_desc *dd; |
diff --git a/drivers/misc/mic/host/mic_x100.c b/drivers/misc/mic/host/mic_x100.c index 5562fdd3ef4e..b7a21e11dcdf 100644 --- a/drivers/misc/mic/host/mic_x100.c +++ b/drivers/misc/mic/host/mic_x100.c | |||
| @@ -549,6 +549,13 @@ struct mic_smpt_ops mic_x100_smpt_ops = { | |||
| 549 | .set = mic_x100_smpt_set, | 549 | .set = mic_x100_smpt_set, |
| 550 | }; | 550 | }; |
| 551 | 551 | ||
| 552 | static bool mic_x100_dma_filter(struct dma_chan *chan, void *param) | ||
| 553 | { | ||
| 554 | if (chan->device->dev->parent == (struct device *)param) | ||
| 555 | return true; | ||
| 556 | return false; | ||
| 557 | } | ||
| 558 | |||
| 552 | struct mic_hw_ops mic_x100_ops = { | 559 | struct mic_hw_ops mic_x100_ops = { |
| 553 | .aper_bar = MIC_X100_APER_BAR, | 560 | .aper_bar = MIC_X100_APER_BAR, |
| 554 | .mmio_bar = MIC_X100_MMIO_BAR, | 561 | .mmio_bar = MIC_X100_MMIO_BAR, |
| @@ -563,6 +570,7 @@ struct mic_hw_ops mic_x100_ops = { | |||
| 563 | .send_firmware_intr = mic_x100_send_firmware_intr, | 570 | .send_firmware_intr = mic_x100_send_firmware_intr, |
| 564 | .load_mic_fw = mic_x100_load_firmware, | 571 | .load_mic_fw = mic_x100_load_firmware, |
| 565 | .get_postcode = mic_x100_get_postcode, | 572 | .get_postcode = mic_x100_get_postcode, |
| 573 | .dma_filter = mic_x100_dma_filter, | ||
| 566 | }; | 574 | }; |
| 567 | 575 | ||
| 568 | struct mic_hw_intr_ops mic_x100_intr_ops = { | 576 | struct mic_hw_intr_ops mic_x100_intr_ops = { |
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 3fac67a5204c..557f9782c53c 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c | |||
| @@ -544,7 +544,8 @@ xpnet_init(void) | |||
| 544 | * use ether_setup() to init the majority of our device | 544 | * use ether_setup() to init the majority of our device |
| 545 | * structure and then override the necessary pieces. | 545 | * structure and then override the necessary pieces. |
| 546 | */ | 546 | */ |
| 547 | xpnet_device = alloc_netdev(0, XPNET_DEVICE_NAME, ether_setup); | 547 | xpnet_device = alloc_netdev(0, XPNET_DEVICE_NAME, NET_NAME_UNKNOWN, |
| 548 | ether_setup); | ||
| 548 | if (xpnet_device == NULL) { | 549 | if (xpnet_device == NULL) { |
| 549 | kfree(xpnet_broadcast_partitions); | 550 | kfree(xpnet_broadcast_partitions); |
| 550 | return -ENOMEM; | 551 | return -ENOMEM; |
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 9d3dbb28734b..21c2337bad68 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c | |||
| @@ -244,7 +244,8 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name) | |||
| 244 | if (version & 0x8000) | 244 | if (version & 0x8000) |
| 245 | maj_ver |= 0x0008; | 245 | maj_ver |= 0x0008; |
| 246 | 246 | ||
| 247 | sprintf(bts_scr_name, "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver); | 247 | sprintf(bts_scr_name, "ti-connectivity/TIInit_%d.%d.%d.bts", |
| 248 | chip, maj_ver, min_ver); | ||
| 248 | 249 | ||
| 249 | /* to be accessed later via sysfs entry */ | 250 | /* to be accessed later via sysfs entry */ |
| 250 | kim_gdata->version.full = version; | 251 | kim_gdata->version.full = version; |
| @@ -287,7 +288,7 @@ static long download_firmware(struct kim_data_s *kim_gdata) | |||
| 287 | long len = 0; | 288 | long len = 0; |
| 288 | unsigned char *ptr = NULL; | 289 | unsigned char *ptr = NULL; |
| 289 | unsigned char *action_ptr = NULL; | 290 | unsigned char *action_ptr = NULL; |
| 290 | unsigned char bts_scr_name[30] = { 0 }; /* 30 char long bts scr name? */ | 291 | unsigned char bts_scr_name[40] = { 0 }; /* 40 char long bts scr name? */ |
| 291 | int wr_room_space; | 292 | int wr_room_space; |
| 292 | int cmd_size; | 293 | int cmd_size; |
| 293 | unsigned long timeout; | 294 | unsigned long timeout; |
| @@ -778,7 +779,7 @@ static int kim_probe(struct platform_device *pdev) | |||
| 778 | pr_info("sysfs entries created\n"); | 779 | pr_info("sysfs entries created\n"); |
| 779 | 780 | ||
| 780 | kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); | 781 | kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); |
| 781 | if (IS_ERR(kim_debugfs_dir)) { | 782 | if (!kim_debugfs_dir) { |
| 782 | pr_err(" debugfs entries creation failed "); | 783 | pr_err(" debugfs entries creation failed "); |
| 783 | err = -EIO; | 784 | err = -EIO; |
| 784 | goto err_debugfs_dir; | 785 | goto err_debugfs_dir; |
| @@ -788,7 +789,6 @@ static int kim_probe(struct platform_device *pdev) | |||
| 788 | kim_gdata, &version_debugfs_fops); | 789 | kim_gdata, &version_debugfs_fops); |
| 789 | debugfs_create_file("protocols", S_IRUGO, kim_debugfs_dir, | 790 | debugfs_create_file("protocols", S_IRUGO, kim_debugfs_dir, |
| 790 | kim_gdata, &list_debugfs_fops); | 791 | kim_gdata, &list_debugfs_fops); |
| 791 | pr_info(" debugfs entries created "); | ||
| 792 | return 0; | 792 | return 0; |
| 793 | 793 | ||
| 794 | err_debugfs_dir: | 794 | err_debugfs_dir: |
diff --git a/drivers/misc/vexpress-syscfg.c b/drivers/misc/vexpress-syscfg.c index 3250fc1df0aa..b3a812384a6f 100644 --- a/drivers/misc/vexpress-syscfg.c +++ b/drivers/misc/vexpress-syscfg.c | |||
| @@ -130,7 +130,7 @@ static int vexpress_syscfg_write(void *context, unsigned int index, | |||
| 130 | return vexpress_syscfg_exec(func, index, true, &val); | 130 | return vexpress_syscfg_exec(func, index, true, &val); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | struct regmap_config vexpress_syscfg_regmap_config = { | 133 | static struct regmap_config vexpress_syscfg_regmap_config = { |
| 134 | .lock = vexpress_config_lock, | 134 | .lock = vexpress_config_lock, |
| 135 | .unlock = vexpress_config_unlock, | 135 | .unlock = vexpress_config_unlock, |
| 136 | .reg_bits = 32, | 136 | .reg_bits = 32, |
| @@ -276,7 +276,7 @@ int vexpress_syscfg_device_register(struct platform_device *pdev) | |||
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | 278 | ||
| 279 | int vexpress_syscfg_probe(struct platform_device *pdev) | 279 | static int vexpress_syscfg_probe(struct platform_device *pdev) |
| 280 | { | 280 | { |
| 281 | struct vexpress_syscfg *syscfg; | 281 | struct vexpress_syscfg *syscfg; |
| 282 | struct resource *res; | 282 | struct resource *res; |
diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index e0d5017785e5..248399a881af 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c | |||
| @@ -748,7 +748,7 @@ static void vmci_guest_remove_device(struct pci_dev *pdev) | |||
| 748 | /* The rest are managed resources and will be freed by PCI core */ | 748 | /* The rest are managed resources and will be freed by PCI core */ |
| 749 | } | 749 | } |
| 750 | 750 | ||
| 751 | static DEFINE_PCI_DEVICE_TABLE(vmci_ids) = { | 751 | static const struct pci_device_id vmci_ids[] = { |
| 752 | { PCI_DEVICE(PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_VMCI), }, | 752 | { PCI_DEVICE(PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_VMCI), }, |
| 753 | { 0 }, | 753 | { 0 }, |
| 754 | }; | 754 | }; |
