caif: SPI-driver bugfix - incorrect padding.
Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f2527ec436
commit
2c24a5d1b4
|
@ -33,6 +33,9 @@ MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
|
MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
|
||||||
MODULE_DESCRIPTION("CAIF SPI driver");
|
MODULE_DESCRIPTION("CAIF SPI driver");
|
||||||
|
|
||||||
|
/* Returns the number of padding bytes for alignment. */
|
||||||
|
#define PAD_POW2(x, pow) ((((x)&((pow)-1))==0) ? 0 : (((pow)-((x)&((pow)-1)))))
|
||||||
|
|
||||||
static int spi_loop;
|
static int spi_loop;
|
||||||
module_param(spi_loop, bool, S_IRUGO);
|
module_param(spi_loop, bool, S_IRUGO);
|
||||||
MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
|
MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
|
||||||
|
@ -41,7 +44,10 @@ MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
|
||||||
module_param(spi_frm_align, int, S_IRUGO);
|
module_param(spi_frm_align, int, S_IRUGO);
|
||||||
MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
|
MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
|
||||||
|
|
||||||
/* SPI padding options. */
|
/*
|
||||||
|
* SPI padding options.
|
||||||
|
* Warning: must be a base of 2 (& operation used) and can not be zero !
|
||||||
|
*/
|
||||||
module_param(spi_up_head_align, int, S_IRUGO);
|
module_param(spi_up_head_align, int, S_IRUGO);
|
||||||
MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
|
MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
|
||||||
|
|
||||||
|
@ -240,15 +246,13 @@ static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
|
||||||
static const struct file_operations dbgfs_state_fops = {
|
static const struct file_operations dbgfs_state_fops = {
|
||||||
.open = dbgfs_open,
|
.open = dbgfs_open,
|
||||||
.read = dbgfs_state,
|
.read = dbgfs_state,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE
|
||||||
.llseek = default_llseek,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations dbgfs_frame_fops = {
|
static const struct file_operations dbgfs_frame_fops = {
|
||||||
.open = dbgfs_open,
|
.open = dbgfs_open,
|
||||||
.read = dbgfs_frame,
|
.read = dbgfs_frame,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE
|
||||||
.llseek = default_llseek,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void dev_debugfs_add(struct cfspi *cfspi)
|
static inline void dev_debugfs_add(struct cfspi *cfspi)
|
||||||
|
@ -337,6 +341,9 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
|
||||||
u8 *dst = buf;
|
u8 *dst = buf;
|
||||||
caif_assert(buf);
|
caif_assert(buf);
|
||||||
|
|
||||||
|
if (cfspi->slave && !cfspi->slave_talked)
|
||||||
|
cfspi->slave_talked = true;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct caif_payload_info *info;
|
struct caif_payload_info *info;
|
||||||
|
@ -357,8 +364,8 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
|
||||||
* Compute head offset i.e. number of bytes to add to
|
* Compute head offset i.e. number of bytes to add to
|
||||||
* get the start of the payload aligned.
|
* get the start of the payload aligned.
|
||||||
*/
|
*/
|
||||||
if (spi_up_head_align) {
|
if (spi_up_head_align > 1) {
|
||||||
spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
|
spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
|
||||||
*dst = (u8)(spad - 1);
|
*dst = (u8)(spad - 1);
|
||||||
dst += spad;
|
dst += spad;
|
||||||
}
|
}
|
||||||
|
@ -373,7 +380,7 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
|
||||||
* Compute tail offset i.e. number of bytes to add to
|
* Compute tail offset i.e. number of bytes to add to
|
||||||
* get the complete CAIF frame aligned.
|
* get the complete CAIF frame aligned.
|
||||||
*/
|
*/
|
||||||
epad = (skb->len + spad) & spi_up_tail_align;
|
epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
|
||||||
dst += epad;
|
dst += epad;
|
||||||
|
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
|
@ -417,14 +424,14 @@ int cfspi_xmitlen(struct cfspi *cfspi)
|
||||||
* Compute head offset i.e. number of bytes to add to
|
* Compute head offset i.e. number of bytes to add to
|
||||||
* get the start of the payload aligned.
|
* get the start of the payload aligned.
|
||||||
*/
|
*/
|
||||||
if (spi_up_head_align)
|
if (spi_up_head_align > 1)
|
||||||
spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
|
spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute tail offset i.e. number of bytes to add to
|
* Compute tail offset i.e. number of bytes to add to
|
||||||
* get the complete CAIF frame aligned.
|
* get the complete CAIF frame aligned.
|
||||||
*/
|
*/
|
||||||
epad = (skb->len + spad) & spi_up_tail_align;
|
epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
|
||||||
|
|
||||||
if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
|
if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
|
||||||
skb_queue_tail(&cfspi->chead, skb);
|
skb_queue_tail(&cfspi->chead, skb);
|
||||||
|
@ -433,6 +440,7 @@ int cfspi_xmitlen(struct cfspi *cfspi)
|
||||||
} else {
|
} else {
|
||||||
/* Put back packet. */
|
/* Put back packet. */
|
||||||
skb_queue_head(&cfspi->qhead, skb);
|
skb_queue_head(&cfspi->qhead, skb);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} while (pkts <= CAIF_MAX_SPI_PKTS);
|
} while (pkts <= CAIF_MAX_SPI_PKTS);
|
||||||
|
|
||||||
|
@ -453,6 +461,15 @@ static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
|
||||||
{
|
{
|
||||||
struct cfspi *cfspi = (struct cfspi *)ifc->priv;
|
struct cfspi *cfspi = (struct cfspi *)ifc->priv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The slave device is the master on the link. Interrupts before the
|
||||||
|
* slave has transmitted are considered spurious.
|
||||||
|
*/
|
||||||
|
if (cfspi->slave && !cfspi->slave_talked) {
|
||||||
|
printk(KERN_WARNING "CFSPI: Spurious SS interrupt.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!in_interrupt())
|
if (!in_interrupt())
|
||||||
spin_lock(&cfspi->lock);
|
spin_lock(&cfspi->lock);
|
||||||
if (assert) {
|
if (assert) {
|
||||||
|
@ -465,7 +482,8 @@ static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
|
||||||
spin_unlock(&cfspi->lock);
|
spin_unlock(&cfspi->lock);
|
||||||
|
|
||||||
/* Wake up the xfer thread. */
|
/* Wake up the xfer thread. */
|
||||||
wake_up_interruptible(&cfspi->wait);
|
if (assert)
|
||||||
|
wake_up_interruptible(&cfspi->wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
|
static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
|
||||||
|
@ -523,7 +541,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
|
||||||
* Compute head offset i.e. number of bytes added to
|
* Compute head offset i.e. number of bytes added to
|
||||||
* get the start of the payload aligned.
|
* get the start of the payload aligned.
|
||||||
*/
|
*/
|
||||||
if (spi_down_head_align) {
|
if (spi_down_head_align > 1) {
|
||||||
spad = 1 + *src;
|
spad = 1 + *src;
|
||||||
src += spad;
|
src += spad;
|
||||||
}
|
}
|
||||||
|
@ -564,7 +582,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
|
||||||
* Compute tail offset i.e. number of bytes added to
|
* Compute tail offset i.e. number of bytes added to
|
||||||
* get the complete CAIF frame aligned.
|
* get the complete CAIF frame aligned.
|
||||||
*/
|
*/
|
||||||
epad = (pkt_len + spad) & spi_down_tail_align;
|
epad = PAD_POW2((pkt_len + spad), spi_down_tail_align);
|
||||||
src += epad;
|
src += epad;
|
||||||
} while ((src - buf) < len);
|
} while ((src - buf) < len);
|
||||||
|
|
||||||
|
@ -625,11 +643,20 @@ int cfspi_spi_probe(struct platform_device *pdev)
|
||||||
cfspi->ndev = ndev;
|
cfspi->ndev = ndev;
|
||||||
cfspi->pdev = pdev;
|
cfspi->pdev = pdev;
|
||||||
|
|
||||||
/* Set flow info */
|
/* Set flow info. */
|
||||||
cfspi->flow_off_sent = 0;
|
cfspi->flow_off_sent = 0;
|
||||||
cfspi->qd_low_mark = LOW_WATER_MARK;
|
cfspi->qd_low_mark = LOW_WATER_MARK;
|
||||||
cfspi->qd_high_mark = HIGH_WATER_MARK;
|
cfspi->qd_high_mark = HIGH_WATER_MARK;
|
||||||
|
|
||||||
|
/* Set slave info. */
|
||||||
|
if (!strncmp(cfspi_spi_driver.driver.name, "cfspi_sspi", 10)) {
|
||||||
|
cfspi->slave = true;
|
||||||
|
cfspi->slave_talked = false;
|
||||||
|
} else {
|
||||||
|
cfspi->slave = false;
|
||||||
|
cfspi->slave_talked = false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Assign the SPI device. */
|
/* Assign the SPI device. */
|
||||||
cfspi->dev = dev;
|
cfspi->dev = dev;
|
||||||
/* Assign the device ifc to this SPI interface. */
|
/* Assign the device ifc to this SPI interface. */
|
||||||
|
|
|
@ -36,10 +36,15 @@ static inline int forward_to_spi_cmd(struct cfspi *cfspi)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int spi_frm_align = 2;
|
int spi_frm_align = 2;
|
||||||
int spi_up_head_align = 1;
|
|
||||||
int spi_up_tail_align;
|
/*
|
||||||
int spi_down_head_align = 3;
|
* SPI padding options.
|
||||||
int spi_down_tail_align = 1;
|
* Warning: must be a base of 2 (& operation used) and can not be zero !
|
||||||
|
*/
|
||||||
|
int spi_up_head_align = 1 << 1;
|
||||||
|
int spi_up_tail_align = 1 << 0;
|
||||||
|
int spi_down_head_align = 1 << 2;
|
||||||
|
int spi_down_tail_align = 1 << 1;
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
static inline void debugfs_store_prev(struct cfspi *cfspi)
|
static inline void debugfs_store_prev(struct cfspi *cfspi)
|
||||||
|
|
|
@ -121,6 +121,8 @@ struct cfspi {
|
||||||
wait_queue_head_t wait;
|
wait_queue_head_t wait;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
bool flow_stop;
|
bool flow_stop;
|
||||||
|
bool slave;
|
||||||
|
bool slave_talked;
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
enum cfspi_state dbg_state;
|
enum cfspi_state dbg_state;
|
||||||
u16 pcmd;
|
u16 pcmd;
|
||||||
|
|
Loading…
Reference in New Issue