Commit 8448cefe authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hsi-for-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi

Pull HSI updates from Sebastian Reichel:

 - proper runtime pm support for omap-ssi and ssi-protocol

 - misc fixes

* tag 'hsi-for-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi: (24 commits)
  HSI: omap_ssi: drop pm_runtime_irq_safe
  HSI: omap_ssi_port: use rpm autosuspend API
  HSI: omap_ssi: call msg->complete() from process context
  HSI: omap_ssi_port: ensure clocks are kept enabled during transfer
  HSI: omap_ssi_port: replace pm_runtime_put_sync with non-sync variant
  HSI: omap_ssi_port: avoid calling runtime_pm_*_sync inside spinlock
  HSI: omap_ssi_port: avoid pm_runtime_get_sync in ssi_start_dma and ssi_start_pio
  HSI: omap_ssi_port: switch to threaded pio irq
  HSI: omap_ssi_core: remove pm_runtime_get_sync call from tasklet
  HSI: omap_ssi_core: use pm_runtime_put instead of pm_runtime_put_sync
  HSI: omap_ssi_port: prepare start_tx/stop_tx for blocking pm_runtime calls
  HSI: core: switch port event notifier from atomic to blocking
  HSI: omap_ssi_port: replace wkin_cken with atomic bitmap operations
  HSI: omap_ssi: convert cawake irq handler to thread
  HSI: ssi_protocol: fix ssip_xmit invocation
  HSI: ssi_protocol: replace spin_lock with spin_lock_bh
  HSI: ssi_protocol: avoid ssi_waketest call with held spinlock
  HSI: omap_ssi: do not reset module
  HSI: omap_ssi_port: remove useless newline
  hsi: Only descend into hsi directory when CONFIG_HSI is set
  ...
parents 818e607b 9c99e5e5
...@@ -484,7 +484,7 @@ X!Ilib/fonts/fonts.c ...@@ -484,7 +484,7 @@ X!Ilib/fonts/fonts.c
</para> </para>
!Iinclude/linux/hsi/hsi.h !Iinclude/linux/hsi/hsi.h
!Edrivers/hsi/hsi.c !Edrivers/hsi/hsi_core.c
</chapter> </chapter>
<chapter id="pwm"> <chapter id="pwm">
......
...@@ -78,7 +78,7 @@ obj-$(CONFIG_TARGET_CORE) += target/ ...@@ -78,7 +78,7 @@ obj-$(CONFIG_TARGET_CORE) += target/
obj-$(CONFIG_MTD) += mtd/ obj-$(CONFIG_MTD) += mtd/
obj-$(CONFIG_SPI) += spi/ obj-$(CONFIG_SPI) += spi/
obj-$(CONFIG_SPMI) += spmi/ obj-$(CONFIG_SPMI) += spmi/
obj-y += hsi/ obj-$(CONFIG_HSI) += hsi/
obj-y += net/ obj-y += net/
obj-$(CONFIG_ATM) += atm/ obj-$(CONFIG_ATM) += atm/
obj-$(CONFIG_FUSION) += message/ obj-$(CONFIG_FUSION) += message/
......
# #
# Makefile for HSI # Makefile for HSI
# #
obj-$(CONFIG_HSI_BOARDINFO) += hsi_boardinfo.o
obj-$(CONFIG_HSI) += hsi.o obj-$(CONFIG_HSI) += hsi.o
hsi-objs := hsi_core.o
hsi-$(CONFIG_HSI_BOARDINFO) += hsi_boardinfo.o
obj-y += controllers/ obj-y += controllers/
obj-y += clients/ obj-y += clients/
...@@ -444,8 +444,8 @@ static void cs_hsi_read_on_control_complete(struct hsi_msg *msg) ...@@ -444,8 +444,8 @@ static void cs_hsi_read_on_control_complete(struct hsi_msg *msg)
hi->control_state &= ~SSI_CHANNEL_STATE_READING; hi->control_state &= ~SSI_CHANNEL_STATE_READING;
if (msg->status == HSI_STATUS_ERROR) { if (msg->status == HSI_STATUS_ERROR) {
dev_err(&hi->cl->device, "Control RX error detected\n"); dev_err(&hi->cl->device, "Control RX error detected\n");
cs_hsi_control_read_error(hi, msg);
spin_unlock(&hi->lock); spin_unlock(&hi->lock);
cs_hsi_control_read_error(hi, msg);
goto out; goto out;
} }
dev_dbg(&hi->cl->device, "Read on control: %08X\n", cmd); dev_dbg(&hi->cl->device, "Read on control: %08X\n", cmd);
...@@ -1275,7 +1275,7 @@ static int cs_char_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -1275,7 +1275,7 @@ static int cs_char_mmap(struct file *file, struct vm_area_struct *vma)
if (vma->vm_end < vma->vm_start) if (vma->vm_end < vma->vm_start)
return -EINVAL; return -EINVAL;
if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) != 1) if (vma_pages(vma) != 1)
return -EINVAL; return -EINVAL;
vma->vm_flags |= VM_IO | VM_DONTDUMP | VM_DONTEXPAND; vma->vm_flags |= VM_IO | VM_DONTDUMP | VM_DONTEXPAND;
......
...@@ -88,6 +88,8 @@ void ssi_waketest(struct hsi_client *cl, unsigned int enable); ...@@ -88,6 +88,8 @@ void ssi_waketest(struct hsi_client *cl, unsigned int enable);
#define SSIP_READY_CMD SSIP_CMD(SSIP_READY, 0) #define SSIP_READY_CMD SSIP_CMD(SSIP_READY, 0)
#define SSIP_SWBREAK_CMD SSIP_CMD(SSIP_SW_BREAK, 0) #define SSIP_SWBREAK_CMD SSIP_CMD(SSIP_SW_BREAK, 0)
#define SSIP_WAKETEST_FLAG 0
/* Main state machine states */ /* Main state machine states */
enum { enum {
INIT, INIT,
...@@ -116,7 +118,7 @@ enum { ...@@ -116,7 +118,7 @@ enum {
* @main_state: Main state machine * @main_state: Main state machine
* @send_state: TX state machine * @send_state: TX state machine
* @recv_state: RX state machine * @recv_state: RX state machine
* @waketest: Flag to follow wake line test * @flags: Flags, currently only used to follow wake line test
* @rxid: RX data id * @rxid: RX data id
* @txid: TX data id * @txid: TX data id
* @txqueue_len: TX queue length * @txqueue_len: TX queue length
...@@ -137,7 +139,7 @@ struct ssi_protocol { ...@@ -137,7 +139,7 @@ struct ssi_protocol {
unsigned int main_state; unsigned int main_state;
unsigned int send_state; unsigned int send_state;
unsigned int recv_state; unsigned int recv_state;
unsigned int waketest:1; unsigned long flags;
u8 rxid; u8 rxid;
u8 txid; u8 txid;
unsigned int txqueue_len; unsigned int txqueue_len;
...@@ -148,6 +150,7 @@ struct ssi_protocol { ...@@ -148,6 +150,7 @@ struct ssi_protocol {
struct net_device *netdev; struct net_device *netdev;
struct list_head txqueue; struct list_head txqueue;
struct list_head cmdqueue; struct list_head cmdqueue;
struct work_struct work;
struct hsi_client *cl; struct hsi_client *cl;
struct list_head link; struct list_head link;
atomic_t tx_usecnt; atomic_t tx_usecnt;
...@@ -405,15 +408,17 @@ static void ssip_reset(struct hsi_client *cl) ...@@ -405,15 +408,17 @@ static void ssip_reset(struct hsi_client *cl)
spin_lock_bh(&ssi->lock); spin_lock_bh(&ssi->lock);
if (ssi->send_state != SEND_IDLE) if (ssi->send_state != SEND_IDLE)
hsi_stop_tx(cl); hsi_stop_tx(cl);
if (ssi->waketest) spin_unlock_bh(&ssi->lock);
ssi_waketest(cl, 0); if (test_and_clear_bit(SSIP_WAKETEST_FLAG, &ssi->flags))
ssi_waketest(cl, 0); /* FIXME: To be removed */
spin_lock_bh(&ssi->lock);
del_timer(&ssi->rx_wd); del_timer(&ssi->rx_wd);
del_timer(&ssi->tx_wd); del_timer(&ssi->tx_wd);
del_timer(&ssi->keep_alive); del_timer(&ssi->keep_alive);
ssi->main_state = 0; ssi->main_state = 0;
ssi->send_state = 0; ssi->send_state = 0;
ssi->recv_state = 0; ssi->recv_state = 0;
ssi->waketest = 0; ssi->flags = 0;
ssi->rxid = 0; ssi->rxid = 0;
ssi->txid = 0; ssi->txid = 0;
list_for_each_safe(head, tmp, &ssi->txqueue) { list_for_each_safe(head, tmp, &ssi->txqueue) {
...@@ -437,7 +442,8 @@ static void ssip_dump_state(struct hsi_client *cl) ...@@ -437,7 +442,8 @@ static void ssip_dump_state(struct hsi_client *cl)
dev_err(&cl->device, "Send state: %d\n", ssi->send_state); dev_err(&cl->device, "Send state: %d\n", ssi->send_state);
dev_err(&cl->device, "CMT %s\n", (ssi->main_state == ACTIVE) ? dev_err(&cl->device, "CMT %s\n", (ssi->main_state == ACTIVE) ?
"Online" : "Offline"); "Online" : "Offline");
dev_err(&cl->device, "Wake test %d\n", ssi->waketest); dev_err(&cl->device, "Wake test %d\n",
test_bit(SSIP_WAKETEST_FLAG, &ssi->flags));
dev_err(&cl->device, "Data RX id: %d\n", ssi->rxid); dev_err(&cl->device, "Data RX id: %d\n", ssi->rxid);
dev_err(&cl->device, "Data TX id: %d\n", ssi->txid); dev_err(&cl->device, "Data TX id: %d\n", ssi->txid);
...@@ -515,17 +521,17 @@ static void ssip_start_rx(struct hsi_client *cl) ...@@ -515,17 +521,17 @@ static void ssip_start_rx(struct hsi_client *cl)
dev_dbg(&cl->device, "RX start M(%d) R(%d)\n", ssi->main_state, dev_dbg(&cl->device, "RX start M(%d) R(%d)\n", ssi->main_state,
ssi->recv_state); ssi->recv_state);
spin_lock(&ssi->lock); spin_lock_bh(&ssi->lock);
/* /*
* We can have two UP events in a row due to a short low * We can have two UP events in a row due to a short low
* high transition. Therefore we need to ignore the sencond UP event. * high transition. Therefore we need to ignore the sencond UP event.
*/ */
if ((ssi->main_state != ACTIVE) || (ssi->recv_state == RECV_READY)) { if ((ssi->main_state != ACTIVE) || (ssi->recv_state == RECV_READY)) {
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
return; return;
} }
ssip_set_rxstate(ssi, RECV_READY); ssip_set_rxstate(ssi, RECV_READY);
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
msg = ssip_claim_cmd(ssi); msg = ssip_claim_cmd(ssi);
ssip_set_cmd(msg, SSIP_READY_CMD); ssip_set_cmd(msg, SSIP_READY_CMD);
...@@ -539,10 +545,10 @@ static void ssip_stop_rx(struct hsi_client *cl) ...@@ -539,10 +545,10 @@ static void ssip_stop_rx(struct hsi_client *cl)
struct ssi_protocol *ssi = hsi_client_drvdata(cl); struct ssi_protocol *ssi = hsi_client_drvdata(cl);
dev_dbg(&cl->device, "RX stop M(%d)\n", ssi->main_state); dev_dbg(&cl->device, "RX stop M(%d)\n", ssi->main_state);
spin_lock(&ssi->lock); spin_lock_bh(&ssi->lock);
if (likely(ssi->main_state == ACTIVE)) if (likely(ssi->main_state == ACTIVE))
ssip_set_rxstate(ssi, RECV_IDLE); ssip_set_rxstate(ssi, RECV_IDLE);
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
} }
static void ssip_free_strans(struct hsi_msg *msg) static void ssip_free_strans(struct hsi_msg *msg)
...@@ -559,9 +565,9 @@ static void ssip_strans_complete(struct hsi_msg *msg) ...@@ -559,9 +565,9 @@ static void ssip_strans_complete(struct hsi_msg *msg)
data = msg->context; data = msg->context;
ssip_release_cmd(msg); ssip_release_cmd(msg);
spin_lock(&ssi->lock); spin_lock_bh(&ssi->lock);
ssip_set_txstate(ssi, SENDING); ssip_set_txstate(ssi, SENDING);
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
hsi_async_write(cl, data); hsi_async_write(cl, data);
} }
...@@ -666,15 +672,17 @@ static void ssip_rx_bootinforeq(struct hsi_client *cl, u32 cmd) ...@@ -666,15 +672,17 @@ static void ssip_rx_bootinforeq(struct hsi_client *cl, u32 cmd)
/* Fall through */ /* Fall through */
case INIT: case INIT:
case HANDSHAKE: case HANDSHAKE:
spin_lock(&ssi->lock); spin_lock_bh(&ssi->lock);
ssi->main_state = HANDSHAKE; ssi->main_state = HANDSHAKE;
if (!ssi->waketest) { spin_unlock_bh(&ssi->lock);
ssi->waketest = 1;
if (!test_and_set_bit(SSIP_WAKETEST_FLAG, &ssi->flags))
ssi_waketest(cl, 1); /* FIXME: To be removed */ ssi_waketest(cl, 1); /* FIXME: To be removed */
}
spin_lock_bh(&ssi->lock);
/* Start boot handshake watchdog */ /* Start boot handshake watchdog */
mod_timer(&ssi->tx_wd, jiffies + msecs_to_jiffies(SSIP_WDTOUT)); mod_timer(&ssi->tx_wd, jiffies + msecs_to_jiffies(SSIP_WDTOUT));
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
dev_dbg(&cl->device, "Send BOOTINFO_RESP\n"); dev_dbg(&cl->device, "Send BOOTINFO_RESP\n");
if (SSIP_DATA_VERSION(cmd) != SSIP_LOCAL_VERID) if (SSIP_DATA_VERSION(cmd) != SSIP_LOCAL_VERID)
dev_warn(&cl->device, "boot info req verid mismatch\n"); dev_warn(&cl->device, "boot info req verid mismatch\n");
...@@ -696,14 +704,14 @@ static void ssip_rx_bootinforesp(struct hsi_client *cl, u32 cmd) ...@@ -696,14 +704,14 @@ static void ssip_rx_bootinforesp(struct hsi_client *cl, u32 cmd)
if (SSIP_DATA_VERSION(cmd) != SSIP_LOCAL_VERID) if (SSIP_DATA_VERSION(cmd) != SSIP_LOCAL_VERID)
dev_warn(&cl->device, "boot info resp verid mismatch\n"); dev_warn(&cl->device, "boot info resp verid mismatch\n");
spin_lock(&ssi->lock); spin_lock_bh(&ssi->lock);
if (ssi->main_state != ACTIVE) if (ssi->main_state != ACTIVE)
/* Use tx_wd as a boot watchdog in non ACTIVE state */ /* Use tx_wd as a boot watchdog in non ACTIVE state */
mod_timer(&ssi->tx_wd, jiffies + msecs_to_jiffies(SSIP_WDTOUT)); mod_timer(&ssi->tx_wd, jiffies + msecs_to_jiffies(SSIP_WDTOUT));
else else
dev_dbg(&cl->device, "boot info resp ignored M(%d)\n", dev_dbg(&cl->device, "boot info resp ignored M(%d)\n",
ssi->main_state); ssi->main_state);
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
} }
static void ssip_rx_waketest(struct hsi_client *cl, u32 cmd) static void ssip_rx_waketest(struct hsi_client *cl, u32 cmd)
...@@ -711,20 +719,22 @@ static void ssip_rx_waketest(struct hsi_client *cl, u32 cmd) ...@@ -711,20 +719,22 @@ static void ssip_rx_waketest(struct hsi_client *cl, u32 cmd)
struct ssi_protocol *ssi = hsi_client_drvdata(cl); struct ssi_protocol *ssi = hsi_client_drvdata(cl);
unsigned int wkres = SSIP_PAYLOAD(cmd); unsigned int wkres = SSIP_PAYLOAD(cmd);
spin_lock(&ssi->lock); spin_lock_bh(&ssi->lock);
if (ssi->main_state != HANDSHAKE) { if (ssi->main_state != HANDSHAKE) {
dev_dbg(&cl->device, "wake lines test ignored M(%d)\n", dev_dbg(&cl->device, "wake lines test ignored M(%d)\n",
ssi->main_state); ssi->main_state);
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
return; return;
} }
if (ssi->waketest) { spin_unlock_bh(&ssi->lock);
ssi->waketest = 0;
if (test_and_clear_bit(SSIP_WAKETEST_FLAG, &ssi->flags))
ssi_waketest(cl, 0); /* FIXME: To be removed */ ssi_waketest(cl, 0); /* FIXME: To be removed */
}
spin_lock_bh(&ssi->lock);
ssi->main_state = ACTIVE; ssi->main_state = ACTIVE;
del_timer(&ssi->tx_wd); /* Stop boot handshake timer */ del_timer(&ssi->tx_wd); /* Stop boot handshake timer */
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
dev_notice(&cl->device, "WAKELINES TEST %s\n", dev_notice(&cl->device, "WAKELINES TEST %s\n",
wkres & SSIP_WAKETEST_FAILED ? "FAILED" : "OK"); wkres & SSIP_WAKETEST_FAILED ? "FAILED" : "OK");
...@@ -741,20 +751,20 @@ static void ssip_rx_ready(struct hsi_client *cl) ...@@ -741,20 +751,20 @@ static void ssip_rx_ready(struct hsi_client *cl)
{ {
struct ssi_protocol *ssi = hsi_client_drvdata(cl); struct ssi_protocol *ssi = hsi_client_drvdata(cl);
spin_lock(&ssi->lock); spin_lock_bh(&ssi->lock);
if (unlikely(ssi->main_state != ACTIVE)) { if (unlikely(ssi->main_state != ACTIVE)) {
dev_dbg(&cl->device, "READY on wrong state: S(%d) M(%d)\n", dev_dbg(&cl->device, "READY on wrong state: S(%d) M(%d)\n",
ssi->send_state, ssi->main_state); ssi->send_state, ssi->main_state);
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
return; return;
} }
if (ssi->send_state != WAIT4READY) { if (ssi->send_state != WAIT4READY) {
dev_dbg(&cl->device, "Ignore spurious READY command\n"); dev_dbg(&cl->device, "Ignore spurious READY command\n");
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
return; return;
} }
ssip_set_txstate(ssi, SEND_READY); ssip_set_txstate(ssi, SEND_READY);
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
ssip_xmit(cl); ssip_xmit(cl);
} }
...@@ -766,22 +776,22 @@ static void ssip_rx_strans(struct hsi_client *cl, u32 cmd) ...@@ -766,22 +776,22 @@ static void ssip_rx_strans(struct hsi_client *cl, u32 cmd)
int len = SSIP_PDU_LENGTH(cmd); int len = SSIP_PDU_LENGTH(cmd);
dev_dbg(&cl->device, "RX strans: %d frames\n", len); dev_dbg(&cl->device, "RX strans: %d frames\n", len);
spin_lock(&ssi->lock); spin_lock_bh(&ssi->lock);
if (unlikely(ssi->main_state != ACTIVE)) { if (unlikely(ssi->main_state != ACTIVE)) {
dev_err(&cl->device, "START TRANS wrong state: S(%d) M(%d)\n", dev_err(&cl->device, "START TRANS wrong state: S(%d) M(%d)\n",
ssi->send_state, ssi->main_state); ssi->send_state, ssi->main_state);
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
return; return;
} }
ssip_set_rxstate(ssi, RECEIVING); ssip_set_rxstate(ssi, RECEIVING);
if (unlikely(SSIP_MSG_ID(cmd) != ssi->rxid)) { if (unlikely(SSIP_MSG_ID(cmd) != ssi->rxid)) {
dev_err(&cl->device, "START TRANS id %d expected %d\n", dev_err(&cl->device, "START TRANS id %d expected %d\n",
SSIP_MSG_ID(cmd), ssi->rxid); SSIP_MSG_ID(cmd), ssi->rxid);
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
goto out1; goto out1;
} }
ssi->rxid++; ssi->rxid++;
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
skb = netdev_alloc_skb(ssi->netdev, len * 4); skb = netdev_alloc_skb(ssi->netdev, len * 4);
if (unlikely(!skb)) { if (unlikely(!skb)) {
dev_err(&cl->device, "No memory for rx skb\n"); dev_err(&cl->device, "No memory for rx skb\n");
...@@ -849,7 +859,7 @@ static void ssip_swbreak_complete(struct hsi_msg *msg) ...@@ -849,7 +859,7 @@ static void ssip_swbreak_complete(struct hsi_msg *msg)
struct ssi_protocol *ssi = hsi_client_drvdata(cl); struct ssi_protocol *ssi = hsi_client_drvdata(cl);
ssip_release_cmd(msg); ssip_release_cmd(msg);
spin_lock(&ssi->lock); spin_lock_bh(&ssi->lock);
if (list_empty(&ssi->txqueue)) { if (list_empty(&ssi->txqueue)) {
if (atomic_read(&ssi->tx_usecnt)) { if (atomic_read(&ssi->tx_usecnt)) {
ssip_set_txstate(ssi, SEND_READY); ssip_set_txstate(ssi, SEND_READY);
...@@ -857,9 +867,9 @@ static void ssip_swbreak_complete(struct hsi_msg *msg) ...@@ -857,9 +867,9 @@ static void ssip_swbreak_complete(struct hsi_msg *msg)
ssip_set_txstate(ssi, SEND_IDLE); ssip_set_txstate(ssi, SEND_IDLE);
hsi_stop_tx(cl); hsi_stop_tx(cl);
} }
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
} else { } else {
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
ssip_xmit(cl); ssip_xmit(cl);
} }
netif_wake_queue(ssi->netdev); netif_wake_queue(ssi->netdev);
...@@ -876,17 +886,17 @@ static void ssip_tx_data_complete(struct hsi_msg *msg) ...@@ -876,17 +886,17 @@ static void ssip_tx_data_complete(struct hsi_msg *msg)
ssip_error(cl); ssip_error(cl);
goto out; goto out;
} }
spin_lock(&ssi->lock); spin_lock_bh(&ssi->lock);
if (list_empty(&ssi->txqueue)) { if (list_empty(&ssi->txqueue)) {
ssip_set_txstate(ssi, SENDING_SWBREAK); ssip_set_txstate(ssi, SENDING_SWBREAK);
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
cmsg = ssip_claim_cmd(ssi); cmsg = ssip_claim_cmd(ssi);
ssip_set_cmd(cmsg, SSIP_SWBREAK_CMD); ssip_set_cmd(cmsg, SSIP_SWBREAK_CMD);
cmsg->complete = ssip_swbreak_complete; cmsg->complete = ssip_swbreak_complete;
dev_dbg(&cl->device, "Send SWBREAK\n"); dev_dbg(&cl->device, "Send SWBREAK\n");
hsi_async_write(cl, cmsg); hsi_async_write(cl, cmsg);
} else { } else {
spin_unlock(&ssi->lock); spin_unlock_bh(&ssi->lock);
ssip_xmit(cl); ssip_xmit(cl);
} }
out: out:
...@@ -926,11 +936,11 @@ static int ssip_pn_open(struct net_device *dev) ...@@ -926,11 +936,11 @@ static int ssip_pn_open(struct net_device *dev)
} }
dev_dbg(&cl->device, "Configuring SSI port\n"); dev_dbg(&cl->device, "Configuring SSI port\n");
hsi_setup(cl); hsi_setup(cl);
spin_lock_bh(&ssi->lock);
if (!ssi->waketest) { if (!test_and_set_bit(SSIP_WAKETEST_FLAG, &ssi->flags))
ssi->waketest = 1;
ssi_waketest(cl, 1); /* FIXME: To be removed */ ssi_waketest(cl, 1); /* FIXME: To be removed */
}
spin_lock_bh(&ssi->lock);
ssi->main_state = HANDSHAKE; ssi->main_state = HANDSHAKE;
spin_unlock_bh(&ssi->lock); spin_unlock_bh(&ssi->lock);
...@@ -959,6 +969,15 @@ static int ssip_pn_set_mtu(struct net_device *dev, int new_mtu) ...@@ -959,6 +969,15 @@ static int ssip_pn_set_mtu(struct net_device *dev, int new_mtu)
return 0; return 0;
} }
static void ssip_xmit_work(struct work_struct *work)
{
struct ssi_protocol *ssi =
container_of(work, struct ssi_protocol, work);
struct hsi_client *cl = ssi->cl;
ssip_xmit(cl);
}
static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev) static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct hsi_client *cl = to_hsi_client(dev->dev.parent); struct hsi_client *cl = to_hsi_client(dev->dev.parent);
...@@ -1011,7 +1030,7 @@ static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1011,7 +1030,7 @@ static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev)
dev_dbg(&cl->device, "Start TX on SEND READY qlen %d\n", dev_dbg(&cl->device, "Start TX on SEND READY qlen %d\n",
ssi->txqueue_len); ssi->txqueue_len);
spin_unlock_bh(&ssi->lock); spin_unlock_bh(&ssi->lock);
ssip_xmit(cl); schedule_work(&ssi->work);
} else { } else {
spin_unlock_bh(&ssi->lock); spin_unlock_bh(&ssi->lock);
} }
...@@ -1088,6 +1107,7 @@ static int ssi_protocol_probe(struct device *dev) ...@@ -1088,6 +1107,7 @@ static int ssi_protocol_probe(struct device *dev)
atomic_set(&ssi->tx_usecnt, 0); atomic_set(&ssi->tx_usecnt, 0);
hsi_client_set_drvdata(cl, ssi); hsi_client_set_drvdata(cl, ssi);
ssi->cl = cl; ssi->cl = cl;
INIT_WORK(&ssi->work, ssip_xmit_work);
ssi->channel_id_cmd = hsi_get_channel_id_by_name(cl, "mcsaab-control"); ssi->channel_id_cmd = hsi_get_channel_id_by_name(cl, "mcsaab-control");
if (ssi->channel_id_cmd < 0) { if (ssi->channel_id_cmd < 0) {
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#define SSI_MAX_GDD_LCH 8 #define SSI_MAX_GDD_LCH 8
#define SSI_BYTES_TO_FRAMES(x) ((((x) - 1) >> 2) + 1) #define SSI_BYTES_TO_FRAMES(x) ((((x) - 1) >> 2) + 1)
#define SSI_WAKE_EN 0
/** /**
* struct omap_ssm_ctx - OMAP synchronous serial module (TX/RX) context * struct omap_ssm_ctx - OMAP synchronous serial module (TX/RX) context
* @mode: Bit transmission mode * @mode: Bit transmission mode
...@@ -71,13 +73,14 @@ struct omap_ssm_ctx { ...@@ -71,13 +73,14 @@ struct omap_ssm_ctx {
* @txqueue: TX message queues * @txqueue: TX message queues
* @rxqueue: RX message queues * @rxqueue: RX message queues
* @brkqueue: Queue of incoming HWBREAK requests (FRAME mode) * @brkqueue: Queue of incoming HWBREAK requests (FRAME mode)
* @errqueue: Queue for failed messages
* @errqueue_work: Delayed Work for failed messages
* @irq: IRQ number * @irq: IRQ number
* @wake_irq: IRQ number for incoming wake line (-1 if none) * @wake_irq: IRQ number for incoming wake line (-1 if none)
* @wake_gpio: GPIO number for incoming wake line (-1 if none) * @wake_gpio: GPIO number for incoming wake line (-1 if none)
* @pio_tasklet: Bottom half for PIO transfers and events * @flags: flags to keep track of states
* @wake_tasklet: Bottom half for incoming wake events
* @wkin_cken: Keep track of clock references due to the incoming wake line
* @wk_refcount: Reference count for output wake line * @wk_refcount: Reference count for output wake line
* @work: worker for starting TX
* @sys_mpu_enable: Context for the interrupt enable register for irq 0 * @sys_mpu_enable: Context for the interrupt enable register for irq 0
* @sst: Context for the synchronous serial transmitter * @sst: Context for the synchronous serial transmitter
* @ssr: Context for the synchronous serial receiver * @ssr: Context for the synchronous serial receiver
...@@ -95,14 +98,15 @@ struct omap_ssi_port { ...@@ -95,14 +98,15 @@ struct omap_ssi_port {
struct list_head txqueue[SSI_MAX_CHANNELS]; struct list_head txqueue[SSI_MAX_CHANNELS];
struct list_head rxqueue[SSI_MAX_CHANNELS]; struct list_head rxqueue[SSI_MAX_CHANNELS];
struct list_head brkqueue; struct list_head brkqueue;
struct list_head errqueue;
struct delayed_work errqueue_work;
unsigned int irq; unsigned int irq;
int wake_irq; int wake_irq;
struct gpio_desc *wake_gpio; struct gpio_desc *wake_gpio;
struct tasklet_struct pio_tasklet;
struct tasklet_struct wake_tasklet;
bool wktest:1; /* FIXME: HACK to be removed */ bool wktest:1; /* FIXME: HACK to be removed */
bool wkin_cken:1; /* Workaround */ unsigned long flags;
unsigned int wk_refcount; unsigned int wk_refcount;
struct work_struct work;
/* OMAP SSI port context */ /* OMAP SSI port context */
u32 sys_mpu_enable; /* We use only one irq */ u32 sys_mpu_enable; /* We use only one irq */
struct omap_ssm_ctx sst; struct omap_ssm_ctx sst;
...@@ -138,7 +142,6 @@ struct gdd_trn { ...@@ -138,7 +142,6 @@ struct gdd_trn {
* @fck_rate: clock rate * @fck_rate: clock rate
* @loss_count: To follow if we need to restore context or not * @loss_count: To follow if we need to restore context or not
* @max_speed: Maximum TX speed (Kb/s) set by the clients. * @max_speed: Maximum TX speed (Kb/s) set by the clients.
* @sysconfig: SSI controller saved context
* @gdd_gcr: SSI GDD saved context * @gdd_gcr: SSI GDD saved context
* @get_loss: Pointer to omap_pm_get_dev_context_loss_count, if any * @get_loss: Pointer to omap_pm_get_dev_context_loss_count, if any
* @port: Array of pointers of the ports of the controller * @port: Array of pointers of the ports of the controller
...@@ -158,7 +161,6 @@ struct omap_ssi_controller { ...@@ -158,7 +161,6 @@ struct omap_ssi_controller {
u32 loss_count; u32 loss_count;
u32 max_speed; u32 max_speed;
/* OMAP SSI Controller context */ /* OMAP SSI Controller context */
u32 sysconfig;
u32 gdd_gcr; u32 gdd_gcr;
int (*get_loss)(struct device *dev); int (*get_loss)(struct device *dev);
struct omap_ssi_port **port; struct omap_ssi_port **port;
......
...@@ -58,7 +58,7 @@ static int ssi_debug_show(struct seq_file *m, void *p __maybe_unused) ...@@ -58,7 +58,7 @@ static int ssi_debug_show(struct seq_file *m, void *p __maybe_unused)
seq_printf(m, "REVISION\t: 0x%08x\n", readl(sys + SSI_REVISION_REG)); seq_printf(m, "REVISION\t: 0x%08x\n", readl(sys + SSI_REVISION_REG));
seq_printf(m, "SYSCONFIG\t: 0x%08x\n", readl(sys + SSI_SYSCONFIG_REG)); seq_printf(m, "SYSCONFIG\t: 0x%08x\n", readl(sys + SSI_SYSCONFIG_REG));
seq_printf(m, "SYSSTATUS\t: 0x%08x\n", readl(sys + SSI_SYSSTATUS_REG)); seq_printf(m, "SYSSTATUS\t: 0x%08x\n", readl(sys + SSI_SYSSTATUS_REG));
pm_runtime_put_sync(ssi->device.parent); pm_runtime_put(ssi->device.parent);
return 0; return 0;
} }
...@@ -112,7 +112,7 @@ static int ssi_debug_gdd_show(struct seq_file *m, void *p __maybe_unused) ...@@ -112,7 +112,7 @@ static int ssi_debug_gdd_show(struct seq_file *m, void *p __maybe_unused)
readw(gdd + SSI_GDD_CLNK_CTRL_REG(lch))); readw(gdd + SSI_GDD_CLNK_CTRL_REG(lch)));
} }
pm_runtime_put_sync(ssi->device.parent); pm_runtime_put(ssi->device.parent);
return 0; return 0;
} }
...@@ -193,7 +193,7 @@ void ssi_waketest(struct hsi_client *cl, unsigned int enable) ...@@ -193,7 +193,7 @@ void ssi_waketest(struct hsi_client *cl, unsigned int enable)
} else { } else {
writel_relaxed(SSI_WAKE(0), writel_relaxed(SSI_WAKE(0),
omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num)); omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));
pm_runtime_put_sync(ssi->device.parent); pm_runtime_put(ssi->device.parent);
} }
} }
EXPORT_SYMBOL_GPL(ssi_waketest); EXPORT_SYMBOL_GPL(ssi_waketest);
...@@ -217,7 +217,7 @@ static void ssi_gdd_complete(struct hsi_controller *ssi, unsigned int lch) ...@@ -217,7 +217,7 @@ static void ssi_gdd_complete(struct hsi_controller *ssi, unsigned int lch)
if (msg->ttype == HSI_MSG_READ) { if (msg->ttype == HSI_MSG_READ) {
dir = DMA_FROM_DEVICE; dir = DMA_FROM_DEVICE;
val = SSI_DATAAVAILABLE(msg->channel); val = SSI_DATAAVAILABLE(msg->channel);
pm_runtime_put_sync(ssi->device.parent); pm_runtime_put(omap_port->pdev);
} else { } else {
dir = DMA_TO_DEVICE; dir = DMA_TO_DEVICE;
val = SSI_DATAACCEPT(msg->channel); val = SSI_DATAACCEPT(msg->channel);
...@@ -235,7 +235,9 @@ static void ssi_gdd_complete(struct hsi_controller *ssi, unsigned int lch) ...@@ -235,7 +235,9 @@ static void ssi_gdd_complete(struct hsi_controller *ssi, unsigned int lch)
spin_lock(&omap_port->lock); spin_lock(&omap_port->lock);
list_del(&msg->link); /* Dequeue msg */ list_del(&msg->link); /* Dequeue msg */
spin_unlock(&omap_port->lock); spin_unlock(&omap_port->lock);
msg->complete(msg);
list_add_tail(&msg->link, &omap_port->errqueue);
schedule_delayed_work(&omap_port->errqueue_work, 0);
return; return;
} }
spin_lock(&omap_port->lock); spin_lock(&omap_port->lock);
...@@ -255,7 +257,13 @@ static void ssi_gdd_tasklet(unsigned long dev) ...@@ -255,7 +257,13 @@ static void ssi_gdd_tasklet(unsigned long dev)
unsigned int lch; unsigned int lch;
u32 status_reg; u32 status_reg;
pm_runtime_get_sync(ssi->device.parent); pm_runtime_get(ssi->device.parent);
if (!pm_runtime_active(ssi->device.parent)) {
dev_warn(ssi->device.parent, "ssi_gdd_tasklet called without runtime PM!\n");
pm_runtime_put(ssi->device.parent);
return;
}
status_reg = readl(sys + SSI_GDD_MPU_IRQ_STATUS_REG); status_reg = readl(sys + SSI_GDD_MPU_IRQ_STATUS_REG);
for (lch = 0; lch < SSI_MAX_GDD_LCH; lch++) { for (lch = 0; lch < SSI_MAX_GDD_LCH; lch++) {
...@@ -265,7 +273,7 @@ static void ssi_gdd_tasklet(unsigned long dev) ...@@ -265,7 +273,7 @@ static void ssi_gdd_tasklet(unsigned long dev)
writel_relaxed(status_reg, sys + SSI_GDD_MPU_IRQ_STATUS_REG); writel_relaxed(status_reg, sys + SSI_GDD_MPU_IRQ_STATUS_REG);
status_reg = readl(sys + SSI_GDD_MPU_IRQ_STATUS_REG); status_reg = readl(sys + SSI_GDD_MPU_IRQ_STATUS_REG);
pm_runtime_put_sync(ssi->device.parent); pm_runtime_put(ssi->device.parent);
if (status_reg) if (status_reg)
tasklet_hi_schedule(&omap_ssi->gdd_tasklet); tasklet_hi_schedule(&omap_ssi->gdd_tasklet);
...@@ -312,7 +320,7 @@ static int ssi_clk_event(struct notifier_block *nb, unsigned long event, ...@@ -312,7 +320,7 @@ static int ssi_clk_event(struct notifier_block *nb, unsigned long event,
continue; continue;
/* Workaround for SWBREAK + CAwake down race in CMT */ /* Workaround for SWBREAK + CAwake down race in CMT */
tasklet_disable(&omap_port->wake_tasklet); disable_irq(omap_port->wake_irq);
/* stop all ssi communication */ /* stop all ssi communication */
pinctrl_pm_select_idle_state(omap_port->pdev); pinctrl_pm_select_idle_state(omap_port->pdev);
...@@ -338,7 +346,7 @@ static int ssi_clk_event(struct notifier_block *nb, unsigned long event, ...@@ -338,7 +346,7 @@ static int ssi_clk_event(struct notifier_block *nb, unsigned long event,
/* resume ssi communication */ /* resume ssi communication */
pinctrl_pm_select_default_state(omap_port->pdev); pinctrl_pm_select_default_state(omap_port->pdev);
tasklet_enable(&omap_port->wake_tasklet); enable_irq(omap_port->wake_irq);
} }
break; break;
...@@ -452,8 +460,6 @@ static int ssi_add_controller(struct hsi_controller *ssi, ...@@ -452,8 +460,6 @@ static int ssi_add_controller(struct hsi_controller *ssi,
static int ssi_hw_init(struct hsi_controller *ssi) static int ssi_hw_init(struct hsi_controller *ssi)
{ {
struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi); struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
unsigned int i;
u32 val;
int err; int err;
err = pm_runtime_get_sync(ssi->device.parent); err = pm_runtime_get_sync(ssi->device.parent);
...@@ -461,27 +467,12 @@ static int ssi_hw_init(struct hsi_controller *ssi) ...@@ -461,27 +467,12 @@ static int ssi_hw_init(struct hsi_controller *ssi)
dev_err(&ssi->device, "runtime PM failed %d\n", err); dev_err(&ssi->device, "runtime PM failed %d\n", err);
return err; return err;
} }
/* Reseting SSI controller */
writel_relaxed(SSI_SOFTRESET, omap_ssi->sys + SSI_SYSCONFIG_REG);
val = readl(omap_ssi->sys + SSI_SYSSTATUS_REG);
for (i = 0; ((i < 20) && !(val & SSI_RESETDONE)); i++) {
msleep(20);
val = readl(omap_ssi->sys + SSI_SYSSTATUS_REG);
}
if (!(val & SSI_RESETDONE)) {
dev_err(&ssi->device, "SSI HW reset failed\n");
pm_runtime_put_sync(ssi->device.parent);
return -EIO;
}
/* Reseting GDD */ /* Reseting GDD */
writel_relaxed(SSI_SWRESET, omap_ssi->gdd + SSI_GDD_GRST_REG); writel_relaxed(SSI_SWRESET, omap_ssi->gdd + SSI_GDD_GRST_REG);
/* Get FCK rate in KHz */ /* Get FCK rate in KHz */
omap_ssi->fck_rate = DIV_ROUND_CLOSEST(ssi_get_clk_rate(ssi), 1000); omap_ssi->fck_rate = DIV_ROUND_CLOSEST(ssi_get_clk_rate(ssi), 1000);
dev_dbg(&ssi->device, "SSI fck rate %lu KHz\n", omap_ssi->fck_rate); dev_dbg(&ssi->device, "SSI fck rate %lu KHz\n", omap_ssi->fck_rate);
/* Set default PM settings */
val = SSI_AUTOIDLE | SSI_SIDLEMODE_SMART | SSI_MIDLEMODE_SMART;
writel_relaxed(val, omap_ssi->sys + SSI_SYSCONFIG_REG);
omap_ssi->sysconfig = val;
writel_relaxed(SSI_CLK_AUTOGATING_ON, omap_ssi->sys + SSI_GDD_GCR_REG); writel_relaxed(SSI_CLK_AUTOGATING_ON, omap_ssi->sys + SSI_GDD_GCR_REG);
omap_ssi->gdd_gcr = SSI_CLK_AUTOGATING_ON; omap_ssi->gdd_gcr = SSI_CLK_AUTOGATING_ON;
pm_runtime_put_sync(ssi->device.parent); pm_runtime_put_sync(ssi->device.parent);
...@@ -552,7 +543,6 @@ static int ssi_probe(struct platform_device *pd) ...@@ -552,7 +543,6 @@ static int ssi_probe(struct platform_device *pd)
if (err < 0) if (err < 0)
goto out1; goto out1;
pm_runtime_irq_safe(&pd->dev);
pm_runtime_enable(&pd->dev); pm_runtime_enable(&pd->dev);
err = ssi_hw_init(ssi); err = ssi_hw_init(ssi);
......
This diff is collapsed.
...@@ -90,19 +90,19 @@ struct hsi_client *hsi_new_client(struct hsi_port *port, ...@@ -90,19 +90,19 @@ struct hsi_client *hsi_new_client(struct hsi_port *port,
cl->tx_cfg = info->tx_cfg; cl->tx_cfg = info->tx_cfg;
if (cl->tx_cfg.channels) { if (cl->tx_cfg.channels) {
size = cl->tx_cfg.num_channels * sizeof(*cl->tx_cfg.channels); size = cl->tx_cfg.num_channels * sizeof(*cl->tx_cfg.channels);
cl->tx_cfg.channels = kzalloc(size , GFP_KERNEL); cl->tx_cfg.channels = kmemdup(info->tx_cfg.channels, size,
GFP_KERNEL);
if (!cl->tx_cfg.channels) if (!cl->tx_cfg.channels)
goto err_tx; goto err_tx;
memcpy(cl->tx_cfg.channels, info->tx_cfg.channels, size);
} }
cl->rx_cfg = info->rx_cfg; cl->rx_cfg = info->rx_cfg;
if (cl->rx_cfg.channels) { if (cl->rx_cfg.channels) {
size = cl->rx_cfg.num_channels * sizeof(*cl->rx_cfg.channels); size = cl->rx_cfg.num_channels * sizeof(*cl->rx_cfg.channels);
cl->rx_cfg.channels = kzalloc(size , GFP_KERNEL); cl->rx_cfg.channels = kmemdup(info->rx_cfg.channels, size,
GFP_KERNEL);
if (!cl->rx_cfg.channels) if (!cl->rx_cfg.channels)
goto err_rx; goto err_rx;
memcpy(cl->rx_cfg.channels, info->rx_cfg.channels, size);
} }
cl->device.bus = &hsi_bus_type; cl->device.bus = &hsi_bus_type;
...@@ -507,7 +507,7 @@ struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags) ...@@ -507,7 +507,7 @@ struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags)
port[i]->stop_tx = hsi_dummy_cl; port[i]->stop_tx = hsi_dummy_cl;
port[i]->release = hsi_dummy_cl; port[i]->release = hsi_dummy_cl;
mutex_init(&port[i]->lock); mutex_init(&port[i]->lock);
ATOMIC_INIT_NOTIFIER_HEAD(&port[i]->n_head); BLOCKING_INIT_NOTIFIER_HEAD(&port[i]->n_head);
dev_set_name(&port[i]->device, "port%d", i); dev_set_name(&port[i]->device, "port%d", i);
hsi->port[i]->device.release = hsi_port_release; hsi->port[i]->device.release = hsi_port_release;
device_initialize(&hsi->port[i]->device); device_initialize(&hsi->port[i]->device);
...@@ -689,7 +689,7 @@ int hsi_register_port_event(struct hsi_client *cl, ...@@ -689,7 +689,7 @@ int hsi_register_port_event(struct hsi_client *cl,
cl->ehandler = handler; cl->ehandler = handler;
cl->nb.notifier_call = hsi_event_notifier_call; cl->nb.notifier_call = hsi_event_notifier_call;
return atomic_notifier_chain_register(&port->n_head, &cl->nb); return blocking_notifier_chain_register(&port->n_head, &cl->nb);
} }
EXPORT_SYMBOL_GPL(hsi_register_port_event); EXPORT_SYMBOL_GPL(hsi_register_port_event);
...@@ -709,7 +709,7 @@ int hsi_unregister_port_event(struct hsi_client *cl) ...@@ -709,7 +709,7 @@ int hsi_unregister_port_event(struct hsi_client *cl)
WARN_ON(!hsi_port_claimed(cl)); WARN_ON(!hsi_port_claimed(cl));
err = atomic_notifier_chain_unregister(&port->n_head, &cl->nb); err = blocking_notifier_chain_unregister(&port->n_head, &cl->nb);
if (!err) if (!err)
cl->ehandler = NULL; cl->ehandler = NULL;
...@@ -734,7 +734,7 @@ EXPORT_SYMBOL_GPL(hsi_unregister_port_event); ...@@ -734,7 +734,7 @@ EXPORT_SYMBOL_GPL(hsi_unregister_port_event);
*/ */
int hsi_event(struct hsi_port *port, unsigned long event) int hsi_event(struct hsi_port *port, unsigned long event)
{ {
return atomic_notifier_call_chain(&port->n_head, event, NULL); return blocking_notifier_call_chain(&port->n_head, event, NULL);
} }
EXPORT_SYMBOL_GPL(hsi_event); EXPORT_SYMBOL_GPL(hsi_event);
......
...@@ -246,7 +246,7 @@ struct hsi_port { ...@@ -246,7 +246,7 @@ struct hsi_port {
int (*stop_tx)(struct hsi_client *cl); int (*stop_tx)(struct hsi_client *cl);
int (*release)(struct hsi_client *cl); int (*release)(struct hsi_client *cl);
/* private */ /* private */
struct atomic_notifier_head n_head; struct blocking_notifier_head n_head;
}; };
#define to_hsi_port(dev) container_of(dev, struct hsi_port, device) #define to_hsi_port(dev) container_of(dev, struct hsi_port, device)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment