summaryrefslogtreecommitdiff
path: root/arch/sparc/kernel
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2017-06-10 14:11:12 -0700
committerDavid S. Miller <davem@davemloft.net>2017-06-10 14:11:12 -0700
commit0abdfaf4a95435c0197603a262149019ca2f448d (patch)
treef195fabfa9406d05f8578b0532136e14311bedc3 /arch/sparc/kernel
parent95c4629d92d15d10e5f7c55bfb72583f96a91374 (diff)
parent93ec4a828e6d777a61f497bc6e0cf9239fde35c7 (diff)
Merge branch 'sparc64-LDC-changes-for-porting-VCC-driver-into-upstream-kernel'
Jag Raman says: ==================== sparc64: LDC changes for porting VCC driver into upstream kernel This series of patches is part of an effort to add VCC (Virtual Console Concentrator) support to Linux. VCC enables the virtualization of serial console on SPARC processors. VCC provides access to the guest domain's serial console. VCC depends on some core functionalities in the linux kernel for SPARC. The functionalities include LDC (Logical Domain Channels), MDESC (Machine Descriptor) and VIO (Virtual IO protocol). In order for VCC to be enabled, it requires that these core functionalities support them. This series of patches adds LDC support to enable VCC on Linux. It is the first batch of changes to enable VCC. This version 4 of the series addresses the following changes suggested by Dave Miller Patch 1/5: Modifies ldc_print/__ldc_print to print caller name. Fixes indentation of wrapped lines. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r--arch/sparc/kernel/ldc.c141
1 files changed, 98 insertions, 43 deletions
diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c
index 59d503866431..97a5743b04e2 100644
--- a/arch/sparc/kernel/ldc.c
+++ b/arch/sparc/kernel/ldc.c
@@ -34,7 +34,6 @@
static char version[] =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
-#define LDC_PACKET_SIZE 64
/* Packet header layout for unreliable and reliable mode frames.
* When in RAW mode, packets are simply straight 64-byte payloads
@@ -178,6 +177,8 @@ do { if (lp->cfg.debug & LDC_DEBUG_##TYPE) \
printk(KERN_INFO PFX "ID[%lu] " f, lp->id, ## a); \
} while (0)
+#define LDC_ABORT(lp) ldc_abort((lp), __func__)
+
static const char *state_to_str(u8 state)
{
switch (state) {
@@ -196,15 +197,6 @@ static const char *state_to_str(u8 state)
}
}
-static void ldc_set_state(struct ldc_channel *lp, u8 state)
-{
- ldcdbg(STATE, "STATE (%s) --> (%s)\n",
- state_to_str(lp->state),
- state_to_str(state));
-
- lp->state = state;
-}
-
static unsigned long __advance(unsigned long off, unsigned long num_entries)
{
off += LDC_PACKET_SIZE;
@@ -516,11 +508,12 @@ static int send_data_nack(struct ldc_channel *lp, struct ldc_packet *data_pkt)
return err;
}
-static int ldc_abort(struct ldc_channel *lp)
+static int ldc_abort(struct ldc_channel *lp, const char *msg)
{
unsigned long hv_err;
- ldcdbg(STATE, "ABORT\n");
+ ldcdbg(STATE, "ABORT[%s]\n", msg);
+ ldc_print(lp);
/* We report but do not act upon the hypervisor errors because
* there really isn't much we can do if they fail at this point.
@@ -605,7 +598,7 @@ static int process_ver_info(struct ldc_channel *lp, struct ldc_version *vp)
}
}
if (err)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
return 0;
}
@@ -618,13 +611,13 @@ static int process_ver_ack(struct ldc_channel *lp, struct ldc_version *vp)
if (lp->hs_state == LDC_HS_GOTVERS) {
if (lp->ver.major != vp->major ||
lp->ver.minor != vp->minor)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
} else {
lp->ver = *vp;
lp->hs_state = LDC_HS_GOTVERS;
}
if (send_rts(lp))
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
return 0;
}
@@ -635,17 +628,17 @@ static int process_ver_nack(struct ldc_channel *lp, struct ldc_version *vp)
unsigned long new_tail;
if (vp->major == 0 && vp->minor == 0)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
vap = find_by_major(vp->major);
if (!vap)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
p = handshake_compose_ctrl(lp, LDC_INFO, LDC_VERS,
vap, sizeof(*vap),
&new_tail);
if (!p)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
return send_tx_packet(lp, p, new_tail);
}
@@ -668,7 +661,7 @@ static int process_version(struct ldc_channel *lp,
return process_ver_nack(lp, vp);
default:
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
}
}
@@ -681,13 +674,13 @@ static int process_rts(struct ldc_channel *lp,
if (p->stype != LDC_INFO ||
lp->hs_state != LDC_HS_GOTVERS ||
p->env != lp->cfg.mode)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
lp->snd_nxt = p->seqid;
lp->rcv_nxt = p->seqid;
lp->hs_state = LDC_HS_SENTRTR;
if (send_rtr(lp))
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
return 0;
}
@@ -700,7 +693,7 @@ static int process_rtr(struct ldc_channel *lp,
if (p->stype != LDC_INFO ||
p->env != lp->cfg.mode)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
lp->snd_nxt = p->seqid;
lp->hs_state = LDC_HS_COMPLETE;
@@ -723,7 +716,7 @@ static int process_rdx(struct ldc_channel *lp,
if (p->stype != LDC_INFO ||
!(rx_seq_ok(lp, p->seqid)))
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
lp->rcv_nxt = p->seqid;
@@ -750,14 +743,14 @@ static int process_control_frame(struct ldc_channel *lp,
return process_rdx(lp, p);
default:
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
}
}
static int process_error_frame(struct ldc_channel *lp,
struct ldc_packet *p)
{
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
}
static int process_data_ack(struct ldc_channel *lp,
@@ -776,7 +769,7 @@ static int process_data_ack(struct ldc_channel *lp,
return 0;
}
if (head == lp->tx_tail)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
}
return 0;
@@ -820,16 +813,21 @@ static irqreturn_t ldc_rx(int irq, void *dev_id)
lp->hs_state = LDC_HS_COMPLETE;
ldc_set_state(lp, LDC_STATE_CONNECTED);
- event_mask |= LDC_EVENT_UP;
-
- orig_state = lp->chan_state;
+ /*
+ * Generate an LDC_EVENT_UP event if the channel
+ * was not already up.
+ */
+ if (orig_state != LDC_CHANNEL_UP) {
+ event_mask |= LDC_EVENT_UP;
+ orig_state = lp->chan_state;
+ }
}
/* If we are in reset state, flush the RX queue and ignore
* everything.
*/
if (lp->flags & LDC_FLAG_RESET) {
- (void) __set_rx_head(lp, lp->rx_tail);
+ (void) ldc_rx_reset(lp);
goto out;
}
@@ -880,7 +878,7 @@ handshake_complete:
break;
default:
- err = ldc_abort(lp);
+ err = LDC_ABORT(lp);
break;
}
@@ -895,7 +893,7 @@ handshake_complete:
err = __set_rx_head(lp, new);
if (err < 0) {
- (void) ldc_abort(lp);
+ (void) LDC_ABORT(lp);
break;
}
if (lp->hs_state == LDC_HS_COMPLETE)
@@ -936,7 +934,14 @@ static irqreturn_t ldc_tx(int irq, void *dev_id)
lp->hs_state = LDC_HS_COMPLETE;
ldc_set_state(lp, LDC_STATE_CONNECTED);
- event_mask |= LDC_EVENT_UP;
+ /*
+ * Generate an LDC_EVENT_UP event if the channel
+ * was not already up.
+ */
+ if (orig_state != LDC_CHANNEL_UP) {
+ event_mask |= LDC_EVENT_UP;
+ orig_state = lp->chan_state;
+ }
}
spin_unlock_irqrestore(&lp->lock, flags);
@@ -1447,12 +1452,52 @@ int ldc_state(struct ldc_channel *lp)
}
EXPORT_SYMBOL(ldc_state);
+void ldc_set_state(struct ldc_channel *lp, u8 state)
+{
+ ldcdbg(STATE, "STATE (%s) --> (%s)\n",
+ state_to_str(lp->state),
+ state_to_str(state));
+
+ lp->state = state;
+}
+
+int ldc_mode(struct ldc_channel *lp)
+{
+ return lp->cfg.mode;
+}
+
+int ldc_rx_reset(struct ldc_channel *lp)
+{
+ return __set_rx_head(lp, lp->rx_tail);
+}
+
+void __ldc_print(struct ldc_channel *lp, const char *caller)
+{
+ pr_info("%s: id=0x%lx flags=0x%x state=%s cstate=0x%lx hsstate=0x%x\n"
+ "\trx_h=0x%lx rx_t=0x%lx rx_n=%ld\n"
+ "\ttx_h=0x%lx tx_t=0x%lx tx_n=%ld\n"
+ "\trcv_nxt=%u snd_nxt=%u\n",
+ caller, lp->id, lp->flags, state_to_str(lp->state),
+ lp->chan_state, lp->hs_state,
+ lp->rx_head, lp->rx_tail, lp->rx_num_entries,
+ lp->tx_head, lp->tx_tail, lp->tx_num_entries,
+ lp->rcv_nxt, lp->snd_nxt);
+}
+
static int write_raw(struct ldc_channel *lp, const void *buf, unsigned int size)
{
struct ldc_packet *p;
- unsigned long new_tail;
+ unsigned long new_tail, hv_err;
int err;
+ hv_err = sun4v_ldc_tx_get_state(lp->id, &lp->tx_head, &lp->tx_tail,
+ &lp->chan_state);
+ if (unlikely(hv_err))
+ return -EBUSY;
+
+ if (unlikely(lp->chan_state != LDC_CHANNEL_UP))
+ return LDC_ABORT(lp);
+
if (size > LDC_PACKET_SIZE)
return -EMSGSIZE;
@@ -1483,7 +1528,7 @@ static int read_raw(struct ldc_channel *lp, void *buf, unsigned int size)
&lp->rx_tail,
&lp->chan_state);
if (hv_err)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
if (lp->chan_state == LDC_CHANNEL_DOWN ||
lp->chan_state == LDC_CHANNEL_RESETTING)
@@ -1526,7 +1571,7 @@ static int write_nonraw(struct ldc_channel *lp, const void *buf,
return -EBUSY;
if (unlikely(lp->chan_state != LDC_CHANNEL_UP))
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
if (!tx_has_space_for(lp, size))
return -EAGAIN;
@@ -1592,9 +1637,9 @@ static int rx_bad_seq(struct ldc_channel *lp, struct ldc_packet *p,
if (err)
return err;
- err = __set_rx_head(lp, lp->rx_tail);
+ err = ldc_rx_reset(lp);
if (err < 0)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
return 0;
}
@@ -1607,7 +1652,7 @@ static int data_ack_nack(struct ldc_channel *lp, struct ldc_packet *p)
return err;
}
if (p->stype & LDC_NACK)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
return 0;
}
@@ -1627,7 +1672,7 @@ static int rx_data_wait(struct ldc_channel *lp, unsigned long cur_head)
&lp->rx_tail,
&lp->chan_state);
if (hv_err)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
if (lp->chan_state == LDC_CHANNEL_DOWN ||
lp->chan_state == LDC_CHANNEL_RESETTING)
@@ -1650,7 +1695,7 @@ static int rx_set_head(struct ldc_channel *lp, unsigned long head)
int err = __set_rx_head(lp, head);
if (err < 0)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
lp->rx_head = head;
return 0;
@@ -1689,7 +1734,7 @@ static int read_nonraw(struct ldc_channel *lp, void *buf, unsigned int size)
&lp->rx_tail,
&lp->chan_state);
if (hv_err)
- return ldc_abort(lp);
+ return LDC_ABORT(lp);
if (lp->chan_state == LDC_CHANNEL_DOWN ||
lp->chan_state == LDC_CHANNEL_RESETTING)
@@ -1733,9 +1778,14 @@ static int read_nonraw(struct ldc_channel *lp, void *buf, unsigned int size)
lp->rcv_nxt = p->seqid;
+ /*
+ * If this is a control-only packet, there is nothing
+ * else to do but advance the rx queue since the packet
+ * was already processed above.
+ */
if (!(p->type & LDC_DATA)) {
new = rx_advance(lp, new);
- goto no_data;
+ break;
}
if (p->stype & (LDC_ACK | LDC_NACK)) {
err = data_ack_nack(lp, p);
@@ -1900,6 +1950,8 @@ int ldc_read(struct ldc_channel *lp, void *buf, unsigned int size)
unsigned long flags;
int err;
+ ldcdbg(RX, "%s: entered size=%d\n", __func__, size);
+
if (!buf)
return -EINVAL;
@@ -1915,6 +1967,9 @@ int ldc_read(struct ldc_channel *lp, void *buf, unsigned int size)
spin_unlock_irqrestore(&lp->lock, flags);
+ ldcdbg(RX, "%s: mode=%d, head=%lu, tail=%lu rv=%d\n", __func__,
+ lp->cfg.mode, lp->rx_head, lp->rx_tail, err);
+
return err;
}
EXPORT_SYMBOL(ldc_read);