mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-05 05:36:46 +07:00
aec8e88c94
When we get an interrupt from the hardware, the first thing the driver does is tell the device to mask off the interrupt line. Unfortunately this involves a SPI transaction in interrupt context. Some (most?) SPI controllers perform the transfer asynchronously and try to sleep. This is bad, and triggers a BUG(). So, work around this by using adding a hwbus hook for the cw1200 driver core to call. The cw1200_spi driver translates this into irq_disable()/irq_enable() calls instead, which can safely be called in interrupt context. Apparently the platforms I used to develop the cw1200_spi driver used synchronous spi_sync() implementations, which is why this didn't surface until now. Many thanks to Dave Sizeburns for the inital bug report and his services as a tester. Signed-off-by: Solomon Peachy <pizza@shaftnet.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
35 lines
1.1 KiB
C
35 lines
1.1 KiB
C
/*
|
|
* Common hwbus abstraction layer interface for cw1200 wireless driver
|
|
*
|
|
* Copyright (c) 2010, ST-Ericsson
|
|
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#ifndef CW1200_HWBUS_H
|
|
#define CW1200_HWBUS_H
|
|
|
|
struct hwbus_priv;
|
|
|
|
void cw1200_irq_handler(struct cw1200_common *priv);
|
|
|
|
/* This MUST be wrapped with hwbus_ops->lock/unlock! */
|
|
int __cw1200_irq_enable(struct cw1200_common *priv, int enable);
|
|
|
|
struct hwbus_ops {
|
|
int (*hwbus_memcpy_fromio)(struct hwbus_priv *self, unsigned int addr,
|
|
void *dst, int count);
|
|
int (*hwbus_memcpy_toio)(struct hwbus_priv *self, unsigned int addr,
|
|
const void *src, int count);
|
|
void (*lock)(struct hwbus_priv *self);
|
|
void (*unlock)(struct hwbus_priv *self);
|
|
size_t (*align_size)(struct hwbus_priv *self, size_t size);
|
|
int (*power_mgmt)(struct hwbus_priv *self, bool suspend);
|
|
int (*irq_enable)(struct hwbus_priv *self, int enable);
|
|
};
|
|
|
|
#endif /* CW1200_HWBUS_H */
|