Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH v1 6/8] dmaengine: enhance network subsystem to support DMA device hotplug
From: Dan Williams @ 2012-04-23 18:30 UTC (permalink / raw)
  To: Jiang Liu
  Cc: Vinod Koul, Jiang Liu, Keping Chen, David S. Miller,
	Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
	Patrick McHardy, netdev, linux-pci, linux-kernel
In-Reply-To: <1335189109-4871-7-git-send-email-jiang.liu@huawei.com>

On Mon, Apr 23, 2012 at 6:51 AM, Jiang Liu <liuj97@gmail.com> wrote:
> Enhance network subsystem to correctly update DMA channel reference counts,
> so it won't break DMA device hotplug logic.
>
> Signed-off-by: Jiang Liu <liuj97@gmail.com>

This introduces an atomic action on every channel touch, which is more
expensive than what we had previously.  There has always been a
concern about the overhead of offload that sometimes makes ineffective
or a loss compared to cpu copies.  In the cases where net_dma shows
improvement this will eat into / maybe eliminate that advantage.

Take a look at where dmaengine started [1].  It was from the beginning
going through contortions to avoid something like this.  We made it
simpler here [2], but still kept the principle of not dirtying a
shared cacheline on every channel touch, and certainly not locking it.

If you are going to hotplug the entire IOH, then you are probably ok
with network links going down, so could you just down the links and
remove the driver with the existing code?

--
Dan

[1]: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commitdiff;h=c13c826
[2]: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commitdiff;h=6f49a57a

^ permalink raw reply

* Re: [PATCHv2] workqueue: Catch more locking problems with flush_work()
From: Tejun Heo @ 2012-04-23 18:07 UTC (permalink / raw)
  To: Stephen Boyd; +Cc: linux-kernel, netdev, Ben Dooks, Yong Zhang
In-Reply-To: <1334968130-20724-1-git-send-email-sboyd@codeaurora.org>

On Fri, Apr 20, 2012 at 05:28:50PM -0700, Stephen Boyd wrote:
> If a workqueue is flushed with flush_work() lockdep checking can
> be circumvented. For example:
> 
>  static DEFINE_MUTEX(mutex);
> 
>  static void my_work(struct work_struct *w)
>  {
>          mutex_lock(&mutex);
>          mutex_unlock(&mutex);
>  }
> 
>  static DECLARE_WORK(work, my_work);
> 
>  static int __init start_test_module(void)
>  {
>          schedule_work(&work);
>          return 0;
>  }
>  module_init(start_test_module);
> 
>  static void __exit stop_test_module(void)
>  {
>          mutex_lock(&mutex);
>          flush_work(&work);
>          mutex_unlock(&mutex);
>  }
>  module_exit(stop_test_module);
> 
> would not always print a warning when flush_work() was called.
> In this trivial example nothing could go wrong since we are
> guaranteed module_init() and module_exit() don't run concurrently,
> but if the work item is schedule asynchronously we could have a
> scenario where the work item is running just at the time flush_work()
> is called resulting in a classic ABBA locking problem.
> 
> Add a lockdep hint by acquiring and releasing the work item
> lockdep_map in flush_work() so that we always catch this
> potential deadlock scenario.
> 
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>

Applied to wq/for-3.5.  Let's see whether it triggers spuriously.

Thanks.

-- 
tejun

^ permalink raw reply

* Re: [PATCH] [brcmsmac] "INTERMEDIATE but not AMPDU" only when tracing
From: Franky Lin @ 2012-04-23 17:43 UTC (permalink / raw)
  To: Eldad Zack, John W. Linville
  Cc: Brett Rudley, Roland Vossen, Arend van Spriel, Kan Yan,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1335048484-5925-1-git-send-email-eldad-v6AqZgAe4C4dvzyIwGCCOg@public.gmane.org>

On 04/21/2012 03:48 PM, Eldad Zack wrote:
>  From the code comment I understand that this something that can - and does, quite frequently - happen.
> This patch demotes the message to the trace level.
>
> Signed-off-by: Eldad Zack<eldad-v6AqZgAe4C4dvzyIwGCCOg@public.gmane.org>

Thx Eldad,

Acked-by: Franky Lin<frankyl-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 2/2 net-next] tcp: sk_add_backlog() is too agressive for TCP
From: Eric Dumazet @ 2012-04-23 17:23 UTC (permalink / raw)
  To: Rick Jones
  Cc: David Miller, netdev, Tom Herbert, Neal Cardwell,
	Maciej Żenczykowski, Yuchung Cheng, Ilpo Järvinen
In-Reply-To: <4F958DFD.7010207@hp.com>

On Mon, 2012-04-23 at 10:14 -0700, Rick Jones wrote:

> 
> This will increase what can be queued for arriving segments in general 
> and not for ACKs specifically yes?  (A possible issue that would have 
> come-up with my previous wondering about just increasing SO_RCVBUF as 
> SO_SNDBUF was increasing).  Perhaps only add sk->sk_sndbuf to the limit 
> if the arriving segment contains no data?

Thats the backlog limit that we tweak here.

Its not a big deal if we allow a bit more packets to come and later drop
them if we hit the real rcvbuf limit. (ACKS wont consume space, since
they are freed as soon as processed)

By the way, we used to have (sk_rcvbuf << 1) limit in the past.

Before commit c377411f2494a931ff we had :

if (sk->sk_backlog.len >= max(sk->sk_backlog.limit, sk->sk_rcvbuf << 1)) 
	return -ENOBUFS

We probably had drops in the past but didnt notice, since we lacked 
a counter for those drops.

^ permalink raw reply

* Re: [PATCH 2/2 net-next] tcp: sk_add_backlog() is too agressive for TCP
From: Rick Jones @ 2012-04-23 17:14 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David Miller, netdev, Tom Herbert, Neal Cardwell,
	Maciej Żenczykowski, Yuchung Cheng, Ilpo Järvinen
In-Reply-To: <1335173934.3293.84.camel@edumazet-glaptop>

On 04/23/2012 02:38 AM, Eric Dumazet wrote:
> From: Eric Dumazet<edumazet@google.com>
>
> While investigating TCP performance problems on 10Gb+ links, we found a
> tcp sender was dropping lot of incoming ACKS because of sk_rcvbuf limit
> in sk_add_backlog(), especially if receiver doesnt use GRO/LRO and sends
> one ACK every two MSS segments.
>
> A sender usually tweaks sk_sndbuf, but sk_rcvbuf stays at its default
> value (87380), allowing a too small backlog.
>
> A TCP ACK, even being small, can consume nearly same truesize space than
> outgoing packets. Using sk_rcvbuf + sk_sndbuf as a limit makes sense and
> is fast to compute.
>
> Performance results on netperf, single flow, receiver with disabled
> GRO/LRO : 7500 Mbits instead of 6050 Mbits, no more TCPBacklogDrop
> increments at sender.
>
> Signed-off-by: Eric Dumazet<edumazet@google.com>
> Cc: Neal Cardwell<ncardwell@google.com>
> Cc: Tom Herbert<therbert@google.com>
> Cc: Maciej Żenczykowski<maze@google.com>
> Cc: Yuchung Cheng<ycheng@google.com>
> Cc: Ilpo Järvinen<ilpo.jarvinen@helsinki.fi>
> Cc: Rick Jones<rick.jones2@hp.com>
> ---
>   net/ipv4/tcp_ipv4.c |    3 ++-
>   net/ipv6/tcp_ipv6.c |    3 ++-
>   2 files changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
> index 917607e..cf97e98 100644
> --- a/net/ipv4/tcp_ipv4.c
> +++ b/net/ipv4/tcp_ipv4.c
> @@ -1752,7 +1752,8 @@ process:
>   			if (!tcp_prequeue(sk, skb))
>   				ret = tcp_v4_do_rcv(sk, skb);
>   		}
> -	} else if (unlikely(sk_add_backlog(sk, skb, sk->sk_rcvbuf))) {
> +	} else if (unlikely(sk_add_backlog(sk, skb,
> +					   sk->sk_rcvbuf + sk->sk_sndbuf))) {
>   		bh_unlock_sock(sk);
>   		NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);
>   		goto discard_and_relse;

This will increase what can be queued for arriving segments in general 
and not for ACKs specifically yes?  (A possible issue that would have 
come-up with my previous wondering about just increasing SO_RCVBUF as 
SO_SNDBUF was increasing).  Perhaps only add sk->sk_sndbuf to the limit 
if the arriving segment contains no data?

rick


> diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
> index b04e6d8..5fb19d3 100644
> --- a/net/ipv6/tcp_ipv6.c
> +++ b/net/ipv6/tcp_ipv6.c
> @@ -1654,7 +1654,8 @@ process:
>   			if (!tcp_prequeue(sk, skb))
>   				ret = tcp_v6_do_rcv(sk, skb);
>   		}
> -	} else if (unlikely(sk_add_backlog(sk, skb, sk->sk_rcvbuf))) {
> +	} else if (unlikely(sk_add_backlog(sk, skb,
> +					   sk->sk_rcvbuf + sk->sk_sndbuf))) {
>   		bh_unlock_sock(sk);
>   		NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);
>   		goto discard_and_relse;
>

^ permalink raw reply

* [PATCH net-next] tcp: introduce tcp_try_coalesce
From: Eric Dumazet @ 2012-04-23 17:11 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, Neal Cardwell, Tom Herbert, Maciej Żenczykowski,
	Ilpo Järvinen

From: Eric Dumazet <edumazet@google.com>

commit c8628155ece3 (tcp: reduce out_of_order memory use) took care of
coalescing tcp segments provided by legacy devices (linear skbs)

We extend this idea to fragged skbs, as their truesize can be heavy.

ixgbe for example uses 256+1024+PAGE_SIZE/2 = 3328 bytes per segment.

Use this coalescing strategy for receive queue too.

This contributes to reduce number of tcp collapses, at minimal cost, and
reduces memory overhead and packets drops.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
Cc: Tom Herbert <therbert@google.com>
Cc: Maciej Żenczykowski <maze@google.com>
Cc: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
---
 net/ipv4/tcp_input.c |   79 ++++++++++++++++++++++++++++++++---------
 1 file changed, 62 insertions(+), 17 deletions(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 37e1c5c..bd7aef5 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4449,6 +4449,58 @@ static inline int tcp_try_rmem_schedule(struct sock *sk, unsigned int size)
 	return 0;
 }
 
+/**
+ * tcp_try_coalesce - try to merge skb to prior one
+ * @sk: socket
+ * @to: prior buffer
+ * @from: buffer to add in queue
+ *
+ * Before queueing skb @from after @to, try to merge them
+ * to reduce overall memory use and queue lengths, if cost is small.
+ * Packets in ofo or receive queues can stay a long time.
+ * Better try to coalesce them right now to avoid future collapses.
+ * Returns > 0 value if caller should free @from instead of queueing it
+ */
+static int tcp_try_coalesce(struct sock *sk,
+			    struct sk_buff *to,
+			    struct sk_buff *from)
+{
+	int len = from->len;
+
+	if (tcp_hdr(from)->fin)
+		return 0;
+	if (len <= skb_tailroom(to)) {
+		BUG_ON(skb_copy_bits(from, 0, skb_put(to, len), len));
+merge:
+		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRCVCOALESCE);
+		TCP_SKB_CB(to)->end_seq = TCP_SKB_CB(from)->end_seq;
+		TCP_SKB_CB(to)->ack_seq = TCP_SKB_CB(from)->ack_seq;
+		return 1;
+	}
+	if (skb_headlen(from) == 0 &&
+	    !skb_has_frag_list(to) &&
+	    !skb_has_frag_list(from) &&
+	    (skb_shinfo(to)->nr_frags +
+	     skb_shinfo(from)->nr_frags <= MAX_SKB_FRAGS)) {
+		int delta = from->truesize - ksize(from->head) -
+			    SKB_DATA_ALIGN(sizeof(struct sk_buff));
+
+		WARN_ON_ONCE(delta < len);
+		memcpy(skb_shinfo(to)->frags + skb_shinfo(to)->nr_frags,
+		       skb_shinfo(from)->frags,
+		       skb_shinfo(from)->nr_frags * sizeof(skb_frag_t));
+		skb_shinfo(to)->nr_frags += skb_shinfo(from)->nr_frags;
+		skb_shinfo(from)->nr_frags = 0;
+		to->truesize += delta;
+		atomic_add(delta, &sk->sk_rmem_alloc);
+		sk_mem_charge(sk, delta);
+		to->len += len;
+		to->data_len += len;
+		goto merge;
+	}
+	return 0;
+}
+
 static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
@@ -4487,23 +4539,11 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
 	end_seq = TCP_SKB_CB(skb)->end_seq;
 
 	if (seq == TCP_SKB_CB(skb1)->end_seq) {
-		/* Packets in ofo can stay in queue a long time.
-		 * Better try to coalesce them right now
-		 * to avoid future tcp_collapse_ofo_queue(),
-		 * probably the most expensive function in tcp stack.
-		 */
-		if (skb->len <= skb_tailroom(skb1) && !tcp_hdr(skb)->fin) {
-			NET_INC_STATS_BH(sock_net(sk),
-					 LINUX_MIB_TCPRCVCOALESCE);
-			BUG_ON(skb_copy_bits(skb, 0,
-					     skb_put(skb1, skb->len),
-					     skb->len));
-			TCP_SKB_CB(skb1)->end_seq = end_seq;
-			TCP_SKB_CB(skb1)->ack_seq = TCP_SKB_CB(skb)->ack_seq;
+		if (tcp_try_coalesce(sk, skb1, skb) <= 0) {
+			__skb_queue_after(&tp->out_of_order_queue, skb1, skb);
+		} else {
 			__kfree_skb(skb);
 			skb = NULL;
-		} else {
-			__skb_queue_after(&tp->out_of_order_queue, skb1, skb);
 		}
 
 		if (!tp->rx_opt.num_sacks ||
@@ -4624,13 +4664,18 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
 		}
 
 		if (eaten <= 0) {
+			struct sk_buff *tail;
 queue_and_out:
 			if (eaten < 0 &&
 			    tcp_try_rmem_schedule(sk, skb->truesize))
 				goto drop;
 
-			skb_set_owner_r(skb, sk);
-			__skb_queue_tail(&sk->sk_receive_queue, skb);
+			tail = skb_peek_tail(&sk->sk_receive_queue);
+			eaten = tail ? tcp_try_coalesce(sk, tail, skb) : -1;
+			if (eaten <= 0) {
+				skb_set_owner_r(skb, sk);
+				__skb_queue_tail(&sk->sk_receive_queue, skb);
+			}
 		}
 		tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
 		if (skb->len)

^ permalink raw reply related

* [PATCH 25/28] mISDN: Bugfix hfcsusb: usb endpoint activation/deactivation
From: Karsten Keil @ 2012-04-21 16:09 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

From: Martin Bachem <info@colognechip.com>

Fixed activation/deactivation of B1/B2's USB endpoints

Signed-off-by: Martin Bachem <info@colognechip.com>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
 drivers/isdn/hardware/mISDN/hfcsusb.c |   10 ++--------
 1 files changed, 2 insertions(+), 8 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 3c20b4f..cd0f2f6 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -232,7 +232,7 @@ hfcusb_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
 		return ret;
 	case PH_ACTIVATE_REQ:
 		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
-			hfcsusb_start_endpoint(hw, bch->nr);
+			hfcsusb_start_endpoint(hw, bch->nr - 1);
 			ret = hfcsusb_setup_bch(bch, ch->protocol);
 		} else
 			ret = 0;
@@ -496,12 +496,6 @@ open_bchannel(struct hfcsusb *hw, struct channel_req *rq)
 	bch->ch.protocol = rq->protocol;
 	rq->ch = &bch->ch;
 
-	/* start USB endpoint for bchannel */
-	if (rq->adr.channel  == 1)
-		hfcsusb_start_endpoint(hw, HFC_CHAN_B1);
-	else
-		hfcsusb_start_endpoint(hw, HFC_CHAN_B2);
-
 	if (!try_module_get(THIS_MODULE))
 		printk(KERN_WARNING "%s: %s:cannot get module\n",
 		       hw->name, __func__);
@@ -1806,7 +1800,7 @@ deactivate_bchannel(struct bchannel *bch)
 	mISDN_clear_bchannel(bch);
 	spin_unlock_irqrestore(&hw->lock, flags);
 	hfcsusb_setup_bch(bch, ISDN_P_NONE);
-	hfcsusb_stop_endpoint(hw, bch->nr);
+	hfcsusb_stop_endpoint(hw, bch->nr - 1);
 }
 
 /*
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 09/28] mISDN: Fix refcounting bug
From: Karsten Keil @ 2012-03-17 14:44 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

Under some configs it was still not possible to unload the driver.

Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
 drivers/isdn/mISDN/tei.c |   52 +++++++++++++++++++++++++++++++++------------
 1 files changed, 38 insertions(+), 14 deletions(-)

diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c
index 969766f..25ed826 100644
--- a/drivers/isdn/mISDN/tei.c
+++ b/drivers/isdn/mISDN/tei.c
@@ -790,18 +790,22 @@ tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len)
 static struct layer2 *
 create_new_tei(struct manager *mgr, int tei, int sapi)
 {
-	u_long		opt = 0;
-	u_long		flags;
-	int		id;
-	struct layer2	*l2;
+	u_long			opt = 0;
+	u_long			flags;
+	int			id;
+	struct layer2		*l2;
+	struct channel_req	rq;
 
 	if (!mgr->up)
 		return NULL;
 	if ((tei >= 0) && (tei < 64))
 		test_and_set_bit(OPTION_L2_FIXEDTEI, &opt);
-	if (mgr->ch.st->dev->Dprotocols
-	    & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1)))
+	if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) |
+	    (1 << ISDN_P_NT_E1))) {
 		test_and_set_bit(OPTION_L2_PMX, &opt);
+		rq.protocol = ISDN_P_NT_E1;
+	} else
+		rq.protocol = ISDN_P_NT_S0;
 	l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi);
 	if (!l2) {
 		printk(KERN_WARNING "%s:no memory for layer2\n", __func__);
@@ -836,6 +840,14 @@ create_new_tei(struct manager *mgr, int tei, int sapi)
 		l2->ch.recv = mgr->ch.recv;
 		l2->ch.peer = mgr->ch.peer;
 		l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL);
+		/* We need open here L1 for the manager as well (refcounting) */
+		rq.adr.dev = mgr->ch.st->dev->id;
+		id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, &rq);
+		if (id < 0) {
+			printk(KERN_WARNING "%s: cannot open L1\n", __func__);
+			l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
+			l2 = NULL;
+		}
 	}
 	return l2;
 }
@@ -978,10 +990,11 @@ TEIrelease(struct layer2 *l2)
 static int
 create_teimgr(struct manager *mgr, struct channel_req *crq)
 {
-	struct layer2	*l2;
-	u_long		opt = 0;
-	u_long		flags;
-	int		id;
+	struct layer2		*l2;
+	u_long			opt = 0;
+	u_long			flags;
+	int			id;
+	struct channel_req	l1rq;
 
 	if (*debug & DEBUG_L2_TEI)
 		printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
@@ -1016,6 +1029,7 @@ create_teimgr(struct manager *mgr, struct channel_req *crq)
 		if (crq->protocol == ISDN_P_LAPD_TE)
 			test_and_set_bit(MGR_OPT_USER, &mgr->options);
 	}
+	l1rq.adr = crq->adr;
 	if (mgr->ch.st->dev->Dprotocols
 	    & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1)))
 		test_and_set_bit(OPTION_L2_PMX, &opt);
@@ -1055,24 +1069,34 @@ create_teimgr(struct manager *mgr, struct channel_req *crq)
 		l2->tm->tei_m.fsm = &teifsmu;
 		l2->tm->tei_m.state = ST_TEI_NOP;
 		l2->tm->tval = 1000; /* T201  1 sec */
+		if (test_bit(OPTION_L2_PMX, &opt))
+			l1rq.protocol = ISDN_P_TE_E1;
+		else
+			l1rq.protocol = ISDN_P_TE_S0;
 	} else {
 		l2->tm->tei_m.fsm = &teifsmn;
 		l2->tm->tei_m.state = ST_TEI_NOP;
 		l2->tm->tval = 2000; /* T202  2 sec */
+		if (test_bit(OPTION_L2_PMX, &opt))
+			l1rq.protocol = ISDN_P_NT_E1;
+		else
+			l1rq.protocol = ISDN_P_NT_S0;
 	}
 	mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer);
 	write_lock_irqsave(&mgr->lock, flags);
 	id = get_free_id(mgr);
 	list_add_tail(&l2->list, &mgr->layer2);
 	write_unlock_irqrestore(&mgr->lock, flags);
-	if (id < 0) {
-		l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
-	} else {
+	if (id >= 0) {
 		l2->ch.nr = id;
 		l2->up->nr = id;
 		crq->ch = &l2->ch;
-		id = 0;
+		/* We need open here L1 for the manager as well (refcounting) */
+		id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL,
+					  &l1rq);
 	}
+	if (id < 0)
+		l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
 	return id;
 }
 
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 26/28] mISDN: Enhance hfcsusb driver
From: Karsten Keil @ 2012-04-21 16:16 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

- Add support for MISDN_CTRL_RX_OFF and MISDN_CTRL_FILL_EMPTY
- Add MISDN_CTRL_RX_BUFFER  handling
- Use a extra buffer pointer for the current transmitted frame, this allows
  upper layers to send next data earlier and should avoid TX underuns

Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
 drivers/isdn/hardware/mISDN/hfcsusb.c |  205 ++++++++++++++++++++++-----------
 drivers/isdn/hardware/mISDN/hfcsusb.h |   10 +-
 2 files changed, 143 insertions(+), 72 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index cd0f2f6..02b9fe9 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -27,7 +27,7 @@
  *   poll=<n>, default 128
  *     n : burst size of PH_DATA_IND at transparent rx data
  *
- * Revision: 0.3.3 (socket), 2008-11-05
+ * Revision: 0.3.5 (socket), 2012-01-16
  */
 
 #include <linux/module.h>
@@ -294,13 +294,12 @@ hfcusb_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb)
 
 	switch (hh->prim) {
 	case PH_DATA_REQ:
-		if (debug & DBG_HFC_CALL_TRACE)
-			printk(KERN_DEBUG "%s: %s: PH_DATA_REQ\n",
-			       hw->name, __func__);
-
 		spin_lock_irqsave(&hw->lock, flags);
 		ret = dchannel_senddata(dch, skb);
 		spin_unlock_irqrestore(&hw->lock, flags);
+		if (debug & DBG_HFC_CALL_TRACE)
+			printk(KERN_DEBUG "%s: %s: PH_DATA_REQ ret %d\n",
+			       hw->name, __func__, ret);
 		if (ret > 0) {
 			ret = 0;
 			queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL);
@@ -807,17 +806,49 @@ hfcsusb_ph_command(struct hfcsusb *hw, u_char command)
 static int
 channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
 {
-	int	ret = 0;
+	struct hfcsusb *hw = bch->hw;
+	int idx, o1, o2, ret = 0;
 
+	idx = (bch->nr - 1) & 1;
 	switch (cq->op) {
 	case MISDN_CTRL_GETOP:
-		cq->op = MISDN_CTRL_FILL_EMPTY;
+		cq->op = MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY |
+			 MISDN_CTRL_RX_BUFFER;
+		break;
+	case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
+		o1 = hw->dropcnt[idx];
+		if (cq->p1) {
+			test_and_set_bit(FLG_RX_OFF, &bch->Flags);
+			hw->dropcnt[idx] = 0;
+		} else
+			test_and_clear_bit(FLG_RX_OFF, &bch->Flags);
+		cq->p2 = o1;
+		if (debug & DEBUG_HW_BCHANNEL)
+			printk(KERN_DEBUG "Bch%d RX %s dropped %d\n",
+			       bch->nr, cq->p1 ? "off" : "on", o1);
 		break;
 	case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */
-		test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
-		if (debug & DEBUG_HW_OPEN)
-			printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d "
-			       "off=%d)\n", __func__, bch->nr, !!cq->p1);
+		if (cq->p1) {
+			test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
+			if (cq->p2 > -1)
+				hw->fillbyte[idx] = cq->p2 & 0xff;
+		} else
+			test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+		if (debug & DEBUG_HW_BCHANNEL)
+			printk(KERN_DEBUG "FILL_EMPTY Bch%d %s val %02x\n",
+			       bch->nr, cq->p1 ? "on" : "off",
+			       hw->fillbyte[idx]);
+		break;
+	case MISDN_CTRL_RX_BUFFER:
+		/* We return the old values */
+		o1 = bch->minlen;
+		o2 =  bch->maxlen;
+		if (cq->p1 != MISDN_CTRL_RX_SIZE_IGNORE)
+			bch->minlen = cq->p1;
+		if (cq->p2 != MISDN_CTRL_RX_SIZE_IGNORE)
+			bch->minlen = cq->p2;
+		cq->p1 = o1;
+		cq->p2 = o2;
 		break;
 	default:
 		printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op);
@@ -861,9 +892,21 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
 		hdlc = 1;
 	}
 	if (fifo->bch) {
+		if (test_bit(FLG_RX_OFF, &fifo->bch->Flags)) {
+			i = (fifo->bch->nr - 1) & 1;
+			hw->dropcnt[i]++;
+			spin_unlock(&hw->lock);
+			return;
+		}
 		rx_skb = fifo->bch->rx_skb;
 		maxlen = fifo->bch->maxlen;
 		hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
+		if (!hdlc) {
+			if (len >= fifo->bch->minlen)
+				maxlen = len;
+			else
+				maxlen = 2 * fifo->bch->minlen;
+		}
 	}
 	if (fifo->ech) {
 		rx_skb = fifo->ech->rx_skb;
@@ -938,8 +981,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
 				if (fifo->bch)
 					recv_Bchannel(fifo->bch, MISDN_ID_ANY);
 				if (fifo->ech)
-					recv_Echannel(fifo->ech,
-						      &hw->dch);
+					recv_Echannel(fifo->ech, &hw->dch);
 			} else {
 				if (debug & DBG_HFC_FIFO_VERBOSE) {
 					printk(KERN_DEBUG
@@ -957,7 +999,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
 		}
 	} else {
 		/* deliver transparent data to layer2 */
-		if (rx_skb->len >= poll)
+		if (rx_skb->len >= fifo->bch->minlen)
 			recv_Bchannel(fifo->bch, MISDN_ID_ANY);
 	}
 	spin_unlock(&hw->lock);
@@ -1184,36 +1226,48 @@ tx_iso_complete(struct urb *urb)
 	struct iso_urb *context_iso_urb = (struct iso_urb *) urb->context;
 	struct usb_fifo *fifo = context_iso_urb->owner_fifo;
 	struct hfcsusb *hw = fifo->hw;
-	struct sk_buff *tx_skb;
 	int k, tx_offset, num_isoc_packets, sink, remain, current_len,
-		errcode, hdlc, i;
-	int *tx_idx;
+		errcode, hdlc = 1, i;
 	int frame_complete, fifon, status;
-	__u8 threshbit;
+	__u8 threshbit, fill = 0;
 
 	spin_lock(&hw->lock);
+	if (!fifo->ctx) {
+		if (fifo->dch) {
+			fifo->ctx = fifo->dch->tx_skb;
+			fifo->ctxi = 0;
+			if (fifo->ctx)
+				i = get_next_dframe(fifo->dch);
+		} else if (fifo->bch) {
+			fifo->ctx = fifo->bch->tx_skb;
+			fifo->ctxi = 0;
+			if (fifo->ctx)
+				get_next_bframe(fifo->bch);
+			hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
+			if (!hdlc)
+				fill = hw->fillbyte[(fifo->bch->nr - 1) & 1];
+		} else {
+			printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n",
+			       hw->name, __func__);
+			spin_unlock(&hw->lock);
+			return;
+		}
+	} else {
+		if (fifo->bch) {
+			hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
+			if (!hdlc)
+				fill = hw->fillbyte[(fifo->bch->nr - 1) & 1];
+		}
+	}
 	if (fifo->stop_gracefull) {
 		fifo->stop_gracefull = 0;
 		fifo->active = 0;
+		if (fifo->ctx)
+			dev_kfree_skb(fifo->ctx);
+		fifo->ctx = NULL;
 		spin_unlock(&hw->lock);
 		return;
 	}
-
-	if (fifo->dch) {
-		tx_skb = fifo->dch->tx_skb;
-		tx_idx = &fifo->dch->tx_idx;
-		hdlc = 1;
-	} else if (fifo->bch) {
-		tx_skb = fifo->bch->tx_skb;
-		tx_idx = &fifo->bch->tx_idx;
-		hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
-	} else {
-		printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n",
-		       hw->name, __func__);
-		spin_unlock(&hw->lock);
-		return;
-	}
-
 	fifon = fifo->fifonum;
 	status = urb->status;
 
@@ -1248,7 +1302,7 @@ tx_iso_complete(struct urb *urb)
 			      fifo->usb_packet_maxlen, fifo->intervall,
 			      (usb_complete_t)tx_iso_complete, urb->context);
 		memset(context_iso_urb->buffer, 0,
-		       sizeof(context_iso_urb->buffer));
+			sizeof(context_iso_urb->buffer));
 		frame_complete = 0;
 
 		for (k = 0; k < num_isoc_packets; ++k) {
@@ -1263,10 +1317,14 @@ tx_iso_complete(struct urb *urb)
 			}
 
 			/* Generate next ISO Packets */
-			if (tx_skb)
-				remain = tx_skb->len - *tx_idx;
-			else
+			if (fifo->ctx)
+				remain = fifo->ctx->len - fifo->ctxi;
+			else {
 				remain = 0;
+				if ((!hdlc) &&
+				    test_bit(FLG_FILLEMPTY, &fifo->bch->Flags))
+					remain = 14;
+			}
 
 			if (remain > 0) {
 				fifo->bit_line -= sink;
@@ -1295,10 +1353,17 @@ tx_iso_complete(struct urb *urb)
 				}
 
 				/* copy tx data to iso-urb buffer */
-				memcpy(context_iso_urb->buffer + tx_offset + 1,
-				       (tx_skb->data + *tx_idx), current_len);
-				*tx_idx += current_len;
-
+				i = tx_offset + 1;
+				if (fifo->ctx) {
+					memcpy(context_iso_urb->buffer + i,
+						(fifo->ctx->data + fifo->ctxi),
+						current_len);
+					fifo->ctxi += current_len;
+				} else {
+					memset(context_iso_urb->buffer + i,
+						fill, current_len);
+					frame_complete = 1;
+				}
 				urb->iso_frame_desc[k].offset = tx_offset;
 				urb->iso_frame_desc[k].length = current_len + 1;
 
@@ -1313,14 +1378,14 @@ tx_iso_complete(struct urb *urb)
 					       urb->iso_frame_desc[k].length);
 
 					for (i = urb->iso_frame_desc[k].offset;
-					     i < (urb->iso_frame_desc[k].offset
-						  + urb->iso_frame_desc[k].length);
-					     i++)
+					    i < (urb->iso_frame_desc[k].offset +
+					    urb->iso_frame_desc[k].length);
+					    i++)
 						printk("%x ",
 						       context_iso_urb->buffer[i]);
 
 					printk(" skb->len(%i) tx-idx(%d)\n",
-					       tx_skb->len, *tx_idx);
+					       fifo->ctx->len, fifo->ctxi);
 				}
 
 				tx_offset += (current_len + 1);
@@ -1335,29 +1400,34 @@ tx_iso_complete(struct urb *urb)
 
 			if (frame_complete) {
 				frame_complete = 0;
-
 				if (debug & DBG_HFC_FIFO_VERBOSE) {
 					printk(KERN_DEBUG  "%s: %s: "
 					       "fifon(%i) new TX len(%i): ",
 					       hw->name, __func__,
-					       fifon, tx_skb->len);
+					       fifon, fifo->ctx->len);
 					i = 0;
-					while (i < tx_skb->len)
+					while (i < fifo->ctx->len)
 						printk("%02x ",
-						       tx_skb->data[i++]);
+						       fifo->ctx->data[i++]);
 					printk("\n");
 				}
-
-				dev_kfree_skb(tx_skb);
-				tx_skb = NULL;
-				if (fifo->dch && get_next_dframe(fifo->dch))
-					tx_skb = fifo->dch->tx_skb;
-				else if (fifo->bch &&
-					 get_next_bframe(fifo->bch)) {
-					if (test_bit(FLG_TRANSPARENT,
-						     &fifo->bch->Flags))
-						confirm_Bsend(fifo->bch);
-					tx_skb = fifo->bch->tx_skb;
+				dev_kfree_skb(fifo->ctx);
+				fifo->ctx = NULL;
+				fifo->ctxi = 0;
+				if (fifo->dch) {
+					if (fifo->dch->tx_skb) {
+						fifo->ctx = fifo->dch->tx_skb;
+						get_next_dframe(fifo->dch);
+					} else
+						test_and_clear_bit(FLG_TX_BUSY,
+							&fifo->dch->Flags);
+				} else if (fifo->bch) {
+					if (fifo->bch->tx_skb) {
+						fifo->ctx = fifo->bch->tx_skb;
+						get_next_bframe(fifo->bch);
+					} else
+						test_and_clear_bit(FLG_TX_BUSY,
+							&fifo->bch->Flags);
 				}
 			}
 		}
@@ -1417,11 +1487,10 @@ start_isoc_chain(struct usb_fifo *fifo, int num_packets_per_urb,
 			}
 			fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
 			fifo->iso[i].indx = i;
-
 			/* Init the first iso */
 			if (ISO_BUFFER_SIZE >=
 			    (fifo->usb_packet_maxlen *
-			     num_packets_per_urb)) {
+			    num_packets_per_urb)) {
 				fill_isoc_urb(fifo->iso[i].urb,
 					      fifo->hw->dev, fifo->pipe,
 					      fifo->iso[i].buffer,
@@ -1430,7 +1499,7 @@ start_isoc_chain(struct usb_fifo *fifo, int num_packets_per_urb,
 					      fifo->intervall, complete,
 					      &fifo->iso[i]);
 				memset(fifo->iso[i].buffer, 0,
-				       sizeof(fifo->iso[i].buffer));
+				     sizeof(fifo->iso[i].buffer));
 
 				for (k = 0; k < num_packets_per_urb; k++) {
 					fifo->iso[i].urb->
@@ -1471,7 +1540,7 @@ stop_iso_gracefull(struct usb_fifo *fifo)
 		spin_lock_irqsave(&hw->lock, flags);
 		if (debug)
 			printk(KERN_DEBUG "%s: %s for fifo %i.%i\n",
-			       hw->name, __func__, fifo->fifonum, i);
+			     hw->name, __func__, fifo->fifonum, i);
 		fifo->stop_gracefull = 1;
 		spin_unlock_irqrestore(&hw->lock, flags);
 	}
@@ -1496,7 +1565,7 @@ stop_int_gracefull(struct usb_fifo *fifo)
 	spin_lock_irqsave(&hw->lock, flags);
 	if (debug)
 		printk(KERN_DEBUG "%s: %s for fifo %i\n",
-		       hw->name, __func__, fifo->fifonum);
+		     hw->name, __func__, fifo->fifonum);
 	fifo->stop_gracefull = 1;
 	spin_unlock_irqrestore(&hw->lock, flags);
 
@@ -1505,7 +1574,7 @@ stop_int_gracefull(struct usb_fifo *fifo)
 		schedule_timeout_interruptible((HZ / 1000) * 3);
 	if (debug && fifo->stop_gracefull)
 		printk(KERN_DEBUG "%s: ERROR %s for fifo %i\n",
-		       hw->name, __func__, fifo->fifonum);
+		     hw->name, __func__, fifo->fifonum);
 }
 
 /* start the interrupt transfer for the given fifo */
@@ -1870,7 +1939,7 @@ setup_instance(struct hfcsusb *hw, struct device *parent)
 		hw->bch[i].nr = i + 1;
 		set_channelmap(i + 1, hw->dch.dev.channelmap);
 		hw->bch[i].debug = debug;
-		mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM, -1);
+		mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM, poll);
 		hw->bch[i].hw = hw;
 		hw->bch[i].ch.send = hfcusb_l2l1B;
 		hw->bch[i].ch.ctrl = hfc_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.h b/drivers/isdn/hardware/mISDN/hfcsusb.h
index cb1231b..7d48b86 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.h
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.h
@@ -263,6 +263,8 @@ struct usb_fifo {
 	struct dchannel *dch;	/* link to hfcsusb_t->dch */
 	struct bchannel *bch;	/* link to hfcsusb_t->bch */
 	struct dchannel *ech;	/* link to hfcsusb_t->ech, TODO: E-CHANNEL */
+	struct sk_buff	*ctx;	/* current TX skb */
+	int		ctxi;	/* next byte to write from current TX skb */
 	int last_urblen;	/* remember length of last packet */
 	__u8 stop_gracefull;	/* stops URB retransmission */
 };
@@ -282,7 +284,6 @@ struct hfcsusb {
 	int			packet_size;
 	int			iso_packet_size;
 	struct usb_fifo		fifos[HFCUSB_NUM_FIFOS];
-
 	/* control pipe background handling */
 	struct ctrl_buf		ctrl_buff[HFC_CTRL_BUFSIZE];
 	int			ctrl_in_idx, ctrl_out_idx, ctrl_cnt;
@@ -293,15 +294,16 @@ struct hfcsusb {
 	int			ctrl_in_pipe, ctrl_out_pipe;
 	spinlock_t		ctrl_lock; /* lock for ctrl */
 	spinlock_t              lock;
+	int			nt_timer;
+	int			open;
+	int			dropcnt[2];
 
 	__u8			threshold_mask;
 	__u8			led_state;
-
 	__u8			protocol;
-	int			nt_timer;
-	int			open;
 	__u8			timers;
 	__u8			initdone;
+	__u8			fillbyte[2];
 	char			name[MISDN_MAX_IDLEN];
 };
 
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 17/28] mISDN: Add 2MBit mode for HFC E1 card
From: Karsten Keil @ 2012-03-18 13:45 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

The new mode allows to receive and transmit full transparent
or HDLC data of all timeslots via one FIFO.
Change some register names to match the latest manual for
the E1 chip.

Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
 drivers/isdn/hardware/mISDN/hfc_multi.h |   79 +++---
 drivers/isdn/hardware/mISDN/hfcmulti.c  |  426 ++++++++++++++++++++++++++-----
 include/linux/mISDNif.h                 |   57 +++--
 3 files changed, 440 insertions(+), 122 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h
index c601f88..9dc0543 100644
--- a/drivers/isdn/hardware/mISDN/hfc_multi.h
+++ b/drivers/isdn/hardware/mISDN/hfc_multi.h
@@ -12,6 +12,7 @@
 #define	DEBUG_HFCMULTI_FILL	0x00800000
 #define	DEBUG_HFCMULTI_SYNC	0x01000000
 #define	DEBUG_HFCMULTI_DTMF	0x02000000
+#define	DEBUG_HFCMULTI_TIMER	0x04000000
 #define	DEBUG_HFCMULTI_LOCK	0x80000000
 
 #define	PCI_ENA_REGIO	0x01
@@ -71,7 +72,10 @@ struct hfcm_hw {
 	u_char	r_dtmf;
 	u_char	r_st_sync;
 	u_char	r_sci_msk;
-	u_char	r_tx0, r_tx1;
+	u_char	r_tx0;
+	u_char	r_tx1;
+	u_char	r_rx_sl0_cfg0;
+	u_char	r_tx_sl0_cfg1;
 	u_char	a_st_ctrl0[8];
 	u_char	r_bert_wd_md;
 	timer_t	timer;
@@ -114,6 +118,7 @@ struct hfcm_hw {
 /* hw */
 #define	HFC_CHIP_PLXSD		14 /* whether we have a Speech-Design PLX */
 #define	HFC_CHIP_EMBSD          15 /* whether we have a SD Embedded board */
+#define HFC_CHIP_2MBITRAW	16 /* mode to access full 32 byte data */
 
 #define HFC_IO_MODE_PCIMEM	0x00 /* normal memory mapped IO */
 #define HFC_IO_MODE_REGIO	0x01 /* PCI io access */
@@ -334,24 +339,23 @@ struct hfc_multi {
 #define R_LOS0			0x22
 #define R_LOS1			0x23
 #define R_RX0			0x24
-#define R_RX_FR0		0x25
-#define R_RX_FR1		0x26
+#define R_RX_SL0_CFG0		0x25
+#define R_RX_SL0_CFG1		0x26
 #define R_TX0			0x28
 #define R_TX1			0x29
-#define R_TX_FR0		0x2C
-
-#define R_TX_FR1		0x2D
-#define R_TX_FR2		0x2E
-#define R_JATT_ATT		0x2F /* undocumented */
+#define R_TX_SL0_CFG0		0x2C
+#define R_TX_SL0		0x2D
+#define R_TX_SL0_CFG1		0x2E
+#define R_JATT_CFG		0x2F
 #define A_ST_RD_STATE		0x30
 #define A_ST_WR_STATE		0x30
-#define R_RX_OFF		0x30
+#define R_RX_OFFS		0x30
 #define A_ST_CTRL0		0x31
 #define R_SYNC_OUT		0x31
 #define A_ST_CTRL1		0x32
 #define A_ST_CTRL2		0x33
 #define A_ST_SQ_WR		0x34
-#define R_TX_OFF		0x34
+#define R_TX_OFFS		0x34
 #define R_SYNC_CTRL		0x35
 #define A_ST_CLK_DLY		0x37
 #define R_PWM0			0x38
@@ -414,8 +418,8 @@ struct hfc_multi {
 #define R_RX_SL0_0		0x25
 #define R_RX_SL0_1		0x26
 #define R_RX_SL0_2		0x27
-#define R_JATT_DIR		0x2b /* undocumented */
-#define R_SLIP			0x2c
+#define R_JATT_STA		0x2B
+#define R_SLIP			0x2C
 #define A_ST_RD_STA		0x30
 #define R_FAS_EC		0x30
 #define R_FAS_ECL		0x30
@@ -430,12 +434,12 @@ struct hfc_multi {
 #define R_E_EC			0x36
 #define R_E_ECL			0x36
 #define R_E_ECH			0x37
-#define R_SA6_SA13_EC		0x38
-#define R_SA6_SA13_ECL		0x38
-#define R_SA6_SA13_ECH		0x39
-#define R_SA6_SA23_EC		0x3A
-#define R_SA6_SA23_ECL		0x3A
-#define R_SA6_SA23_ECH		0x3B
+#define R_SA6_VAL13_EC		0x38
+#define R_SA6_VAL13_ECL		0x38
+#define R_SA6_VAL13_ECH		0x39
+#define R_SA6_VAL23_EC		0x3A
+#define R_SA6_VAL23_ECL		0x3A
+#define R_SA6_VAL23_ECH		0x3B
 #define A_ST_B1_RX		0x3C
 #define A_ST_B2_RX		0x3D
 #define A_ST_D_RX		0x3E
@@ -624,7 +628,7 @@ struct hfc_multi {
 #define V_RX_INV_CLK		0x20
 #define V_RX_INV_DATA		0x40
 #define V_AIS_ITU		0x80
-/* R_RX_FR0 */
+/* R_RX_SL0_CFG0 */
 #define V_NO_INSYNC		0x01
 #define V_AUTO_RESYNC		0x02
 #define V_AUTO_RECO		0x04
@@ -633,7 +637,7 @@ struct hfc_multi {
 #define V_XCRC_SYNC		0x20
 #define V_MF_RESYNC		0x40
 #define V_RESYNC		0x80
-/* R_RX_FR1 */
+/* R_RX_SL0_CFG1 */
 #define V_RX_MF			0x01
 #define V_RX_MF_SYNC		0x02
 #define V_RX_SL0_RAM		0x04
@@ -654,17 +658,17 @@ struct hfc_multi {
 #define V_ATX			0x20
 #define V_NTRI			0x40
 #define V_AUTO_ERR_RES		0x80
-/* R_TX_FR0 */
+/* R_TX_SL0_CFG0 */
 #define V_TRP_FAS		0x01
 #define V_TRP_NFAS		0x02
 #define V_TRP_RAL		0x04
 #define V_TRP_SA		0x08
-/* R_TX_FR1 */
+/* R_TX_SL0 */
 #define V_TX_FAS		0x01
 #define V_TX_NFAS		0x02
 #define V_TX_RAL		0x04
 #define V_TX_SA			0x08
-/* R_TX_FR2 */
+/* R_TX_SL0_CFG1 */
 #define V_TX_MF			0x01
 #define V_TRP_SL0		0x02
 #define V_TX_SL0_RAM		0x04
@@ -672,7 +676,7 @@ struct hfc_multi {
 #define V_NEG_E			0x20
 #define V_XS12_ON		0x40
 #define V_XS15_ON		0x80
-/* R_RX_OFF */
+/* R_RX_OFFS */
 #define V_RX_SZ			0x01
 #define V_RX_INIT		0x04
 /* R_SYNC_OUT */
@@ -680,7 +684,7 @@ struct hfc_multi {
 #define V_IPATS0		0x20
 #define V_IPATS1		0x40
 #define V_IPATS2		0x80
-/* R_TX_OFF */
+/* R_TX_OFFS */
 #define V_TX_SZ			0x01
 #define V_TX_INIT		0x04
 /* R_SYNC_CTRL */
@@ -1119,20 +1123,20 @@ struct hfc_register_names {
 	{"R_LOS0",		0x22},
 	{"R_LOS1",		0x23},
 	{"R_RX0",		0x24},
-	{"R_RX_FR0",		0x25},
-	{"R_RX_FR1",		0x26},
+	{"R_RX_SL0_CFG0",	0x25},
+	{"R_RX_SL0_CFG1",	0x26},
 	{"R_TX0",		0x28},
 	{"R_TX1",		0x29},
-	{"R_TX_FR0",		0x2C},
-	{"R_TX_FR1",		0x2D},
-	{"R_TX_FR2",		0x2E},
+	{"R_TX_SL0_CFG0",	0x2C},
+	{"R_TX_SL0",		0x2D},
+	{"R_TX_SL0_CFG1",	0x2E},
 	{"R_JATT_ATT",		0x2F},
-	{"A_ST_xx_STA/R_RX_OFF", 0x30},
+	{"A_ST_xx_STA/R_RX_OFFS", 0x30},
 	{"A_ST_CTRL0/R_SYNC_OUT", 0x31},
 	{"A_ST_CTRL1",		0x32},
 	{"A_ST_CTRL2",		0x33},
 	{"A_ST_SQ_WR",		0x34},
-	{"R_TX_OFF",		0x34},
+	{"R_TX_OFFS",		0x34},
 	{"R_SYNC_CTRL",		0x35},
 	{"A_ST_CLK_DLY",	0x37},
 	{"R_PWM0",		0x38},
@@ -1194,8 +1198,9 @@ struct hfc_register_names {
 	{"R_RX_SL0_0",		0x25},
 	{"R_RX_SL0_1",		0x26},
 	{"R_RX_SL0_2",		0x27},
-	{"R_JATT_DIR",		0x2b},
+	{"R_JATT_STA",		0x2b},
 	{"R_SLIP",		0x2c},
+	{"R_JATT_CFG",		0x2f},
 	{"A_ST_RD_STA",		0x30},
 	{"R_FAS_ECL",		0x30},
 	{"R_FAS_ECH",		0x31},
@@ -1205,10 +1210,10 @@ struct hfc_register_names {
 	{"R_CRC_ECH",		0x35},
 	{"R_E_ECL",		0x36},
 	{"R_E_ECH",		0x37},
-	{"R_SA6_SA13_ECL",	0x38},
-	{"R_SA6_SA13_ECH",	0x39},
-	{"R_SA6_SA23_ECL",	0x3A},
-	{"R_SA6_SA23_ECH",	0x3B},
+	{"R_SA6_VAL13_ECL",	0x38},
+	{"R_SA6_VAL13_ECH",	0x39},
+	{"R_SA6_VAL23_ECL",	0x3A},
+	{"R_SA6_VAL23_ECH",	0x3B},
 	{"A_ST_B1_RX",		0x3C},
 	{"A_ST_B2_RX",		0x3D},
 	{"A_ST_D_RX",		0x3E},
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 4301331..4ae6f8e 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -64,7 +64,7 @@
  *
  *	HFC-E1 only bits:
  *	Bit 0     = 0x0001 = interface: 0=copper, 1=optical
- *	Bit 1     = 0x0002 = reserved (later for 32 B-channels transparent mode)
+ *	Bit 1     = 0x0002 = 32 B-channels bundle mode (one channel)
  *	Bit 2     = 0x0004 = Report LOS
  *	Bit 3     = 0x0008 = Report AIS
  *	Bit 4     = 0x0010 = Report SLIP
@@ -1269,11 +1269,10 @@ init_chip(struct hfc_multi *hc)
 		if (debug & DEBUG_HFCMULTI_INIT)
 			printk(KERN_DEBUG "%s: setting PCM into slave mode\n",
 			       __func__);
-	} else
-		if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) && !plxsd_master) {
+	} else  if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) && !plxsd_master) {
 			if (debug & DEBUG_HFCMULTI_INIT)
 				printk(KERN_DEBUG "%s: setting PCM into master mode\n",
-				       __func__);
+				__func__);
 			hc->hw.r_pcm_md0 |= V_PCM_MD;
 		} else {
 			if (debug & DEBUG_HFCMULTI_INIT)
@@ -1288,7 +1287,18 @@ init_chip(struct hfc_multi *hc)
 			 0x11 /* 16 Bytes TX/RX */);
 	else
 		HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz);
-	HFC_outb(hc, R_FIFO_MD, 0);
+	if (test_bit(HFC_CHIP_2MBITRAW, &hc->chip) &&
+	    (hc->ctype == HFC_TYPE_E1)) {
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG "%s: setting 2MBit raw mode\n",
+				__func__);
+		HFC_outb(hc, R_FIFO_MD, 0x0c);
+		hc->Flen = 0x10;
+		hc->Zmin = 0x80;
+		hc->Zlen = 384;
+
+	} else
+		HFC_outb(hc, R_FIFO_MD, 0);
 	if (hc->ctype == HFC_TYPE_XHFC)
 		hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES;
 	else
@@ -1334,7 +1344,8 @@ init_chip(struct hfc_multi *hc)
 	if (hc->slots == 128)
 		HFC_outb(hc, R_PCM_MD1, 0x20);
 	HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0);
-	if (test_bit(HFC_CHIP_PLXSD, &hc->chip))
+	if (test_bit(HFC_CHIP_PLXSD, &hc->chip) ||
+		test_bit(HFC_CHIP_PCM_MASTER, &hc->chip))
 		HFC_outb(hc, R_PCM_MD2, V_SYNC_SRC); /* sync via SYNC_I / O */
 	else if (test_bit(HFC_CHIP_EMBSD, &hc->chip))
 		HFC_outb(hc, R_PCM_MD2, 0x10); /* V_C2O_EN */
@@ -1956,7 +1967,10 @@ hfcmulti_tx(struct hfc_multi *hc, int ch)
 	int *idxp;
 
 	bch = hc->chan[ch].bch;
-	dch = hc->chan[ch].dch;
+	if (!bch)
+		dch = hc->chan[ch].dch;
+	else
+		dch = NULL;
 	if ((!dch) && (!bch))
 		return;
 
@@ -2205,7 +2219,11 @@ hfcmulti_rx(struct hfc_multi *hc, int ch)
 	int	maxlen;
 
 	bch = hc->chan[ch].bch;
-	dch = hc->chan[ch].dch;
+	if (!bch)
+		dch = hc->chan[ch].dch;
+	else
+		dch = NULL;
+
 	if ((!dch) && (!bch))
 		return;
 	if (dch) {
@@ -2264,20 +2282,20 @@ next_frame:
 	if (Zsize <= 0)
 		return;
 
-	if (*sp == NULL) {
-		*sp = mI_alloc_skb(maxlen + 3, GFP_ATOMIC);
-		if (*sp == NULL) {
-			printk(KERN_DEBUG "%s: No mem for rx_skb\n",
-			       __func__);
-			return;
-		}
-	}
 	/* show activity */
 	if (dch)
 		hc->activity_rx |= 1 << hc->chan[ch].port;
 
 	/* empty fifo with what we have */
 	if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
+		if (*sp == NULL) {
+			*sp = mI_alloc_skb(maxlen + 3, GFP_ATOMIC);
+			if (*sp == NULL) {
+				printk(KERN_DEBUG "%s: No mem for rx_skb\n",
+				    __func__);
+				return;
+			}
+		}
 		if (debug & DEBUG_HFCMULTI_FIFO)
 			printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d "
 			       "bytes (z1=%04x, z2=%04x) HDLC %s (f1=%d, f2=%d) "
@@ -2355,24 +2373,18 @@ next_frame:
 		/* there is an incomplete frame */
 	} else {
 		/* transparent */
+		if (*sp == NULL) {
+			*sp = mI_alloc_skb(Zsize, GFP_ATOMIC);
+			if (*sp == NULL) {
+				printk(KERN_DEBUG "%s: No mem for rx_skb\n",
+				    __func__);
+				return;
+			}
+		}
 		if (Zsize > skb_tailroom(*sp))
 			Zsize = skb_tailroom(*sp);
 		hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize);
-		if (((*sp)->len) < MISDN_COPY_SIZE) {
-			skb = *sp;
-			*sp = mI_alloc_skb(skb->len, GFP_ATOMIC);
-			if (*sp) {
-				memcpy(skb_put(*sp, skb->len),
-				       skb->data, skb->len);
-				skb_trim(skb, 0);
-			} else {
-				printk(KERN_DEBUG "%s: No mem\n", __func__);
-				*sp = skb;
-				skb = NULL;
-			}
-		} else {
-			skb = NULL;
-		}
+		skb = NULL;
 		if (debug & DEBUG_HFCMULTI_FIFO)
 			printk(KERN_DEBUG
 			       "%s(card %d): fifo(%d) reading %d bytes "
@@ -2409,7 +2421,7 @@ signal_state_up(struct dchannel *dch, int info, char *msg)
 static inline void
 handle_timer_irq(struct hfc_multi *hc)
 {
-	int		ch, temp;
+	int		ch, temp, ch_activ = 0;
 	struct dchannel	*dch;
 	u_long		flags;
 
@@ -2443,10 +2455,33 @@ handle_timer_irq(struct hfc_multi *hc)
 		hc->e1_resync = 0;
 		spin_unlock_irqrestore(&HFClock, flags);
 	}
-
-	if (hc->ctype != HFC_TYPE_E1 || hc->e1_state == 1)
+	if (test_bit(HFC_CHIP_2MBITRAW, &hc->chip)) {
+		if (hc->created[hc->chan[0].port] && hc->chan[ch].bch &&
+		    test_bit(FLG_ACTIVE, &hc->chan[ch].bch->Flags)) {
+			ch_activ++;
+			hfcmulti_tx(hc, 0);
+			hfcmulti_rx(hc, 0);
+			ch = 1;
+			if (hc->chan[ch].dch &&
+			    hc->chan[ch].nt_timer > -1) {
+				dch = hc->chan[ch].dch;
+				if (!(--hc->chan[ch].nt_timer)) {
+					schedule_event(dch,
+					    FLG_PHCHANGE);
+					if (debug &
+					    DEBUG_HFCMULTI_STATE)
+						printk(KERN_DEBUG
+						    "%s: nt_timer at "
+						    "state %x\n",
+						    __func__,
+						    dch->state);
+				}
+			}
+		}
+	} else if (hc->ctype != HFC_TYPE_E1 || hc->e1_state == 1) {
 		for (ch = 0; ch <= 31; ch++) {
 			if (hc->created[hc->chan[ch].port]) {
+				ch_activ++;
 				hfcmulti_tx(hc, ch);
 				/* fifo is started when switching to rx-fifo */
 				hfcmulti_rx(hc, ch);
@@ -2467,6 +2502,11 @@ handle_timer_irq(struct hfc_multi *hc)
 				}
 			}
 		}
+	}
+	if (debug & DEBUG_HFCMULTI_TIMER)
+		printk(KERN_DEBUG "Timer IRQ id%dp%d st%d activ %d\n",
+			hc->id, hc->ports, hc->e1_state, ch_activ);
+
 	if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) {
 		dch = hc->chan[hc->dnum[0]].dch;
 		/* LOS */
@@ -2515,7 +2555,7 @@ handle_timer_irq(struct hfc_multi *hc)
 						"RDI gone");
 			hc->chan[hc->dnum[0]].rdi = temp;
 		}
-		temp = HFC_inb_nodebug(hc, R_JATT_DIR);
+		temp = HFC_inb_nodebug(hc, R_JATT_STA);
 		switch (hc->chan[hc->dnum[0]].sync) {
 		case 0:
 			if ((temp & 0x60) == 0x60) {
@@ -2524,9 +2564,9 @@ handle_timer_irq(struct hfc_multi *hc)
 					       "%s: (id=%d) E1 now "
 					       "in clock sync\n",
 					       __func__, hc->id);
-				HFC_outb(hc, R_RX_OFF,
+				HFC_outb(hc, R_RX_OFFS,
 				    hc->chan[hc->dnum[0]].jitter | V_RX_INIT);
-				HFC_outb(hc, R_TX_OFF,
+				HFC_outb(hc, R_TX_OFFS,
 				    hc->chan[hc->dnum[0]].jitter | V_RX_INIT);
 				hc->chan[hc->dnum[0]].sync = 1;
 				goto check_framesync;
@@ -2660,6 +2700,8 @@ fifo_irq(struct hfc_multi *hc, int block)
 
 	r_irq_fifo_bl = HFC_inb_nodebug(hc, R_IRQ_FIFO_BL0 + block);
 	j = 0;
+	printk(KERN_DEBUG "%s: block %d fifo_bl %02x\n", __func__,
+		block, r_irq_fifo_bl);
 	while (j < 8) {
 		ch = (block << 2) + (j >> 1);
 		dch = hc->chan[ch].dch;
@@ -2870,6 +2912,52 @@ hfcmulti_dbusy_timer(struct hfc_multi *hc)
 {
 }
 
+/* special mode to transmit/revceive full frame (all timeslots) in fifo 0 */
+
+static int set_2MBit_mode(struct hfc_multi *hc, int prot)
+{
+	u8 ch, lim;
+
+	for (ch = 0; ch < 64; ch++) {
+		/* Reset all fifo */
+		HFC_outb(hc, R_FIFO, ch);
+		HFC_wait(hc);
+		HFC_outb(hc, R_INC_RES_FIFO, 6);
+	}
+
+	HFC_outb(hc, R_FIRST_FIFO, 0x0);
+	lim = 63;
+	for (ch = 0; ch < 64; ch++) {
+		HFC_outb(hc, R_FSM_IDX, ch);
+		HFC_wait(hc);
+		HFC_outb(hc, A_CHANNEL, ch);
+		HFC_outb(hc, A_FIFO_SEQ, (ch + 1) % 2);
+		if (prot == ISDN_P_B_HDLC)
+			HFC_outb(hc, A_CON_HDLC, 0x4);
+		else
+			HFC_outb(hc, A_CON_HDLC, 0x6);
+		HFC_outb(hc, A_SUBCH_CFG, 0);
+		if (ch == lim)
+			break;
+	}
+	HFC_outb(hc, A_FIFO_SEQ, 0x40);
+
+	for (ch = 0; ch < 64; ch++) {
+		u8 ach, asc, ac, afs, ais, af1, af2;
+		HFC_outb(hc, R_FIFO, ch);
+		HFC_wait(hc);
+		ach = HFC_inb(hc, A_CON_HDLC);
+		asc = HFC_inb(hc, A_SUBCH_CFG);
+		ac = HFC_inb(hc,  A_CHANNEL);
+		afs = HFC_inb(hc, A_FIFO_SEQ);
+		ais = HFC_inb(hc, A_IRQ_MSK);
+		af1 = HFC_inb(hc, A_F1);
+		af2 = HFC_inb(hc, A_F2);
+		printk(KERN_DEBUG "R_FIFO %02d: %02x/%02x/%02x/%02x/%02x %d/%d\n",
+			ch, ach, asc, ac, afs, ais, af1, af2);
+	}
+	return 0;
+}
 
 /*
  * activate/deactivate hardware for selected channels and mode
@@ -3514,12 +3602,24 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb)
 		/* activate B-channel if not already activated */
 		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
 			hc->chan[bch->slot].txpending = 0;
-			ret = mode_hfcmulti(hc, bch->slot,
-					    ch->protocol,
-					    hc->chan[bch->slot].slot_tx,
-					    hc->chan[bch->slot].bank_tx,
-					    hc->chan[bch->slot].slot_rx,
-					    hc->chan[bch->slot].bank_rx);
+			if (test_bit(HFC_CHIP_2MBITRAW, &hc->chip)) {
+				ret = set_2MBit_mode(hc, ch->protocol);
+				/* The default content for these registers can
+				 * be changed via a MISDN_CTRL_L1_TS0_MODE ctrl
+				 * request
+				 */
+				HFC_outb(hc, R_RX_SL0_CFG0,
+					hc->hw.r_rx_sl0_cfg0);
+				HFC_outb(hc, R_TX_SL0_CFG1,
+					hc->hw.r_tx_sl0_cfg1);
+			} else {
+				ret = mode_hfcmulti(hc, bch->slot,
+					ch->protocol,
+					hc->chan[bch->slot].slot_tx,
+					hc->chan[bch->slot].bank_tx,
+					hc->chan[bch->slot].slot_rx,
+					hc->chan[bch->slot].bank_rx);
+			}
 			if (!ret) {
 				if (ch->protocol == ISDN_P_B_RAW && !hc->dtmf
 				    && test_bit(HFC_CHIP_DTMF, &hc->chip)) {
@@ -3591,11 +3691,13 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
 	int			slot_rx;
 	int			bank_rx;
 	int			num;
+	u8			v1, v2;
 
 	switch (cq->op) {
 	case MISDN_CTRL_GETOP:
-		cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP
-			| MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY;
+		cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP |
+			MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY |
+			MISDN_CTRL_L1_TESTS;
 		break;
 	case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
 		hc->chan[bch->slot].rx_off = !!cq->p1;
@@ -3702,6 +3804,38 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
 		else
 			ret = -EINVAL;
 		break;
+	case MISDN_CTRL_L1_TS0_MODE:
+		if (hc->ctype == HFC_TYPE_E1) {
+			v1 = hc->hw.r_rx_sl0_cfg0;
+			v2 = hc->hw.r_tx_sl0_cfg1;
+			if (cq->p1 > -1) {
+				hc->hw.r_rx_sl0_cfg0 = cq->p1 & 0xff;
+				HFC_outb(hc, R_RX_SL0_CFG0, cq->p1 & 0xff);
+				printk(KERN_DEBUG "RX_SL0_CFG0 = %x\n", cq->p1);
+			} else
+				printk(KERN_DEBUG "RX_SL0_CFG0 not modified\n");
+			if (cq->p2 > -1) {
+				hc->hw.r_tx_sl0_cfg1 = cq->p2 & 0xff;
+				HFC_outb(hc, R_TX_SL0_CFG1, cq->p2 & 0xff);
+				printk(KERN_DEBUG "TX_SL0_CFG1 = %x\n", cq->p2);
+			} else
+				printk(KERN_DEBUG "TX_SL0_CFG1 not modified\n");
+			cq->p1 = v1;
+			cq->p2 = v2;
+		} else {
+			printk(KERN_DEBUG "Not E1\n");
+			ret = -EINVAL;
+		}
+		break;
+	case MISDN_CTRL_L1_GET_SYNC_INFO:
+		cq->p1 = HFC_inb(hc, R_E1_RD_STA);
+		cq->p1 |= (HFC_inb(hc, R_SYNC_STA) << 8);
+		cq->p2 = HFC_inb(hc, R_RX_SL0_0);
+		cq->p2 |= (HFC_inb(hc, R_RX_SL0_1) << 8);
+		cq->p2 |= (HFC_inb(hc, R_RX_SL0_2) << 16);
+		cq->p3 = HFC_inb(hc, R_JATT_STA);
+		cq->p3 |= (HFC_inb(hc, R_SLIP) << 8);
+		break;
 	default:
 		printk(KERN_WARNING "%s: unknown Op %x\n",
 		       __func__, cq->op);
@@ -3776,6 +3910,12 @@ ph_state_change(struct dchannel *dch)
 		}
 		switch (dch->state) {
 		case (1):
+			if (test_bit(HFC_CHIP_2MBITRAW, &hc->chip)) {
+				if (debug & DEBUG_HFCMULTI_STATE)
+					printk(KERN_DEBUG
+						"2 MBIT Raw state 1 reached\n");
+				break;
+			}
 			if (hc->e1_state != 1) {
 				for (i = 1; i <= 31; i++) {
 					/* reset fifos on e1 activation */
@@ -3874,6 +4014,113 @@ ph_state_change(struct dchannel *dch)
 	}
 }
 
+int init_2MBit_mode(struct hfc_multi *hc, int nr)
+{
+	u_char		r_e1_wr_sta;
+	int		pt;
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: ch%d entered\n", __func__, nr);
+
+	if (nr != 0) {
+		printk(KERN_ERR "Only ch0 supports 2MBit card%d\n", hc->id);
+		return -EINVAL;
+	}
+
+	pt = hc->chan[nr].port;
+	if (pt != 0) {
+		printk(KERN_ERR "Only port 0 in 2MBit mode %d\n", hc->id);
+		return -EINVAL;
+	}
+
+	hc->chan[nr].slot_tx = -1;
+	hc->chan[nr].slot_rx = -1;
+	hc->chan[nr].conf = -1;
+	mode_hfcmulti(hc, nr, ISDN_P_NONE, -1, 0, -1, 0);
+
+	if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[nr].cfg)) {
+		HFC_outb(hc, R_LOS0, 255); /* 2 ms */
+		HFC_outb(hc, R_LOS1, 255); /* 512 ms */
+	}
+	if (test_bit(HFC_CFG_OPTICAL, &hc->chan[nr].cfg)) {
+		HFC_outb(hc, R_RX0, 0);
+		hc->hw.r_tx0 = 0 | V_OUT_EN;
+	} else {
+		HFC_outb(hc, R_RX0, 1);
+		hc->hw.r_tx0 = 1 | V_OUT_EN;
+	}
+	hc->hw.r_tx1 = V_ATX | V_NTRI;
+	HFC_outb(hc, R_TX0, hc->hw.r_tx0);
+	HFC_outb(hc, R_TX1, hc->hw.r_tx1);
+	HFC_outb(hc, R_TX_SL0_CFG0, 0x00);
+	HFC_outb(hc, R_TX_SL0, 0xf8);
+
+	HFC_outb(hc, R_TX_SL0_CFG1, V_TX_MF | V_TX_E | V_NEG_E);
+	/* set transparent SL0 is set on ACTIVATE */
+	hc->hw.r_tx_sl0_cfg1 = V_TX_MF | V_TRP_SL0;
+
+	HFC_outb(hc, R_RX_SL0_CFG0, V_AUTO_RESYNC | V_AUTO_RECO | 0);
+
+	hc->hw.r_rx_sl0_cfg0 = 0x1;
+
+	if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg))
+		HFC_outb(hc, R_RX_SL0_CFG1, V_RX_MF | V_RX_MF_SYNC);
+
+	/* Default TE mode and clock from interface */
+	r_e1_wr_sta = 1;
+	hc->e1_getclock = 1;
+	if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip))
+		HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX);
+	else
+		HFC_outb(hc, R_SYNC_OUT, 0);
+
+	if (test_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip))
+		hc->e1_getclock = 1;
+	if (test_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip))
+		hc->e1_getclock = 0;
+	if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
+		/* SLAVE (clock master) */
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG
+			    "%s: E1 port is clock master (clock from PCM)\n",
+			    __func__);
+		HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC);
+	} else {
+		if (hc->e1_getclock) {
+			/* MASTER (clock slave) */
+			if (debug & DEBUG_HFCMULTI_INIT)
+				printk(KERN_DEBUG
+				       "%s: E1 port is clock slave (clock to PCM)\n",
+				       __func__);
+			HFC_outb(hc, R_SYNC_CTRL, 0);
+		} else {
+			/* MASTER (clock master) */
+			if (debug & DEBUG_HFCMULTI_INIT)
+				printk(KERN_DEBUG
+				       "%s: E1 port is clock master (clock from QUARTZ)\n",
+				       __func__);
+			HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC |
+			    V_PCM_SYNC | V_JATT_OFF);
+			HFC_outb(hc, R_SYNC_OUT, 0);
+		}
+	}
+	HFC_outb(hc, R_JATT_CFG, 0x9c);
+	HFC_outb(hc, R_PWM_MD, V_PWM0_MD);
+	HFC_outb(hc, R_PWM0, 0x50);
+	HFC_outb(hc, R_PWM1, 0xff);
+
+	/* state machine setup */
+	HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta | V_E1_LD_STA);
+	udelay(10); /* wait at least 5,21us */
+	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
+		hc->syncronized = 0;
+		plxsd_checksync(hc, 0);
+	}
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk("%s: done\n", __func__);
+	return 0;
+}
+
 /*
  * called for card mode init message
  */
@@ -3928,16 +4175,19 @@ hfcmulti_initmode(struct dchannel *dch)
 		hc->hw.r_tx1 = V_ATX | V_NTRI;
 		HFC_outb(hc, R_TX0, hc->hw.r_tx0);
 		HFC_outb(hc, R_TX1, hc->hw.r_tx1);
-		HFC_outb(hc, R_TX_FR0, 0x00);
-		HFC_outb(hc, R_TX_FR1, 0xf8);
+		HFC_outb(hc, R_TX_SL0_CFG0, 0x00);
+		HFC_outb(hc, R_TX_SL0, 0xf8);
 
-		if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg))
-			HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E);
+		if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg)) {
+			hc->hw.r_tx_sl0_cfg1 = V_TX_MF | V_TX_E | V_NEG_E;
+			HFC_outb(hc, R_TX_SL0_CFG1, hc->hw.r_tx_sl0_cfg1);
+		}
 
-		HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0);
+		hc->hw.r_rx_sl0_cfg0 = V_AUTO_RESYNC | V_AUTO_RECO;
+		HFC_outb(hc, R_RX_SL0_CFG0, hc->hw.r_rx_sl0_cfg0);
 
 		if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg))
-			HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC);
+			HFC_outb(hc, R_RX_SL0_CFG1, V_RX_MF | V_RX_MF_SYNC);
 
 		if (dch->dev.D.protocol == ISDN_P_NT_E1) {
 			if (debug & DEBUG_HFCMULTI_INIT)
@@ -3987,7 +4237,7 @@ hfcmulti_initmode(struct dchannel *dch)
 				HFC_outb(hc, R_SYNC_OUT, 0);
 			}
 		}
-		HFC_outb(hc, R_JATT_ATT, 0x9c); /* undoc register */
+		HFC_outb(hc, R_JATT_CFG, 0x9c); /* undoc register */
 		HFC_outb(hc, R_PWM_MD, V_PWM0_MD);
 		HFC_outb(hc, R_PWM0, 0x50);
 		HFC_outb(hc, R_PWM1, 0xff);
@@ -4086,6 +4336,9 @@ open_dchannel(struct hfc_multi *hc, struct dchannel *dch,
 	if (debug & DEBUG_HW_OPEN)
 		printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__,
 		       dch->dev.id, __builtin_return_address(0));
+	if (test_bit(HFC_CHIP_2MBITRAW, &hc->chip) &&
+	    (hc->ctype == HFC_TYPE_E1)) /* No Dchannel in this mode */
+		return -EINVAL;
 	if (rq->protocol == ISDN_P_NONE)
 		return -EINVAL;
 	if ((dch->dev.D.protocol != ISDN_P_NONE) &&
@@ -4122,15 +4375,20 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch,
 	      struct channel_req *rq)
 {
 	struct bchannel	*bch;
-	int		ch;
+	int		ret, ch;
 
 	if (!test_channelmap(rq->adr.channel, dch->dev.channelmap))
 		return -EINVAL;
 	if (rq->protocol == ISDN_P_NONE)
 		return -EINVAL;
-	if (hc->ctype == HFC_TYPE_E1)
+	if (hc->ctype == HFC_TYPE_E1) {
 		ch = rq->adr.channel;
-	else
+		if (test_bit(HFC_CHIP_2MBITRAW, &hc->chip)) {
+			ret = init_2MBit_mode(hc, ch);
+			if (ret)
+				return ret;
+		}
+	} else
 		ch = (rq->adr.channel - 1) + (dch->slot - 2);
 	bch = hc->chan[ch].bch;
 	if (!bch) {
@@ -4141,6 +4399,7 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch,
 	if (test_and_set_bit(FLG_OPEN, &bch->Flags))
 		return -EBUSY; /* b-channel can be only open once */
 	test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+
 	bch->ch.protocol = rq->protocol;
 	hc->chan[ch].rx_off = 0;
 	rq->ch = &bch->ch;
@@ -4158,10 +4417,11 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
 	struct hfc_multi	*hc = dch->hw;
 	int	ret = 0;
 	int	wd_mode, wd_cnt;
+	u_char	reg, reg1;
 
 	switch (cq->op) {
 	case MISDN_CTRL_GETOP:
-		cq->op = MISDN_CTRL_HFC_OP;
+		cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_L1_TESTS;
 		break;
 	case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */
 		wd_cnt = cq->p1 & 0xf;
@@ -4191,6 +4451,42 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
 			       __func__);
 		HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES);
 		break;
+	case MISDN_CTRL_L1_STATE_TEST:
+		if (hc->ctype == HFC_TYPE_E1) {
+			/* undocumented: status changes during read */
+			reg = HFC_inb_nodebug(hc, R_E1_RD_STA);
+			while (reg != (reg1 =
+				HFC_inb_nodebug(hc, R_E1_RD_STA))) {
+				if (debug & DEBUG_HFCMULTI_STATE)
+					printk(KERN_DEBUG
+					       "%s: reread STATE because %d!=%d\n",
+					       __func__, reg, reg1);
+				reg = reg1; /* repeat */
+			}
+			printk(KERN_DEBUG "Old L1 state %02x\n", reg);
+			reg &= 0x07;
+			if (cq->p1 < 0 || cq->p1 > 6) /* reset auto mode */
+				HFC_outb(hc, R_E1_WR_STA, reg);
+			else {/* force new state state */
+				reg = cq->p1 & 0x07;
+				HFC_outb(hc, R_E1_WR_STA, reg | V_E1_LD_STA);
+				printk(KERN_DEBUG "New L1 state %02x\n", reg);
+			}
+		} else
+			ret = -EINVAL;
+		break;
+	case MISDN_CTRL_L1_AIS_TEST:
+		if (hc->ctype == HFC_TYPE_E1) {
+			printk(KERN_DEBUG "Old AIS state %02x\n", hc->hw.r_tx1);
+			if (cq->p1)
+				hc->hw.r_tx1 |= V_AIS_OUT;
+			else
+				hc->hw.r_tx1 &= ~V_AIS_OUT;
+			HFC_outb(hc, R_TX1, hc->hw.r_tx1);
+			printk(KERN_DEBUG "New AIS state %02x\n", hc->hw.r_tx1);
+		} else
+			ret = -EINVAL;
+		break;
 	default:
 		printk(KERN_WARNING "%s: unknown Op %x\n",
 		       __func__, cq->op);
@@ -4843,7 +5139,18 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt)
 	dch->debug = debug;
 	mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change);
 	dch->hw = hc;
-	dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1);
+	if (port[Port_cnt] & 0x0002) {
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG
+			       "%s: PORT 2MBit raw mode E1: card(%d) port(%d)\n",
+			       __func__, HFC_cnt + 1, 1);
+		test_and_set_bit(HFC_CHIP_2MBITRAW, &hc->chip);
+		dch->dev.Dprotocols = (1 << ISDN_P_NONE);
+		hc->dnum[pt] = 0;
+		hc->bmask[pt] = 1;
+	} else
+		dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1);
+
 	dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
 	    (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
 	dch->dev.D.send = handle_dmsg;
@@ -4852,8 +5159,9 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt)
 	hc->chan[hc->dnum[pt]].dch = dch;
 	hc->chan[hc->dnum[pt]].port = pt;
 	hc->chan[hc->dnum[pt]].nt_timer = -1;
-	for (ch = 1; ch <= 31; ch++) {
-		if (!((1 << ch) & hc->bmask[pt])) /* skip unused channel */
+	for (ch = 0; ch <= 31; ch++) {
+		/* skip unused channel */
+		if (!((1 << ch) & hc->bmask[pt]))
 			continue;
 		bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL);
 		if (!bch) {
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index f474f40..850fe1f 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
  */
 #define	MISDN_MAJOR_VERSION	1
 #define	MISDN_MINOR_VERSION	1
-#define MISDN_RELEASE		28
+#define MISDN_RELEASE		29
 
 /* primitives for information exchange
  * generell format
@@ -363,31 +363,36 @@ clear_channelmap(u_int nr, u_char *map)
 }
 
 /* CONTROL_CHANNEL parameters */
-#define MISDN_CTRL_GETOP		0x0000
-#define MISDN_CTRL_LOOP			0x0001
-#define MISDN_CTRL_CONNECT		0x0002
-#define MISDN_CTRL_DISCONNECT		0x0004
-#define MISDN_CTRL_GET_PCM_SLOTS	0x0010
-#define MISDN_CTRL_SET_PCM_SLOTS	0x0020
-#define MISDN_CTRL_SETPEER		0x0040
-#define MISDN_CTRL_UNSETPEER		0x0080
-#define MISDN_CTRL_RX_OFF		0x0100
-#define MISDN_CTRL_FILL_EMPTY		0x0200
-#define MISDN_CTRL_GETPEER		0x0400
-#define MISDN_CTRL_L1_TIMER3		0x0800
-#define MISDN_CTRL_HW_FEATURES_OP	0x2000
-#define MISDN_CTRL_HW_FEATURES		0x2001
-#define MISDN_CTRL_HFC_OP		0x4000
-#define MISDN_CTRL_HFC_PCM_CONN		0x4001
-#define MISDN_CTRL_HFC_PCM_DISC		0x4002
-#define MISDN_CTRL_HFC_CONF_JOIN	0x4003
-#define MISDN_CTRL_HFC_CONF_SPLIT	0x4004
-#define MISDN_CTRL_HFC_RECEIVE_OFF	0x4005
-#define MISDN_CTRL_HFC_RECEIVE_ON	0x4006
-#define MISDN_CTRL_HFC_ECHOCAN_ON 	0x4007
-#define MISDN_CTRL_HFC_ECHOCAN_OFF 	0x4008
-#define MISDN_CTRL_HFC_WD_INIT		0x4009
-#define MISDN_CTRL_HFC_WD_RESET		0x400A
+#define MISDN_CTRL_GETOP		0x00000000
+#define MISDN_CTRL_LOOP			0x00000001
+#define MISDN_CTRL_CONNECT		0x00000002
+#define MISDN_CTRL_DISCONNECT		0x00000004
+#define MISDN_CTRL_GET_PCM_SLOTS	0x00000010
+#define MISDN_CTRL_SET_PCM_SLOTS	0x00000020
+#define MISDN_CTRL_SETPEER		0x00000040
+#define MISDN_CTRL_UNSETPEER		0x00000080
+#define MISDN_CTRL_RX_OFF		0x00000100
+#define MISDN_CTRL_FILL_EMPTY		0x00000200
+#define MISDN_CTRL_GETPEER		0x00000400
+#define MISDN_CTRL_L1_TIMER3		0x00000800
+#define MISDN_CTRL_HW_FEATURES_OP	0x00002000
+#define MISDN_CTRL_HW_FEATURES		0x00002001
+#define MISDN_CTRL_HFC_OP		0x00004000
+#define MISDN_CTRL_HFC_PCM_CONN		0x00004001
+#define MISDN_CTRL_HFC_PCM_DISC		0x00004002
+#define MISDN_CTRL_HFC_CONF_JOIN	0x00004003
+#define MISDN_CTRL_HFC_CONF_SPLIT	0x00004004
+#define MISDN_CTRL_HFC_RECEIVE_OFF	0x00004005
+#define MISDN_CTRL_HFC_RECEIVE_ON	0x00004006
+#define MISDN_CTRL_HFC_ECHOCAN_ON	0x00004007
+#define MISDN_CTRL_HFC_ECHOCAN_OFF	0x00004008
+#define MISDN_CTRL_HFC_WD_INIT		0x00004009
+#define MISDN_CTRL_HFC_WD_RESET		0x0000400A
+#define MISDN_CTRL_L1_TESTS		0x00010000
+#define MISDN_CTRL_L1_STATE_TEST	0x00010001
+#define MISDN_CTRL_L1_AIS_TEST		0x00010002
+#define MISDN_CTRL_L1_TS0_MODE		0x00010003
+#define MISDN_CTRL_L1_GET_SYNC_INFO	0x00010004
 
 /* special PCM slot numbers */
 #define MISDN_PCM_SLOT_DISABLE	-1	/* PCM disabled */
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 19/28] mISDN: Early confirm for transparent data
From: Karsten Keil @ 2012-04-21 15:11 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

It is better to send a confirm early, less TX underuns will
happen.

Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
 drivers/isdn/hardware/mISDN/avmfritz.c  |    7 ++-----
 drivers/isdn/hardware/mISDN/hfcmulti.c  |    9 ++-------
 drivers/isdn/hardware/mISDN/hfcpci.c    |    7 ++-----
 drivers/isdn/hardware/mISDN/hfcsusb.c   |    6 ------
 drivers/isdn/hardware/mISDN/mISDNipac.c |    7 ++-----
 drivers/isdn/hardware/mISDN/mISDNisar.c |    7 ++-----
 drivers/isdn/hardware/mISDN/netjet.c    |    7 ++-----
 drivers/isdn/hardware/mISDN/w6692.c     |    7 ++-----
 drivers/isdn/mISDN/hwchannel.c          |    5 +++--
 9 files changed, 17 insertions(+), 45 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index e76e1ba..c773a7f 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -670,11 +670,8 @@ avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
 			id = hh->id; /* skb can be freed */
 			hdlc_fill_fifo(bch);
 			ret = 0;
-			spin_unlock_irqrestore(&fc->lock, flags);
-			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
-				queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
-		} else
-			spin_unlock_irqrestore(&fc->lock, flags);
+		}
+		spin_unlock_irqrestore(&fc->lock, flags);
 		return ret;
 	case PH_ACTIVATE_REQ:
 		spin_lock_irqsave(&fc->lock, flags);
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index e91f82a..d826586 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -3586,13 +3586,8 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb)
 			/* start fifo */
 			HFC_outb_nodebug(hc, R_FIFO, 0);
 			HFC_wait_nodebug(hc);
-			if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) {
-				spin_unlock_irqrestore(&hc->lock, flags);
-				queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
-			} else
-				spin_unlock_irqrestore(&hc->lock, flags);
-		} else
-			spin_unlock_irqrestore(&hc->lock, flags);
+		}
+		spin_unlock_irqrestore(&hc->lock, flags);
 		return ret;
 	case PH_ACTIVATE_REQ:
 		if (debug & DEBUG_HFCMULTI_MSG)
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 9262136..6a0d964 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -1702,11 +1702,8 @@ hfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
 			id = hh->id; /* skb can be freed */
 			hfcpci_fill_fifo(bch);
 			ret = 0;
-			spin_unlock_irqrestore(&hc->lock, flags);
-			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
-				queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
-		} else
-			spin_unlock_irqrestore(&hc->lock, flags);
+		}
+		spin_unlock_irqrestore(&hc->lock, flags);
 		return ret;
 	case PH_ACTIVATE_REQ:
 		spin_lock_irqsave(&hc->lock, flags);
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index add28ac..404184a 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -227,12 +227,6 @@ hfcusb_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
 			printk(KERN_DEBUG "%s: %s PH_DATA_REQ ret(%i)\n",
 			       hw->name, __func__, ret);
 		if (ret > 0) {
-			/*
-			 * other l1 drivers don't send early confirms on
-			 * transp data, but hfcsusb does because tx_next
-			 * skb is needed in tx_iso_complete()
-			 */
-			queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL);
 			ret = 0;
 		}
 		return ret;
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
index 4c1937b..d301d8c 100644
--- a/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -1349,11 +1349,8 @@ hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
 			id = hh->id; /* skb can be freed */
 			ret = 0;
 			hscx_fill_fifo(hx);
-			spin_unlock_irqrestore(hx->ip->hwlock, flags);
-			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
-				queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
-		} else
-			spin_unlock_irqrestore(hx->ip->hwlock, flags);
+		}
+		spin_unlock_irqrestore(hx->ip->hwlock, flags);
 		return ret;
 	case PH_ACTIVATE_REQ:
 		spin_lock_irqsave(hx->ip->hwlock, flags);
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
index af9a966..8db914a 100644
--- a/drivers/isdn/hardware/mISDN/mISDNisar.c
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -1490,11 +1490,8 @@ isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
 			id = hh->id; /* skb can be freed */
 			ret = 0;
 			isar_fill_fifo(ich);
-			spin_unlock_irqrestore(ich->is->hwlock, flags);
-			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
-				queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
-		} else
-			spin_unlock_irqrestore(ich->is->hwlock, flags);
+		}
+		spin_unlock_irqrestore(ich->is->hwlock, flags);
 		return ret;
 	case PH_ACTIVATE_REQ:
 		spin_lock_irqsave(ich->is->hwlock, flags);
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
index 0dccda8..fd421e7 100644
--- a/drivers/isdn/hardware/mISDN/netjet.c
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -743,11 +743,8 @@ nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
 			id = hh->id; /* skb can be freed */
 			fill_dma(bc);
 			ret = 0;
-			spin_unlock_irqrestore(&card->lock, flags);
-			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
-				queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
-		} else
-			spin_unlock_irqrestore(&card->lock, flags);
+		}
+		spin_unlock_irqrestore(&card->lock, flags);
 		return ret;
 	case PH_ACTIVATE_REQ:
 		spin_lock_irqsave(&card->lock, flags);
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
index dec013e1..0424652 100644
--- a/drivers/isdn/hardware/mISDN/w6692.c
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -955,11 +955,8 @@ w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
 			id = hh->id; /* skb can be freed */
 			ret = 0;
 			W6692_fill_Bfifo(bc);
-			spin_unlock_irqrestore(&card->lock, flags);
-			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
-				queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
-		} else
-			spin_unlock_irqrestore(&card->lock, flags);
+		}
+		spin_unlock_irqrestore(&card->lock, flags);
 		return ret;
 	case PH_ACTIVATE_REQ:
 		spin_lock_irqsave(&card->lock, flags);
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index c74c363..a250244 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -305,8 +305,8 @@ get_next_bframe(struct bchannel *bch)
 		if (bch->tx_skb) {
 			bch->next_skb = NULL;
 			test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
-			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
-				confirm_Bsend(bch); /* not for transparent */
+			/* confirm imediately to allow next data */
+			confirm_Bsend(bch);
 			return 1;
 		} else {
 			test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
@@ -395,6 +395,7 @@ bchannel_senddata(struct bchannel *ch, struct sk_buff *skb)
 		/* write to fifo */
 		ch->tx_skb = skb;
 		ch->tx_idx = 0;
+		confirm_Bsend(ch);
 		return 1;
 	}
 }
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 18/28] mISDN: Cleanup channel also if it already was deactivated
From: Karsten Keil @ 2012-03-18 13:50 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

If a channel was closed after it was deactivated it
could happen that something was not proper resetted.

Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
 drivers/isdn/hardware/mISDN/avmfritz.c  |   12 ++++--------
 drivers/isdn/hardware/mISDN/hfcmulti.c  |    3 +--
 drivers/isdn/hardware/mISDN/hfcpci.c    |    3 +--
 drivers/isdn/hardware/mISDN/hfcsusb.c   |    3 +--
 drivers/isdn/hardware/mISDN/mISDNipac.c |   13 ++++---------
 drivers/isdn/hardware/mISDN/mISDNisar.c |   13 ++++---------
 drivers/isdn/hardware/mISDN/netjet.c    |   12 ++++--------
 drivers/isdn/hardware/mISDN/w6692.c     |   13 ++++---------
 8 files changed, 23 insertions(+), 49 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index c0b8c96..e76e1ba 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -839,14 +839,10 @@ avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
 	switch (cmd) {
 	case CLOSE_CHANNEL:
 		test_and_clear_bit(FLG_OPEN, &bch->Flags);
-		if (test_bit(FLG_ACTIVE, &bch->Flags)) {
-			spin_lock_irqsave(&fc->lock, flags);
-			mISDN_freebchannel(bch);
-			test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
-			test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
-			modehdlc(bch, ISDN_P_NONE);
-			spin_unlock_irqrestore(&fc->lock, flags);
-		}
+		spin_lock_irqsave(&fc->lock, flags);
+		mISDN_freebchannel(bch);
+		modehdlc(bch, ISDN_P_NONE);
+		spin_unlock_irqrestore(&fc->lock, flags);
 		ch->protocol = ISDN_P_NONE;
 		ch->peer = NULL;
 		module_put(THIS_MODULE);
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 4ae6f8e..e91f82a 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -3859,8 +3859,7 @@ hfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
 	switch (cmd) {
 	case CLOSE_CHANNEL:
 		test_and_clear_bit(FLG_OPEN, &bch->Flags);
-		if (test_bit(FLG_ACTIVE, &bch->Flags))
-			deactivate_bchannel(bch); /* locked there */
+		deactivate_bchannel(bch); /* locked there */
 		ch->protocol = ISDN_P_NONE;
 		ch->peer = NULL;
 		module_put(THIS_MODULE);
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index e2c83a2..9262136 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -1581,8 +1581,7 @@ hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
 		break;
 	case CLOSE_CHANNEL:
 		test_and_clear_bit(FLG_OPEN, &bch->Flags);
-		if (test_bit(FLG_ACTIVE, &bch->Flags))
-			deactivate_bchannel(bch);
+		deactivate_bchannel(bch);
 		ch->protocol = ISDN_P_NONE;
 		ch->peer = NULL;
 		module_put(THIS_MODULE);
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 8cde2a0..add28ac 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -1836,8 +1836,7 @@ hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
 
 	case CLOSE_CHANNEL:
 		test_and_clear_bit(FLG_OPEN, &bch->Flags);
-		if (test_bit(FLG_ACTIVE, &bch->Flags))
-			deactivate_bchannel(bch);
+		deactivate_bchannel(bch);
 		ch->protocol = ISDN_P_NONE;
 		ch->peer = NULL;
 		module_put(THIS_MODULE);
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
index 884369f..4c1937b 100644
--- a/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -1416,15 +1416,10 @@ hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
 	switch (cmd) {
 	case CLOSE_CHANNEL:
 		test_and_clear_bit(FLG_OPEN, &bch->Flags);
-		if (test_bit(FLG_ACTIVE, &bch->Flags)) {
-			spin_lock_irqsave(hx->ip->hwlock, flags);
-			mISDN_freebchannel(bch);
-			hscx_mode(hx, ISDN_P_NONE);
-			spin_unlock_irqrestore(hx->ip->hwlock, flags);
-		} else {
-			skb_queue_purge(&bch->rqueue);
-			bch->rcount = 0;
-		}
+		spin_lock_irqsave(hx->ip->hwlock, flags);
+		mISDN_freebchannel(bch);
+		hscx_mode(hx, ISDN_P_NONE);
+		spin_unlock_irqrestore(hx->ip->hwlock, flags);
 		ch->protocol = ISDN_P_NONE;
 		ch->peer = NULL;
 		module_put(hx->ip->owner);
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
index 9a6da6e..af9a966 100644
--- a/drivers/isdn/hardware/mISDN/mISDNisar.c
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -1603,15 +1603,10 @@ isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
 	switch (cmd) {
 	case CLOSE_CHANNEL:
 		test_and_clear_bit(FLG_OPEN, &bch->Flags);
-		if (test_bit(FLG_ACTIVE, &bch->Flags)) {
-			spin_lock_irqsave(ich->is->hwlock, flags);
-			mISDN_freebchannel(bch);
-			modeisar(ich, ISDN_P_NONE);
-			spin_unlock_irqrestore(ich->is->hwlock, flags);
-		} else {
-			skb_queue_purge(&bch->rqueue);
-			bch->rcount = 0;
-		}
+		spin_lock_irqsave(ich->is->hwlock, flags);
+		mISDN_freebchannel(bch);
+		modeisar(ich, ISDN_P_NONE);
+		spin_unlock_irqrestore(ich->is->hwlock, flags);
 		ch->protocol = ISDN_P_NONE;
 		ch->peer = NULL;
 		module_put(ich->is->owner);
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
index c726e09..0dccda8 100644
--- a/drivers/isdn/hardware/mISDN/netjet.c
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -808,14 +808,10 @@ nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
 	switch (cmd) {
 	case CLOSE_CHANNEL:
 		test_and_clear_bit(FLG_OPEN, &bch->Flags);
-		if (test_bit(FLG_ACTIVE, &bch->Flags)) {
-			spin_lock_irqsave(&card->lock, flags);
-			mISDN_freebchannel(bch);
-			test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
-			test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
-			mode_tiger(bc, ISDN_P_NONE);
-			spin_unlock_irqrestore(&card->lock, flags);
-		}
+		spin_lock_irqsave(&card->lock, flags);
+		mISDN_freebchannel(bch);
+		mode_tiger(bc, ISDN_P_NONE);
+		spin_unlock_irqrestore(&card->lock, flags);
 		ch->protocol = ISDN_P_NONE;
 		ch->peer = NULL;
 		module_put(THIS_MODULE);
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
index 2183357..dec013e1 100644
--- a/drivers/isdn/hardware/mISDN/w6692.c
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -1058,15 +1058,10 @@ w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
 	switch (cmd) {
 	case CLOSE_CHANNEL:
 		test_and_clear_bit(FLG_OPEN, &bch->Flags);
-		if (test_bit(FLG_ACTIVE, &bch->Flags)) {
-			spin_lock_irqsave(&card->lock, flags);
-			mISDN_freebchannel(bch);
-			w6692_mode(bc, ISDN_P_NONE);
-			spin_unlock_irqrestore(&card->lock, flags);
-		} else {
-			skb_queue_purge(&bch->rqueue);
-			bch->rcount = 0;
-		}
+		spin_lock_irqsave(&card->lock, flags);
+		mISDN_freebchannel(bch);
+		w6692_mode(bc, ISDN_P_NONE);
+		spin_unlock_irqrestore(&card->lock, flags);
 		ch->protocol = ISDN_P_NONE;
 		ch->peer = NULL;
 		module_put(THIS_MODULE);
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 23/28] mISDN: Fix compiler warnings
From: Karsten Keil @ 2012-04-21 15:49 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

Newer gcc found some possible uninitialized pointer access.

Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
 drivers/isdn/hardware/mISDN/avmfritz.c |   11 +++++------
 drivers/isdn/hardware/mISDN/hfcmulti.c |    8 ++++----
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index 3781446..d0bdde3 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -404,7 +404,7 @@ static void
 hdlc_empty_fifo(struct bchannel *bch, int count)
 {
 	u32 *ptr;
-	u8 *p, copy;
+	u8 *p;
 	u32  val, addr;
 	int cnt;
 	struct fritzcard *fc = bch->hw;
@@ -412,13 +412,12 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
 	pr_debug("%s: %s %d\n", fc->name, __func__, count);
 	if (test_bit(FLG_RX_OFF, &bch->Flags)) {
 		/* We drop the content, but need to read all bytes from FIFO */
-		copy = 0;
+		p = NULL;
 		if (debug & DEBUG_HW_BFIFO)
 			printk(KERN_DEBUG "Dropped %d bytes - RX off\n", count);
 		val = (bch->nr - 1) & 1;
 		fc->dropcnt[val] += count;
 	} else {
-		copy = 1;
 		if (!bch->rx_skb) {
 			if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
 				if (count >= bch->minlen)
@@ -441,8 +440,8 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
 			return;
 		}
 		p = skb_put(bch->rx_skb, count);
-		ptr = (u32 *)p;
 	}
+	ptr = (u32 *)p;
 	if (AVM_FRITZ_PCIV2 == fc->type)
 		addr = fc->addr + (bch->nr == 2 ?
 				   AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
@@ -453,13 +452,13 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
 	cnt = 0;
 	while (cnt < count) {
 		val = le32_to_cpu(inl(addr));
-		if (copy) {
+		if (ptr) {
 			put_unaligned(val, ptr);
 			ptr++;
 		}
 		cnt += 4;
 	}
-	if (copy && (debug & DEBUG_HW_BFIFO)) {
+	if (ptr && (debug & DEBUG_HW_BFIFO)) {
 		snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ",
 			 bch->nr, fc->name, count);
 		print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 884c090..144c35a 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -2456,12 +2456,12 @@ handle_timer_irq(struct hfc_multi *hc)
 		spin_unlock_irqrestore(&HFClock, flags);
 	}
 	if (test_bit(HFC_CHIP_2MBITRAW, &hc->chip)) {
-		if (hc->created[hc->chan[0].port] && hc->chan[ch].bch &&
+		ch = 0;
+		if (hc->created[hc->chan[ch].port] && hc->chan[ch].bch &&
 		    test_bit(FLG_ACTIVE, &hc->chan[ch].bch->Flags)) {
 			ch_activ++;
-			hfcmulti_tx(hc, 0);
-			hfcmulti_rx(hc, 0);
-			ch = 1;
+			hfcmulti_tx(hc, ch);
+			hfcmulti_rx(hc, ch);
 			if (hc->chan[ch].dch &&
 			    hc->chan[ch].nt_timer > -1) {
 				dch = hc->chan[ch].dch;
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 20/28] mISDN: Allow the driver to set a minimum length for transparent data
From: Karsten Keil @ 2012-04-21 15:19 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

This is usefull for better flow control and will
avoid very short messages to upper layer.

Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
 drivers/isdn/hardware/mISDN/avmfritz.c  |   88 +++++++++++++++++++++----------
 drivers/isdn/hardware/mISDN/hfcmulti.c  |    4 +-
 drivers/isdn/hardware/mISDN/hfcpci.c    |    2 +-
 drivers/isdn/hardware/mISDN/hfcsusb.c   |    2 +-
 drivers/isdn/hardware/mISDN/mISDNipac.c |   25 ++++++---
 drivers/isdn/hardware/mISDN/mISDNisar.c |    2 +-
 drivers/isdn/hardware/mISDN/netjet.c    |    2 +-
 drivers/isdn/hardware/mISDN/w6692.c     |    2 +-
 drivers/isdn/mISDN/hwchannel.c          |    3 +-
 drivers/isdn/mISDN/l1oip_core.c         |    2 +-
 include/linux/mISDNhw.h                 |    3 +-
 11 files changed, 90 insertions(+), 45 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index c773a7f..4b1c86e 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -30,7 +30,7 @@
 #include "ipac.h"
 
 
-#define AVMFRITZ_REV	"2.1"
+#define AVMFRITZ_REV	"2.2"
 
 static int AVM_cnt;
 static int debug;
@@ -69,7 +69,8 @@ enum {
 #define HDLC_MODE_TRANS		0x02
 #define HDLC_MODE_CCR_7		0x04
 #define HDLC_MODE_CCR_16	0x08
-#define HDLC_MODE_TESTLOOP	0x80
+#define HDLC_FIFO_SIZE_128	0x20
+#define HDLC_MODE_TESTLOOP_V1	0x80
 
 #define HDLC_INT_XPR		0x80
 #define HDLC_INT_XDU		0x40
@@ -80,13 +81,16 @@ enum {
 #define HDLC_STAT_RDO		0x10
 #define HDLC_STAT_CRCVFRRAB	0x0E
 #define HDLC_STAT_CRCVFR	0x06
-#define HDLC_STAT_RML_MASK	0x3f00
+#define HDLC_STAT_RML_MASK_V1	0x3f00
+#define HDLC_STAT_RML_MASK_V2	0x7f00
 
 #define HDLC_CMD_XRS		0x80
 #define HDLC_CMD_XME		0x01
 #define HDLC_CMD_RRS		0x20
 #define HDLC_CMD_XML_MASK	0x3f00
-#define HDLC_FIFO_SIZE		32
+
+#define HDLC_FIFO_SIZE_V1	32
+#define HDLC_FIFO_SIZE_V2	128
 
 /* Fritz PCI v2.0 */
 
@@ -346,11 +350,14 @@ modehdlc(struct bchannel *bch, int protocol)
 {
 	struct fritzcard *fc = bch->hw;
 	struct hdlc_hw *hdlc;
+	u8 mode;
 
 	hdlc = &fc->hdlc[(bch->nr - 1) & 1];
 	pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name,
 		 '@' + bch->nr, bch->state, protocol, bch->nr);
 	hdlc->ctrl.ctrl = 0;
+	mode = (AVM_FRITZ_PCIV2 == fc->type) ? HDLC_FIFO_SIZE_128 : 0;
+
 	switch (protocol) {
 	case -1: /* used for init */
 		bch->state = -1;
@@ -358,7 +365,7 @@ modehdlc(struct bchannel *bch, int protocol)
 		if (bch->state == ISDN_P_NONE)
 			break;
 		hdlc->ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
-		hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
+		hdlc->ctrl.sr.mode = mode | HDLC_MODE_TRANS;
 		write_ctrl(bch, 5);
 		bch->state = ISDN_P_NONE;
 		test_and_clear_bit(FLG_HDLC, &bch->Flags);
@@ -367,7 +374,7 @@ modehdlc(struct bchannel *bch, int protocol)
 	case ISDN_P_B_RAW:
 		bch->state = protocol;
 		hdlc->ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
-		hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
+		hdlc->ctrl.sr.mode = mode | HDLC_MODE_TRANS;
 		write_ctrl(bch, 5);
 		hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
 		write_ctrl(bch, 1);
@@ -377,7 +384,7 @@ modehdlc(struct bchannel *bch, int protocol)
 	case ISDN_P_B_HDLC:
 		bch->state = protocol;
 		hdlc->ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
-		hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
+		hdlc->ctrl.sr.mode = mode | HDLC_MODE_ITF_FLG;
 		write_ctrl(bch, 5);
 		hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
 		write_ctrl(bch, 1);
@@ -397,21 +404,29 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
 	u32 *ptr;
 	u8 *p;
 	u32  val, addr;
-	int cnt = 0;
+	int cnt;
 	struct fritzcard *fc = bch->hw;
 
 	pr_debug("%s: %s %d\n", fc->name, __func__, count);
 	if (!bch->rx_skb) {
-		bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC);
+		if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+			if (count >= bch->minlen)
+				cnt = count;
+			else
+				cnt = 2 * bch->minlen;
+		} else
+			cnt = bch->maxlen;
+		bch->rx_skb = mI_alloc_skb(cnt, GFP_ATOMIC);
 		if (!bch->rx_skb) {
 			pr_info("%s: B receive out of memory\n",
 				fc->name);
 			return;
 		}
-	}
-	if ((bch->rx_skb->len + count) > bch->maxlen) {
-		pr_debug("%s: overrun %d\n", fc->name,
-			 bch->rx_skb->len + count);
+	} else
+		cnt = skb_tailroom(bch->rx_skb);
+	if (count > cnt) {
+		pr_debug("%s: overrun %d + %d free %d\n", fc->name,
+			bch->rx_skb->len, count, cnt);
 		return;
 	}
 	p = skb_put(bch->rx_skb, count);
@@ -423,6 +438,7 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
 		addr = fc->addr + CHIP_WINDOW;
 		outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr);
 	}
+	cnt = 0;
 	while (cnt < count) {
 		val = le32_to_cpu(inl(addr));
 		put_unaligned(val, ptr);
@@ -441,7 +457,7 @@ hdlc_fill_fifo(struct bchannel *bch)
 {
 	struct fritzcard *fc = bch->hw;
 	struct hdlc_hw *hdlc;
-	int count, cnt = 0;
+	int count, fs, cnt = 0;
 	u8 *p;
 	u32 *ptr, val, addr;
 
@@ -451,10 +467,12 @@ hdlc_fill_fifo(struct bchannel *bch)
 	count = bch->tx_skb->len - bch->tx_idx;
 	if (count <= 0)
 		return;
+	fs = (fc->type == AVM_FRITZ_PCIV2) ?
+		HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1;
 	p = bch->tx_skb->data + bch->tx_idx;
 	hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
-	if (count > HDLC_FIFO_SIZE) {
-		count = HDLC_FIFO_SIZE;
+	if (count > fs) {
+		count = fs;
 	} else {
 		if (test_bit(FLG_HDLC, &bch->Flags))
 			hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
@@ -463,7 +481,7 @@ hdlc_fill_fifo(struct bchannel *bch)
 		 bch->tx_idx, bch->tx_skb->len);
 	ptr = (u32 *)p;
 	bch->tx_idx += count;
-	hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count);
+	hdlc->ctrl.sr.xml = ((count == fs) ? 0 : count);
 	if (AVM_FRITZ_PCIV2 == fc->type) {
 		__write_ctrl_pciv2(fc, hdlc, bch->nr);
 		addr = fc->addr + (bch->nr == 2 ?
@@ -493,8 +511,6 @@ HDLC_irq_xpr(struct bchannel *bch)
 	else {
 		if (bch->tx_skb) {
 			/* send confirm, on trans, free on hdlc. */
-			if (test_bit(FLG_TRANSPARENT, &bch->Flags))
-				confirm_Bsend(bch);
 			dev_kfree_skb(bch->tx_skb);
 		}
 		if (get_next_bframe(bch))
@@ -506,13 +522,23 @@ static void
 HDLC_irq(struct bchannel *bch, u32 stat)
 {
 	struct fritzcard *fc = bch->hw;
-	int		len;
+	int		len, fs;
+	u32		rmlMask;
 	struct hdlc_hw	*hdlc;
 
 	hdlc = &fc->hdlc[(bch->nr - 1) & 1];
 	pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat);
+	if (fc->type == AVM_FRITZ_PCIV2) {
+		rmlMask = HDLC_STAT_RML_MASK_V2;
+		fs = HDLC_FIFO_SIZE_V2;
+	} else {
+		rmlMask = HDLC_STAT_RML_MASK_V1;
+		fs = HDLC_FIFO_SIZE_V1;
+	}
 	if (stat & HDLC_INT_RPR) {
 		if (stat & HDLC_STAT_RDO) {
+			pr_warning("%s: ch%d stat %x RDO\n",
+				   fc->name, bch->nr, stat);
 			hdlc->ctrl.sr.xml = 0;
 			hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS;
 			write_ctrl(bch, 1);
@@ -521,20 +547,20 @@ HDLC_irq(struct bchannel *bch, u32 stat)
 			if (bch->rx_skb)
 				skb_trim(bch->rx_skb, 0);
 		} else {
-			len = (stat & HDLC_STAT_RML_MASK) >> 8;
+			len = (stat & rmlMask) >> 8;
 			if (!len)
-				len = 32;
+				len = fs;
 			hdlc_empty_fifo(bch, len);
 			if (!bch->rx_skb)
 				goto handle_tx;
-			if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT,
-							       &bch->Flags)) {
+			if ((stat & HDLC_STAT_RME) || (test_bit(FLG_TRANSPARENT,
+			    &bch->Flags) && bch->rx_skb->len >= bch->minlen)) {
 				if (((stat & HDLC_STAT_CRCVFRRAB) ==
 				     HDLC_STAT_CRCVFR) ||
 				    test_bit(FLG_TRANSPARENT, &bch->Flags)) {
 					recv_Bchannel(bch, 0);
 				} else {
-					pr_debug("%s: got invalid frame\n",
+					pr_warning("%s: got invalid frame\n",
 						 fc->name);
 					skb_trim(bch->rx_skb, 0);
 				}
@@ -547,6 +573,8 @@ handle_tx:
 		 * restart transmitting the whole frame on HDLC
 		 * in transparent mode we send the next data
 		 */
+		pr_warning("%s: ch%d stat %x XDU %s\n", fc->name, bch->nr,
+			stat, bch->tx_skb ? "tx_skb" : "no tx_skb");
 		if (bch->tx_skb)
 			pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n",
 				 fc->name, bch->nr, bch->tx_skb->len,
@@ -643,7 +671,7 @@ avm_fritzv2_interrupt(int intno, void *dev_id)
 		mISDNisac_irq(&fc->isac, val);
 	}
 	if (sval & AVM_STATUS0_IRQ_TIMER) {
-		pr_debug("%s: timer irq\n", fc->name);
+		pr_debug("%s: sval(%x) - timer irq\n", fc->name, sval);
 		outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2);
 		udelay(1);
 		outb(fc->ctrlreg, fc->addr + 2);
@@ -1013,7 +1041,7 @@ release_card(struct fritzcard *card)
 static int __devinit
 setup_instance(struct fritzcard *card)
 {
-	int i, err;
+	int i, err, minsize;
 	u_long flags;
 
 	snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1);
@@ -1033,7 +1061,11 @@ setup_instance(struct fritzcard *card)
 	for (i = 0; i < 2; i++) {
 		card->bch[i].nr = i + 1;
 		set_channelmap(i + 1, card->isac.dch.dev.channelmap);
-		mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM);
+		if (AVM_FRITZ_PCIV2 == card->type)
+			minsize = HDLC_FIFO_SIZE_V2;
+		else
+			minsize = HDLC_FIFO_SIZE_V1;
+		mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, minsize);
 		card->bch[i].hw = card;
 		card->bch[i].ch.send = avm_l2l1B;
 		card->bch[i].ch.ctrl = avm_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index d826586..884c090 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -5175,7 +5175,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt)
 		bch->nr = ch;
 		bch->slot = ch;
 		bch->debug = debug;
-		mISDN_initbchannel(bch, MAX_DATA_MEM);
+		mISDN_initbchannel(bch, MAX_DATA_MEM, -1);
 		bch->hw = hc;
 		bch->ch.send = handle_bmsg;
 		bch->ch.ctrl = hfcm_bctrl;
@@ -5248,7 +5248,7 @@ init_multi_port(struct hfc_multi *hc, int pt)
 		bch->nr = ch + 1;
 		bch->slot = i + ch;
 		bch->debug = debug;
-		mISDN_initbchannel(bch, MAX_DATA_MEM);
+		mISDN_initbchannel(bch, MAX_DATA_MEM, -1);
 		bch->hw = hc;
 		bch->ch.send = handle_bmsg;
 		bch->ch.ctrl = hfcm_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 6a0d964..76bb800 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -2117,7 +2117,7 @@ setup_card(struct hfc_pci *card)
 		card->bch[i].nr = i + 1;
 		set_channelmap(i + 1, card->dch.dev.channelmap);
 		card->bch[i].debug = debug;
-		mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM);
+		mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, -1);
 		card->bch[i].hw = card;
 		card->bch[i].ch.send = hfcpci_l2l1B;
 		card->bch[i].ch.ctrl = hfc_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 404184a..3c20b4f 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -1876,7 +1876,7 @@ setup_instance(struct hfcsusb *hw, struct device *parent)
 		hw->bch[i].nr = i + 1;
 		set_channelmap(i + 1, hw->dch.dev.channelmap);
 		hw->bch[i].debug = debug;
-		mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM);
+		mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM, -1);
 		hw->bch[i].hw = hw;
 		hw->bch[i].ch.send = hfcusb_l2l1B;
 		hw->bch[i].ch.ctrl = hfc_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
index d301d8c..1bc75ae 100644
--- a/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -929,20 +929,29 @@ static void
 hscx_empty_fifo(struct hscx_hw *hscx, u8 count)
 {
 	u8 *p;
+	int len;
 
 	pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count);
 	if (!hscx->bch.rx_skb) {
-		hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC);
+		if (test_bit(FLG_TRANSPARENT, &hscx->bch.Flags)) {
+			if (count >= hscx->bch.minlen)
+				len = count;
+			else
+				len = 2 * hscx->bch.minlen;
+		} else
+			len = hscx->bch.maxlen;
+		hscx->bch.rx_skb = mI_alloc_skb(len, GFP_ATOMIC);
 		if (!hscx->bch.rx_skb) {
 			pr_info("%s: B receive out of memory\n",
 				hscx->ip->name);
 			hscx_cmdr(hscx, 0x80); /* RMC */
 			return;
 		}
-	}
-	if ((hscx->bch.rx_skb->len + count) > hscx->bch.maxlen) {
-		pr_debug("%s: overrun %d\n", hscx->ip->name,
-			 hscx->bch.rx_skb->len + count);
+	} else
+		len = skb_tailroom(hscx->bch.rx_skb);
+	if (count > len) {
+		pr_debug("%s: overrun  %d + %d free %d\n", hscx->ip->name,
+			hscx->bch.rx_skb->len, count, len);
 		skb_trim(hscx->bch.rx_skb, 0);
 		hscx_cmdr(hscx, 0x80); /* RMC */
 		return;
@@ -1122,7 +1131,8 @@ ipac_irq(struct hscx_hw *hx, u8 ista)
 		hscx_empty_fifo(hx, hx->fifo_size);
 		if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) {
 			/* receive transparent audio data */
-			if (hx->bch.rx_skb)
+			if (hx->bch.rx_skb &&
+			    (hx->bch.rx_skb->len >= hx->bch.minlen))
 				recv_Bchannel(&hx->bch, 0);
 		}
 	}
@@ -1613,7 +1623,8 @@ mISDNipac_init(struct ipac_hw *ipac, void *hw)
 		set_channelmap(i + 1, ipac->isac.dch.dev.channelmap);
 		list_add(&ipac->hscx[i].bch.ch.list,
 			 &ipac->isac.dch.dev.bchannels);
-		mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM);
+		mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM,
+			ipac->hscx[i].fifo_size);
 		ipac->hscx[i].bch.ch.nr = i + 1;
 		ipac->hscx[i].bch.ch.send = &hscx_l2l1;
 		ipac->hscx[i].bch.ch.ctrl = hscx_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
index 8db914a..202bd92 100644
--- a/drivers/isdn/hardware/mISDN/mISDNisar.c
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -1683,7 +1683,7 @@ mISDNisar_init(struct isar_hw *isar, void *hw)
 	isar->hw = hw;
 	for (i = 0; i < 2; i++) {
 		isar->ch[i].bch.nr = i + 1;
-		mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM);
+		mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM, -1);
 		isar->ch[i].bch.ch.nr = i + 1;
 		isar->ch[i].bch.ch.send = &isar_l2l1;
 		isar->ch[i].bch.ch.ctrl = isar_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
index fd421e7..3c5d704 100644
--- a/drivers/isdn/hardware/mISDN/netjet.c
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -1020,7 +1020,7 @@ setup_instance(struct tiger_hw *card)
 	for (i = 0; i < 2; i++) {
 		card->bc[i].bch.nr = i + 1;
 		set_channelmap(i + 1, card->isac.dch.dev.channelmap);
-		mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM);
+		mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM, -1);
 		card->bc[i].bch.hw = card;
 		card->bc[i].bch.ch.send = nj_l2l1B;
 		card->bc[i].bch.ch.ctrl = nj_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
index 0424652..a506018 100644
--- a/drivers/isdn/hardware/mISDN/w6692.c
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -1312,7 +1312,7 @@ setup_instance(struct w6692_hw *card)
 	card->dch.hw = card;
 	card->dch.dev.nrbchan = 2;
 	for (i = 0; i < 2; i++) {
-		mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM);
+		mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM, -1);
 		card->bc[i].bch.hw = card;
 		card->bc[i].bch.nr = i + 1;
 		card->bc[i].bch.ch.nr = i + 1;
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index a250244..467518c 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -81,7 +81,7 @@ mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf)
 EXPORT_SYMBOL(mISDN_initdchannel);
 
 int
-mISDN_initbchannel(struct bchannel *ch, int maxlen)
+mISDN_initbchannel(struct bchannel *ch, int maxlen, int minlen)
 {
 	ch->Flags = 0;
 	ch->maxlen = maxlen;
@@ -89,6 +89,7 @@ mISDN_initbchannel(struct bchannel *ch, int maxlen)
 	ch->rx_skb = NULL;
 	ch->tx_skb = NULL;
 	ch->tx_idx = 0;
+	ch->minlen = minlen;
 	skb_queue_head_init(&ch->rqueue);
 	ch->rcount = 0;
 	ch->next_skb = NULL;
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index 0f88acf..f68abe8 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -1420,7 +1420,7 @@ init_card(struct l1oip *hc, int pri, int bundle)
 		bch->nr = i + ch;
 		bch->slot = i + ch;
 		bch->debug = debug;
-		mISDN_initbchannel(bch, MAX_DATA_MEM);
+		mISDN_initbchannel(bch, MAX_DATA_MEM, -1);
 		bch->hw = hc;
 		bch->ch.send = handle_bmsg;
 		bch->ch.ctrl = l1oip_bctrl;
diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h
index 7075753..4f97bd3 100644
--- a/include/linux/mISDNhw.h
+++ b/include/linux/mISDNhw.h
@@ -158,6 +158,7 @@ struct bchannel {
 	/* receive data */
 	struct sk_buff		*rx_skb;
 	int			maxlen;
+	int			minlen; /* for transparent data -1 no check */
 	/* send data */
 	struct sk_buff		*next_skb;
 	struct sk_buff		*tx_skb;
@@ -172,7 +173,7 @@ struct bchannel {
 };
 
 extern int	mISDN_initdchannel(struct dchannel *, int, void *);
-extern int	mISDN_initbchannel(struct bchannel *, int);
+extern int	mISDN_initbchannel(struct bchannel *, int, int);
 extern int	mISDN_freedchannel(struct dchannel *);
 extern void	mISDN_clear_bchannel(struct bchannel *);
 extern int	mISDN_freebchannel(struct bchannel *);
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 24/28] mISDN: Bufferlimits for hfcmulti
From: Karsten Keil @ 2012-04-21 15:55 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

Implement the minimum packet length for transparent data.

Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
 drivers/isdn/hardware/mISDN/hfcmulti.c |   51 +++++++++++++++++++++++---------
 1 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 144c35a..50d10ea 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -2374,25 +2374,36 @@ next_frame:
 	} else {
 		/* transparent */
 		if (*sp == NULL) {
-			*sp = mI_alloc_skb(Zsize, GFP_ATOMIC);
+			if (Zsize >= bch->minlen)
+				temp = Zsize;
+			else
+				temp = 2 * bch->minlen;
+			if (temp > maxlen)
+				temp = maxlen;
+
+			*sp = mI_alloc_skb(temp, GFP_ATOMIC);
 			if (*sp == NULL) {
 				printk(KERN_DEBUG "%s: No mem for rx_skb\n",
 				    __func__);
 				return;
 			}
 		}
-		if (Zsize > skb_tailroom(*sp))
-			Zsize = skb_tailroom(*sp);
-		hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize);
-		skb = NULL;
+		temp = Zsize;
+		if (temp > skb_tailroom(*sp))
+			temp = skb_tailroom(*sp);
+		hc->read_fifo(hc, skb_put(*sp, temp), temp);
 		if (debug & DEBUG_HFCMULTI_FIFO)
 			printk(KERN_DEBUG
-			       "%s(card %d): fifo(%d) reading %d bytes "
-			       "(z1=%04x, z2=%04x) TRANS\n",
-			       __func__, hc->id + 1, ch, Zsize, z1, z2);
-		/* only bch is transparent */
-		recv_Bchannel(bch, hc->chan[ch].Zfill);
-		*sp = skb;
+			    "%s(card %d): fifo(%d) reading %d/%d bytes "
+			    "(z1=%04x, z2=%04x) TRANS\n", __func__,
+			    hc->id + 1, ch, temp, Zsize, z1, z2);
+		Zsize -= temp;
+		if ((*sp)->len >= bch->minlen) {
+			recv_Bchannel(bch, hc->chan[ch].Zfill);
+			*sp = NULL;
+			if (Zsize)
+				goto next_frame;
+		}
 	}
 }
 
@@ -3678,21 +3689,21 @@ static int
 channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
 {
 	int			ret = 0;
-	struct dsp_features	*features =
-		(struct dsp_features *)(*((u_long *)&cq->p1));
+	struct dsp_features	*features;
 	struct hfc_multi	*hc = bch->hw;
 	int			slot_tx;
 	int			bank_tx;
 	int			slot_rx;
 	int			bank_rx;
 	int			num;
+	int			o1, o2;
 	u8			v1, v2;
 
 	switch (cq->op) {
 	case MISDN_CTRL_GETOP:
 		cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP |
 			MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY |
-			MISDN_CTRL_L1_TESTS;
+			MISDN_CTRL_L1_TESTS | MISDN_CTRL_RX_BUFFER;
 		break;
 	case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
 		hc->chan[bch->slot].rx_off = !!cq->p1;
@@ -3714,6 +3725,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
 			       "off=%d)\n", __func__, bch->nr, !!cq->p1);
 		break;
 	case MISDN_CTRL_HW_FEATURES: /* fill features structure */
+		features = (struct dsp_features *)(*((u_long *)&cq->p1));
 		if (debug & DEBUG_HFCMULTI_MSG)
 			printk(KERN_DEBUG "%s: HW_FEATURE request\n",
 			       __func__);
@@ -3831,6 +3843,17 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
 		cq->p3 = HFC_inb(hc, R_JATT_STA);
 		cq->p3 |= (HFC_inb(hc, R_SLIP) << 8);
 		break;
+	case MISDN_CTRL_RX_BUFFER:
+		/* We return the old values */
+		o1 = bch->minlen;
+		o2 =  bch->maxlen;
+		if (cq->p1 != MISDN_CTRL_RX_SIZE_IGNORE)
+			bch->minlen = cq->p1;
+		if (cq->p2 != MISDN_CTRL_RX_SIZE_IGNORE)
+			bch->minlen = cq->p2;
+		cq->p1 = o1;
+		cq->p2 = o2;
+		break;
 	default:
 		printk(KERN_WARNING "%s: unknown Op %x\n",
 		       __func__, cq->op);
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 15/28] mISDN: DSP scheduling fix
From: Karsten Keil @ 2012-03-18 13:34 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

dsp_spl_jiffies need to be the same datatype as jiffies (which is ulong).
If not, on 64 bit systems it will fallback to schedule the DSP every jiffie
tic as soon jiffies become > 2^32.

Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
 drivers/isdn/mISDN/dsp.h     |    4 +++-
 drivers/isdn/mISDN/dsp_cmx.c |    2 +-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h
index afe4173..e020957 100644
--- a/drivers/isdn/mISDN/dsp.h
+++ b/drivers/isdn/mISDN/dsp.h
@@ -76,7 +76,9 @@ extern u8 dsp_silence;
 #define MAX_SECONDS_JITTER_CHECK 5
 
 extern struct timer_list dsp_spl_tl;
-extern u32 dsp_spl_jiffies;
+
+/* the datatype need to match jiffies datatype */
+extern ulong dsp_spl_jiffies;
 
 /* the structure of conferences:
  *
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index 0c104b9..3a3b3a5 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -1624,7 +1624,7 @@ send_packet:
 
 static u32	jittercount; /* counter for jitter check */
 struct timer_list dsp_spl_tl;
-u32	dsp_spl_jiffies; /* calculate the next time to fire */
+ulong	dsp_spl_jiffies; /* calculate the next time to fire */
 static u16	dsp_count; /* last sample count */
 static int	dsp_count_valid; /* if we have last sample count */
 
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 28/28] mISDN: Remove additonal PH_DATA confirm for raw data
From: Karsten Keil @ 2012-04-21 16:27 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

Now the confirm is already done in get_next_bframe to
allow early delivery of the next data from higher layers.

Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
 drivers/isdn/hardware/mISDN/hfcmulti.c |    4 ----
 1 files changed, 0 insertions(+), 4 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 50d10ea..7662148 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -2180,10 +2180,6 @@ next_frame:
 		HFC_wait_nodebug(hc);
 	}
 
-	/* send confirm, since get_net_bframe will not do it with trans */
-	if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags))
-		confirm_Bsend(bch);
-
 	/* check for next frame */
 	dev_kfree_skb(*sp);
 	if (bch && get_next_bframe(bch)) { /* hdlc is confirmed here */
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 13/28] mISDN: Make layer1 timer 3 value configurable
From: Karsten Keil @ 2012-03-17 15:04 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

For certification test it is useful to change the layer1
timer3 value on runtime.

Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
 drivers/isdn/mISDN/layer1.c |   16 ++++++++++++++--
 include/linux/mISDNhw.h     |    3 +++
 include/linux/mISDNif.h     |    3 ++-
 3 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c
index 0fc49b3..65912bd 100644
--- a/drivers/isdn/mISDN/layer1.c
+++ b/drivers/isdn/mISDN/layer1.c
@@ -30,11 +30,12 @@ struct layer1 {
 	struct FsmInst l1m;
 	struct FsmTimer timer;
 	int delay;
+	int			t3_value;
 	struct dchannel *dch;
 	dchannel_l1callback *dcb;
 };
 
-#define TIMER3_VALUE 7000
+#define TIMER3_DEFAULT_VALUE	7000
 
 static
 struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL};
@@ -233,7 +234,7 @@ l1_activate_s(struct FsmInst *fi, int event, void *arg)
 {
 	struct layer1 *l1 = fi->userdata;
 
-	mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+	mISDN_FsmRestartTimer(&l1->timer, l1->t3_value, EV_TIMER3, NULL, 2);
 	test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);
 	l1->dcb(l1->dch, HW_RESET_REQ);
 }
@@ -356,6 +357,16 @@ l1_event(struct layer1 *l1, u_int event)
 		release_l1(l1);
 		break;
 	default:
+		if ((event & ~HW_TIMER3_VMASK) == HW_TIMER3_VALUE) {
+			int val = event & HW_TIMER3_VMASK;
+
+			if (val < 5)
+				val = 5;
+			if (val > 30)
+				val = 30;
+			l1->t3_value = val;
+			break;
+		}
 		if (*debug & DEBUG_L1)
 			printk(KERN_DEBUG "%s %x unhandled\n",
 			       __func__, event);
@@ -377,6 +388,7 @@ create_l1(struct dchannel *dch, dchannel_l1callback *dcb) {
 	nl1->l1m.fsm = &l1fsm_s;
 	nl1->l1m.state = ST_L1_F3;
 	nl1->Flags = 0;
+	nl1->t3_value = TIMER3_DEFAULT_VALUE;
 	nl1->l1m.debug = *debug & DEBUG_L1_FSM;
 	nl1->l1m.userdata = nl1;
 	nl1->l1m.userint = 0;
diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h
index 74d5734..7075753 100644
--- a/include/linux/mISDNhw.h
+++ b/include/linux/mISDNhw.h
@@ -136,6 +136,9 @@ extern int	create_l1(struct dchannel *, dchannel_l1callback *);
 #define HW_TESTRX_RAW	0x9602
 #define HW_TESTRX_HDLC	0x9702
 #define HW_TESTRX_OFF	0x9802
+#define HW_TIMER3_IND	0x9902
+#define HW_TIMER3_VALUE	0x9a00
+#define HW_TIMER3_VMASK	0x00FF
 
 struct layer1;
 extern int	l1_event(struct layer1 *, u_int);
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index b7457e8..322d316 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
  */
 #define	MISDN_MAJOR_VERSION	1
 #define	MISDN_MINOR_VERSION	1
-#define MISDN_RELEASE		26
+#define MISDN_RELEASE		27
 
 /* primitives for information exchange
  * generell format
@@ -374,6 +374,7 @@ clear_channelmap(u_int nr, u_char *map)
 #define MISDN_CTRL_RX_OFF		0x0100
 #define MISDN_CTRL_FILL_EMPTY		0x0200
 #define MISDN_CTRL_GETPEER		0x0400
+#define MISDN_CTRL_L1_TIMER3		0x0800
 #define MISDN_CTRL_HW_FEATURES_OP	0x2000
 #define MISDN_CTRL_HW_FEATURES		0x2001
 #define MISDN_CTRL_HFC_OP		0x4000
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 00/28] MISDN patchset for net-next
From: Karsten Keil @ 2012-04-23 16:03 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

Hello David,

please include thes patches into netnext.

This patch collection contains bugfixes and enhancemets to make
the mISDN stack ready for Fax G3 support in CAPI20 (in userspace).

Tested against net-next from today.

Andreas Eversberg (7):
  mISDN: Fix NULL pointer bug in if-condition of mISDN_dsp
  mISDN: Fixed hardware bridging/conference check routine of
    mISDN_dsp.ko.
  mISDN: Fixed false interruption of audio during bridging change.
  mISDN: Added PH_* state info to tei manager.
  mISDN: Using FLG_ACTIVE flag to determine if layer 1 is active or
    not.
  mISDN: Rework of LED status display for HFC-4S/8S/E1 cards.
  mISDN: Added support for fragmentation of E1 interfaces of hfcmulti
    driver.

Karsten Keil (20):
  mISDN: Fix division by zero
  mISDN: Fix refcounting bug
  mISDN: Add interface for PCM only access
  mISDN: Add PCM only B-channel protocol to socket functions
  mISDN: L2 timeouts need to be queued as L2 event
  mISDN: Make layer1 timer 3 value configurable
  mISDN: Layer1 statemachine fix
  mISDN: DSP scheduling fix
  mISDN: Help to identify L2 issues
  mISDN: Add 2MBit mode for HFC E1 card
  mISDN: Cleanup channel also if it already was deactivated
  mISDN: Early confirm for transparent data
  mISDN: Allow the driver to set a minimum length for transparent data
  mISDN: Add interface to allow upper layers to modify RX buffer limits
  mISDN: More support for MISDN_CTRL_FILL_EMPTY and MISDN_CTRL_RX_OFF
  mISDN: Fix compiler warnings
  mISDN: Bufferlimits for hfcmulti
  mISDN: Enhance hfcsusb driver
  mISDN: Add X-Tensions USB ISDN TA XC-525
  mISDN: Remove additonal PH_DATA confirm for raw data

Martin Bachem (1):
  mISDN: Bugfix hfcsusb: usb endpoint activation/deactivation

 drivers/isdn/hardware/mISDN/avmfritz.c  |  254 ++++++--
 drivers/isdn/hardware/mISDN/hfc_multi.h |   94 ++--
 drivers/isdn/hardware/mISDN/hfcmulti.c  | 1059 +++++++++++++++++++++----------
 drivers/isdn/hardware/mISDN/hfcpci.c    |   12 +-
 drivers/isdn/hardware/mISDN/hfcsusb.c   |  224 ++++---
 drivers/isdn/hardware/mISDN/hfcsusb.h   |   16 +-
 drivers/isdn/hardware/mISDN/mISDNipac.c |   62 ++-
 drivers/isdn/hardware/mISDN/mISDNisar.c |   22 +-
 drivers/isdn/hardware/mISDN/netjet.c    |   21 +-
 drivers/isdn/hardware/mISDN/w6692.c     |   22 +-
 drivers/isdn/mISDN/core.c               |   16 +
 drivers/isdn/mISDN/dsp.h                |    4 +-
 drivers/isdn/mISDN/dsp_cmx.c            |   19 +-
 drivers/isdn/mISDN/dsp_dtmf.c           |   19 +-
 drivers/isdn/mISDN/hwchannel.c          |    9 +-
 drivers/isdn/mISDN/l1oip_core.c         |    2 +-
 drivers/isdn/mISDN/layer1.c             |   37 +-
 drivers/isdn/mISDN/layer2.c             |  119 +++-
 drivers/isdn/mISDN/socket.c             |    3 +
 drivers/isdn/mISDN/tei.c                |   71 ++-
 include/linux/mISDNhw.h                 |   13 +-
 include/linux/mISDNif.h                 |   88 ++-
 22 files changed, 1485 insertions(+), 701 deletions(-)

-- 
1.7.3.4

^ permalink raw reply

* [PATCH 27/28] mISDN: Add X-Tensions USB ISDN TA XC-525
From: Karsten Keil @ 2012-04-21 16:19 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

>From  http://www.ip-phone-forum.de/showthread.php?t=225313
Thanks to Lars Immisch for pointing to this.

Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
 drivers/isdn/hardware/mISDN/hfcsusb.h |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.h b/drivers/isdn/hardware/mISDN/hfcsusb.h
index 7d48b86..56e9755 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.h
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.h
@@ -341,6 +341,12 @@ static const char *HFC_NT_LAYER1_STATES[HFC_MAX_NT_LAYER1_STATE + 1] = {
 /* supported devices */
 static struct usb_device_id hfcsusb_idtab[] = {
 	{
+		USB_DEVICE(0x1ae7, 0x0525),
+		.driver_info = (unsigned long) &((struct hfcsusb_vdata)
+			       {LED_SCHEME1, {0x88, -64, -32, -16},
+			       "X-Tensions USB ISDN TA XC-525"}),
+	},
+	{
 		USB_DEVICE(0x0959, 0x2bd0),
 		.driver_info = (unsigned long) &((struct hfcsusb_vdata)
 			{LED_OFF, {4, 0, 2, 1},
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 21/28] mISDN: Add interface to allow upper layers to modify RX buffer limits
From: Karsten Keil @ 2012-04-21 15:26 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

It seems to be useful to let applications decide the
size of the data chunks they want receive.

Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
 drivers/isdn/hardware/mISDN/avmfritz.c  |   17 +++++++++++++----
 drivers/isdn/hardware/mISDN/mISDNipac.c |   17 +++++++++++++----
 include/linux/mISDNif.h                 |   11 ++++++++++-
 3 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index 4b1c86e..9cee744 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -835,15 +835,24 @@ init_card(struct fritzcard *fc)
 static int
 channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
 {
-	int ret = 0;
+	int ret = 0, o1, o2;
 	struct fritzcard *fc = bch->hw;
 
 	switch (cq->op) {
 	case MISDN_CTRL_GETOP:
-		cq->op = 0;
+		cq->op = MISDN_CTRL_RX_BUFFER;
+		break;
+	case MISDN_CTRL_RX_BUFFER:
+		/* We return the old values */
+		o1 = bch->minlen;
+		o2 =  bch->maxlen;
+		if (cq->p1 != MISDN_CTRL_RX_SIZE_IGNORE)
+			bch->minlen = cq->p1;
+		if (cq->p2 != MISDN_CTRL_RX_SIZE_IGNORE)
+			bch->minlen = cq->p2;
+		cq->p1 = o1;
+		cq->p2 = o2;
 		break;
-		/* Nothing implemented yet */
-	case MISDN_CTRL_FILL_EMPTY:
 	default:
 		pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op);
 		ret = -EINVAL;
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
index 1bc75ae..b32f5bb 100644
--- a/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -1395,14 +1395,23 @@ hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
 static int
 channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
 {
-	int	ret = 0;
+	int	ret = 0, o1, o2;
 
 	switch (cq->op) {
 	case MISDN_CTRL_GETOP:
-		cq->op = 0;
+		cq->op = MISDN_CTRL_RX_BUFFER;
+		break;
+	case MISDN_CTRL_RX_BUFFER:
+		/* We return the old values */
+		o1 = bch->minlen;
+		o2 =  bch->maxlen;
+		if (cq->p1 != MISDN_CTRL_RX_SIZE_IGNORE)
+			bch->minlen = cq->p1;
+		if (cq->p2 != MISDN_CTRL_RX_SIZE_IGNORE)
+			bch->minlen = cq->p2;
+		cq->p1 = o1;
+		cq->p2 = o2;
 		break;
-		/* Nothing implemented yet */
-	case MISDN_CTRL_FILL_EMPTY:
 	default:
 		pr_info("%s: unknown Op %x\n", __func__, cq->op);
 		ret = -EINVAL;
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index 850fe1f..b26de1a 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
  */
 #define	MISDN_MAJOR_VERSION	1
 #define	MISDN_MINOR_VERSION	1
-#define MISDN_RELEASE		29
+#define MISDN_RELEASE		30
 
 /* primitives for information exchange
  * generell format
@@ -367,6 +367,7 @@ clear_channelmap(u_int nr, u_char *map)
 #define MISDN_CTRL_LOOP			0x00000001
 #define MISDN_CTRL_CONNECT		0x00000002
 #define MISDN_CTRL_DISCONNECT		0x00000004
+#define MISDN_CTRL_RX_BUFFER		0x00000008
 #define MISDN_CTRL_GET_PCM_SLOTS	0x00000010
 #define MISDN_CTRL_SET_PCM_SLOTS	0x00000020
 #define MISDN_CTRL_SETPEER		0x00000040
@@ -394,6 +395,14 @@ clear_channelmap(u_int nr, u_char *map)
 #define MISDN_CTRL_L1_TS0_MODE		0x00010003
 #define MISDN_CTRL_L1_GET_SYNC_INFO	0x00010004
 
+/* special RX buffer values for MISDN_CTRL_RX_BUFFER
+ * req.p1 is minimum buffer size, req.p2 the maximum
+ * MISDN_CTRL_RX_SIZE_ IGNORE value will not change but is still read back
+ */
+#define MISDN_CTRL_RX_SIZE_NOCHECK	-1
+#define MISDN_CTRL_RX_SIZE_IGNORE	-2
+
+
 /* special PCM slot numbers */
 #define MISDN_PCM_SLOT_DISABLE	-1	/* PCM disabled */
 #define MISDN_PCM_SLOT_IGNORE	-2	/* PCM setting will be not changed */
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 22/28] mISDN: More support for MISDN_CTRL_FILL_EMPTY and MISDN_CTRL_RX_OFF
From: Karsten Keil @ 2012-04-21 15:39 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

Add a common HW flag to support RX_OFF.
Implement MISDN_CTRL_FILL_EMPTY and MISDN_CTRL_RX_OFF for the avmfritz
driver.

Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
 drivers/isdn/hardware/mISDN/avmfritz.c |  169 ++++++++++++++++++++++++--------
 drivers/isdn/mISDN/hwchannel.c         |    1 +
 include/linux/mISDNhw.h                |    4 +-
 include/linux/mISDNif.h                |   10 ++-
 4 files changed, 139 insertions(+), 45 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index 9cee744..3781446 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -141,6 +141,8 @@ struct fritzcard {
 	struct isac_hw		isac;
 	struct hdlc_hw		hdlc[2];
 	struct bchannel		bch[2];
+	int			dropcnt[2];
+	u8			fill[2 * HDLC_FIFO_SIZE_V2];
 	char			log[LOG_SIZE + 1];
 };
 
@@ -402,35 +404,45 @@ static void
 hdlc_empty_fifo(struct bchannel *bch, int count)
 {
 	u32 *ptr;
-	u8 *p;
+	u8 *p, copy;
 	u32  val, addr;
 	int cnt;
 	struct fritzcard *fc = bch->hw;
 
 	pr_debug("%s: %s %d\n", fc->name, __func__, count);
-	if (!bch->rx_skb) {
-		if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
-			if (count >= bch->minlen)
-				cnt = count;
-			else
-				cnt = 2 * bch->minlen;
-		} else
-			cnt = bch->maxlen;
-		bch->rx_skb = mI_alloc_skb(cnt, GFP_ATOMIC);
+	if (test_bit(FLG_RX_OFF, &bch->Flags)) {
+		/* We drop the content, but need to read all bytes from FIFO */
+		copy = 0;
+		if (debug & DEBUG_HW_BFIFO)
+			printk(KERN_DEBUG "Dropped %d bytes - RX off\n", count);
+		val = (bch->nr - 1) & 1;
+		fc->dropcnt[val] += count;
+	} else {
+		copy = 1;
 		if (!bch->rx_skb) {
-			pr_info("%s: B receive out of memory\n",
-				fc->name);
+			if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+				if (count >= bch->minlen)
+					cnt = count;
+				else
+					cnt = 2 * bch->minlen;
+			} else
+				cnt = bch->maxlen;
+			bch->rx_skb = mI_alloc_skb(cnt, GFP_ATOMIC);
+			if (!bch->rx_skb) {
+				pr_info("%s: B receive out of memory\n",
+					fc->name);
+				return;
+			}
+		} else
+			cnt = skb_tailroom(bch->rx_skb);
+		if (count > cnt) {
+			pr_debug("%s: overrun %d + %d free %d\n", fc->name,
+				bch->rx_skb->len, count, cnt);
 			return;
 		}
-	} else
-		cnt = skb_tailroom(bch->rx_skb);
-	if (count > cnt) {
-		pr_debug("%s: overrun %d + %d free %d\n", fc->name,
-			bch->rx_skb->len, count, cnt);
-		return;
+		p = skb_put(bch->rx_skb, count);
+		ptr = (u32 *)p;
 	}
-	p = skb_put(bch->rx_skb, count);
-	ptr = (u32 *)p;
 	if (AVM_FRITZ_PCIV2 == fc->type)
 		addr = fc->addr + (bch->nr == 2 ?
 				   AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
@@ -441,11 +453,13 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
 	cnt = 0;
 	while (cnt < count) {
 		val = le32_to_cpu(inl(addr));
-		put_unaligned(val, ptr);
-		ptr++;
+		if (copy) {
+			put_unaligned(val, ptr);
+			ptr++;
+		}
 		cnt += 4;
 	}
-	if (debug & DEBUG_HW_BFIFO) {
+	if (copy && (debug & DEBUG_HW_BFIFO)) {
 		snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ",
 			 bch->nr, fc->name, count);
 		print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
@@ -457,19 +471,25 @@ hdlc_fill_fifo(struct bchannel *bch)
 {
 	struct fritzcard *fc = bch->hw;
 	struct hdlc_hw *hdlc;
-	int count, fs, cnt = 0;
+	int count, fs, cnt = 0, idx;
 	u8 *p;
 	u32 *ptr, val, addr;
 
-	hdlc = &fc->hdlc[(bch->nr - 1) & 1];
-	if (!bch->tx_skb)
-		return;
-	count = bch->tx_skb->len - bch->tx_idx;
-	if (count <= 0)
-		return;
+	idx = (bch->nr - 1) & 1;
+	hdlc = &fc->hdlc[idx];
 	fs = (fc->type == AVM_FRITZ_PCIV2) ?
 		HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1;
-	p = bch->tx_skb->data + bch->tx_idx;
+	if (!bch->tx_skb) {
+		if (!test_bit(FLG_FILLEMPTY, &bch->Flags))
+			return;
+		count = fs;
+		p = fc->fill + (idx * HDLC_FIFO_SIZE_V2);
+	} else {
+		count = bch->tx_skb->len - bch->tx_idx;
+		if (count <= 0)
+			return;
+		p = bch->tx_skb->data + bch->tx_idx;
+	}
 	hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
 	if (count > fs) {
 		count = fs;
@@ -477,10 +497,13 @@ hdlc_fill_fifo(struct bchannel *bch)
 		if (test_bit(FLG_HDLC, &bch->Flags))
 			hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
 	}
-	pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count,
-		 bch->tx_idx, bch->tx_skb->len);
 	ptr = (u32 *)p;
-	bch->tx_idx += count;
+	if (bch->tx_skb) {
+		pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count,
+			bch->tx_idx, bch->tx_skb->len);
+		bch->tx_idx += count;
+	} else
+		 pr_debug("%s: %s fillempty %d\n", fc->name, __func__, count);
 	hdlc->ctrl.sr.xml = ((count == fs) ? 0 : count);
 	if (AVM_FRITZ_PCIV2 == fc->type) {
 		__write_ctrl_pciv2(fc, hdlc, bch->nr);
@@ -509,11 +532,10 @@ HDLC_irq_xpr(struct bchannel *bch)
 	if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
 		hdlc_fill_fifo(bch);
 	else {
-		if (bch->tx_skb) {
-			/* send confirm, on trans, free on hdlc. */
+		if (bch->tx_skb)
 			dev_kfree_skb(bch->tx_skb);
-		}
-		if (get_next_bframe(bch))
+		if (get_next_bframe(bch) ||
+		    test_bit(FLG_FILLEMPTY, &bch->Flags))
 			hdlc_fill_fifo(bch);
 	}
 }
@@ -523,8 +545,9 @@ HDLC_irq(struct bchannel *bch, u32 stat)
 {
 	struct fritzcard *fc = bch->hw;
 	int		len, fs;
-	u32		rmlMask;
+	u32		rmlMask, err;
 	struct hdlc_hw	*hdlc;
+	struct sk_buff	*skb;
 
 	hdlc = &fc->hdlc[(bch->nr - 1) & 1];
 	pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat);
@@ -546,6 +569,12 @@ HDLC_irq(struct bchannel *bch, u32 stat)
 			write_ctrl(bch, 1);
 			if (bch->rx_skb)
 				skb_trim(bch->rx_skb, 0);
+			if (test_bit(FLG_FIFO_STATUS, &bch->Flags)) {
+				skb = _alloc_mISDN_skb(PH_CONTROL_IND,
+					HW_FIFO_RDO, 0, NULL, GFP_KERNEL);
+				if (skb)
+					recv_Bchannel_skb(bch, skb);
+			}
 		} else {
 			len = (stat & rmlMask) >> 8;
 			if (!len)
@@ -575,13 +604,22 @@ handle_tx:
 		 */
 		pr_warning("%s: ch%d stat %x XDU %s\n", fc->name, bch->nr,
 			stat, bch->tx_skb ? "tx_skb" : "no tx_skb");
-		if (bch->tx_skb)
+		if (bch->tx_skb) {
 			pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n",
 				 fc->name, bch->nr, bch->tx_skb->len,
 				 bch->tx_idx, bch->Flags);
-		else
+			err = HW_FIFO_XDU_DATA;
+		} else {
 			pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n",
 				 fc->name, bch->nr, bch->Flags);
+			err = HW_FIFO_XDU_NODATA;
+		}
+		if (test_bit(FLG_FIFO_STATUS, &bch->Flags)) {
+			skb = _alloc_mISDN_skb(PH_CONTROL_IND, err,
+				0, NULL, GFP_KERNEL);
+			if (skb)
+				recv_Bchannel_skb(bch, skb);
+		}
 		if (bch->tx_skb && bch->tx_skb->len) {
 			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
 				bch->tx_idx = 0;
@@ -721,6 +759,24 @@ avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
 			    NULL, GFP_KERNEL);
 		ret = 0;
 		break;
+	case PH_CONTROL_REQ:
+		switch (hh->id) {
+		case HW_FIFO_STATUS_ON:
+			test_and_set_bit(FLG_FIFO_STATUS, &bch->Flags);
+			id = 0;
+			break;
+		case HW_FIFO_STATUS_OFF:
+			test_and_clear_bit(FLG_FIFO_STATUS, &bch->Flags);
+			id = 0;
+			break;
+		default:
+			pr_info("PH_CONTROL_REQ %x not supported\n", hh->id);
+			id = -EINVAL;
+			break;
+		}
+		_queue_data(ch, PH_CONTROL_CNF, id, 0, NULL, GFP_KERNEL);
+		ret = 0;
+		break;
 	}
 	if (!ret)
 		dev_kfree_skb(skb);
@@ -835,12 +891,39 @@ init_card(struct fritzcard *fc)
 static int
 channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
 {
-	int ret = 0, o1, o2;
+	int ret = 0, o1, o2, idx;
+	u8 *p;
 	struct fritzcard *fc = bch->hw;
 
+	idx = (bch->nr - 1) & 1;
 	switch (cq->op) {
 	case MISDN_CTRL_GETOP:
-		cq->op = MISDN_CTRL_RX_BUFFER;
+		cq->op = MISDN_CTRL_RX_BUFFER |
+			MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY;
+		break;
+	case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
+		o1 = fc->dropcnt[idx];
+		if (cq->p1) {
+			test_and_set_bit(FLG_RX_OFF, &bch->Flags);
+			fc->dropcnt[idx] = 0;
+		} else
+			test_and_clear_bit(FLG_RX_OFF, &bch->Flags);
+		cq->p2 = o1;
+		if (debug & DEBUG_HW_BCHANNEL)
+			printk(KERN_DEBUG "Bch%d RX %s\n",
+			    bch->nr, cq->p1 ? "off" : "on");
+		break;
+	case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */
+		p = fc->fill + (idx * HDLC_FIFO_SIZE_V2);
+		if (cq->p1) {
+			test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
+			if (cq->p2 > -1)
+				memset(p, cq->p2 & 0xff, HDLC_FIFO_SIZE_V2);
+		} else
+			test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+		if (debug & DEBUG_HW_BCHANNEL)
+			printk(KERN_DEBUG "FILL_EMPTY Bch%d %s val %02x\n",
+				bch->nr, cq->p1 ? "on" : "off", *p);
 		break;
 	case MISDN_CTRL_RX_BUFFER:
 		/* We return the old values */
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index 467518c..84fbcf1 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -135,6 +135,7 @@ mISDN_clear_bchannel(struct bchannel *ch)
 	test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
 	test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
 	test_and_clear_bit(FLG_ACTIVE, &ch->Flags);
+	test_and_clear_bit(FLG_RX_OFF, &ch->Flags);
 }
 EXPORT_SYMBOL(mISDN_clear_bchannel);
 
diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h
index 4f97bd3..9776edd 100644
--- a/include/linux/mISDNhw.h
+++ b/include/linux/mISDNhw.h
@@ -73,7 +73,9 @@
 #define FLG_LL_OK		24
 #define FLG_LL_CONN		25
 #define FLG_DTMFSEND		26
-
+/* stop sending received data upstream */
+#define FLG_RX_OFF		27
+#define FLG_FIFO_STATUS		28
 /* workq events */
 #define FLG_RECVQUEUE		30
 #define	FLG_PHCHANGE		31
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index b26de1a..89ce4ec 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
  */
 #define	MISDN_MAJOR_VERSION	1
 #define	MISDN_MINOR_VERSION	1
-#define MISDN_RELEASE		30
+#define MISDN_RELEASE		31
 
 /* primitives for information exchange
  * generell format
@@ -158,6 +158,7 @@
 #define HFC_VOL_CHANGE_RX	0x2602
 #define HFC_SPL_LOOP_ON		0x2603
 #define HFC_SPL_LOOP_OFF	0x2604
+
 /* for T30 FAX and analog modem */
 #define HW_MOD_FRM		0x4000
 #define HW_MOD_FRH		0x4001
@@ -171,6 +172,13 @@
 #define HW_MOD_READY		0x4014
 #define HW_MOD_LASTDATA		0x4015
 
+/* Debug and status via PH_CONTROL */
+#define HW_FIFO_STATUS_OFF	0x8000
+#define HW_FIFO_STATUS_ON	0x8001
+#define HW_FIFO_RDO		0x8002
+#define HW_FIFO_XDU_DATA	0x8003
+#define HW_FIFO_XDU_NODATA	0x8004
+
 /* DSP_TONE_PATT_ON parameter */
 #define TONE_OFF			0x0000
 #define TONE_GERMAN_DIALTONE		0x0001
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 16/28] mISDN: Help to identify L2 issues
From: Karsten Keil @ 2012-03-18 13:38 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

With multiple cards is hard to figure out which port cause trouble.
Now we have the informations in the log output.

Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
---
 drivers/isdn/mISDN/core.c   |   16 +++++++++
 drivers/isdn/mISDN/layer2.c |   75 ++++++++++++++++++++++++------------------
 include/linux/mISDNif.h     |    3 +-
 3 files changed, 61 insertions(+), 33 deletions(-)

diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c
index a24530f..c401634 100644
--- a/drivers/isdn/mISDN/core.c
+++ b/drivers/isdn/mISDN/core.c
@@ -355,6 +355,22 @@ mISDN_unregister_Bprotocol(struct Bprotocol *bp)
 }
 EXPORT_SYMBOL(mISDN_unregister_Bprotocol);
 
+static const char *msg_no_channel = "<no channel>";
+static const char *msg_no_stack = "<no stack>";
+static const char *msg_no_stackdev = "<no stack device>";
+
+const char *mISDNDevName4ch(struct mISDNchannel *ch)
+{
+	if (!ch)
+		return msg_no_channel;
+	if (!ch->st)
+		return msg_no_stack;
+	if (!ch->st->dev)
+		return msg_no_stackdev;
+	return dev_name(&ch->st->dev->dev);
+};
+EXPORT_SYMBOL(mISDNDevName4ch);
+
 static int
 mISDNInit(void)
 {
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c
index d421495..2829d93 100644
--- a/drivers/isdn/mISDN/layer2.c
+++ b/drivers/isdn/mISDN/layer2.c
@@ -110,8 +110,8 @@ l2m_debug(struct FsmInst *fi, char *fmt, ...)
 	vaf.fmt = fmt;
 	vaf.va = &va;
 
-	printk(KERN_DEBUG "l2 (sapi %d tei %d): %pV\n",
-	       l2->sapi, l2->tei, &vaf);
+	printk(KERN_DEBUG "%s l2 (sapi %d tei %d): %pV\n",
+	       mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, &vaf);
 
 	va_end(va);
 }
@@ -154,7 +154,8 @@ l2up(struct layer2 *l2, u_int prim, struct sk_buff *skb)
 	mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr;
 	err = l2->up->send(l2->up, skb);
 	if (err) {
-		printk(KERN_WARNING "%s: err=%d\n", __func__, err);
+		printk(KERN_WARNING "%s: dev %s err=%d\n", __func__,
+			mISDNDevName4ch(&l2->ch), err);
 		dev_kfree_skb(skb);
 	}
 }
@@ -178,7 +179,8 @@ l2up_create(struct layer2 *l2, u_int prim, int len, void *arg)
 		memcpy(skb_put(skb, len), arg, len);
 	err = l2->up->send(l2->up, skb);
 	if (err) {
-		printk(KERN_WARNING "%s: err=%d\n", __func__, err);
+		printk(KERN_WARNING "%s: dev %s err=%d\n", __func__,
+			mISDNDevName4ch(&l2->ch), err);
 		dev_kfree_skb(skb);
 	}
 }
@@ -189,7 +191,8 @@ l2down_skb(struct layer2 *l2, struct sk_buff *skb) {
 
 	ret = l2->ch.recv(l2->ch.peer, skb);
 	if (ret && (*debug & DEBUG_L2_RECV))
-		printk(KERN_DEBUG "l2down_skb: ret(%d)\n", ret);
+		printk(KERN_DEBUG "l2down_skb: dev %s ret(%d)\n",
+			mISDNDevName4ch(&l2->ch), ret);
 	return ret;
 }
 
@@ -289,18 +292,18 @@ l2_timeout(struct FsmInst *fi, int event, void *arg)
 
 	skb = mI_alloc_skb(0, GFP_ATOMIC);
 	if (!skb) {
-		printk(KERN_WARNING "L2(%d,%d) nr:%x timer %s lost - no skb\n",
-			l2->sapi, l2->tei, l2->ch.nr, event == EV_L2_T200 ?
-			"T200" : "T203");
+		printk(KERN_WARNING "%s: L2(%d,%d) nr:%x timer %s no skb\n",
+			mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei,
+			l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203");
 		return;
 	}
 	hh = mISDN_HEAD_P(skb);
 	hh->prim = event == EV_L2_T200 ? DL_TIMER200_IND : DL_TIMER203_IND;
 	hh->id = l2->ch.nr;
 	if (*debug & DEBUG_TIMER)
-		printk(KERN_DEBUG "L2(%d,%d) nr:%x timer %s expired\n",
-			l2->sapi, l2->tei, l2->ch.nr, event == EV_L2_T200 ?
-			"T200" : "T203");
+		printk(KERN_DEBUG "%s: L2(%d,%d) nr:%x timer %s expired\n",
+			mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei,
+			l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203");
 	if (l2->ch.st)
 		l2->ch.st->own.recv(&l2->ch.st->own, skb);
 }
@@ -309,8 +312,8 @@ static int
 l2mgr(struct layer2 *l2, u_int prim, void *arg) {
 	long c = (long)arg;
 
-	printk(KERN_WARNING
-	       "l2mgr: addr:%x prim %x %c\n", l2->id, prim, (char)c);
+	printk(KERN_WARNING "l2mgr: dev %s addr:%x prim %x %c\n",
+		mISDNDevName4ch(&l2->ch), l2->id, prim, (char)c);
 	if (test_bit(FLG_LAPD, &l2->flag) &&
 	    !test_bit(FLG_FIXED_TEI, &l2->flag)) {
 		switch (c) {
@@ -632,8 +635,8 @@ send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr)
 	else {
 		skb = mI_alloc_skb(i, GFP_ATOMIC);
 		if (!skb) {
-			printk(KERN_WARNING "%s: can't alloc skbuff\n",
-			       __func__);
+			printk(KERN_WARNING "%s: can't alloc skbuff in %s\n",
+				mISDNDevName4ch(&l2->ch), __func__);
 			return;
 		}
 	}
@@ -1118,8 +1121,8 @@ enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf)
 		tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0);
 	skb = mI_alloc_skb(i, GFP_ATOMIC);
 	if (!skb) {
-		printk(KERN_WARNING
-		       "isdnl2 can't alloc sbbuff for enquiry_cr\n");
+		printk(KERN_WARNING "%s: isdnl2 can't alloc sbbuff in %s\n",
+			mISDNDevName4ch(&l2->ch), __func__);
 		return;
 	}
 	memcpy(skb_put(skb, i), tmp, i);
@@ -1179,7 +1182,7 @@ invoke_retransmission(struct layer2 *l2, unsigned int nr)
 			else
 				printk(KERN_WARNING
 				       "%s: windowar[%d] is NULL\n",
-				       __func__, p1);
+				    mISDNDevName4ch(&l2->ch), p1);
 			l2->windowar[p1] = NULL;
 		}
 		mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
@@ -1490,8 +1493,8 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
 		p1 = (l2->vs - l2->va) % 8;
 	p1 = (p1 + l2->sow) % l2->window;
 	if (l2->windowar[p1]) {
-		printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n",
-		       p1);
+		printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n",
+		    mISDNDevName4ch(&l2->ch), p1);
 		dev_kfree_skb(l2->windowar[p1]);
 	}
 	l2->windowar[p1] = skb;
@@ -1511,12 +1514,14 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
 		memcpy(skb_push(nskb, i), header, i);
 	else {
 		printk(KERN_WARNING
-		       "isdnl2 pull_iqueue skb header(%d/%d) too short\n", i, p1);
+		    "%s: L2 pull_iqueue skb header(%d/%d) too short\n",
+		    mISDNDevName4ch(&l2->ch), i, p1);
 		oskb = nskb;
 		nskb = mI_alloc_skb(oskb->len + i, GFP_ATOMIC);
 		if (!nskb) {
 			dev_kfree_skb(oskb);
-			printk(KERN_WARNING "%s: no skb mem\n", __func__);
+			printk(KERN_WARNING "%s: no skb mem in %s\n",
+			    mISDNDevName4ch(&l2->ch), __func__);
 			return;
 		}
 		memcpy(skb_put(nskb, i), header, i);
@@ -1892,7 +1897,8 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
 		ptei = *datap++;
 		if ((psapi & 1) || !(ptei & 1)) {
 			printk(KERN_WARNING
-			       "l2 D-channel frame wrong EA0/EA1\n");
+			    "%s l2 D-channel frame wrong EA0/EA1\n",
+			    mISDNDevName4ch(&l2->ch));
 			return ret;
 		}
 		psapi >>= 2;
@@ -1901,7 +1907,7 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
 			/* not our business */
 			if (*debug & DEBUG_L2)
 				printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n",
-				       __func__, psapi, l2->sapi);
+				    mISDNDevName4ch(&l2->ch), psapi, l2->sapi);
 			dev_kfree_skb(skb);
 			return 0;
 		}
@@ -1909,7 +1915,7 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
 			/* not our business */
 			if (*debug & DEBUG_L2)
 				printk(KERN_DEBUG "%s: tei %d/%d mismatch\n",
-				       __func__, ptei, l2->tei);
+				    mISDNDevName4ch(&l2->ch), ptei, l2->tei);
 			dev_kfree_skb(skb);
 			return 0;
 		}
@@ -1950,7 +1956,8 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
 	} else
 		c = 'L';
 	if (c) {
-		printk(KERN_WARNING "l2 D-channel frame error %c\n", c);
+		printk(KERN_WARNING "%s:l2 D-channel frame error %c\n",
+		    mISDNDevName4ch(&l2->ch), c);
 		mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
 	}
 	return ret;
@@ -1964,15 +1971,16 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb)
 	int			ret = -EINVAL;
 
 	if (*debug & DEBUG_L2_RECV)
-		printk(KERN_DEBUG "%s: prim(%x) id(%x) sapi(%d) tei(%d)\n",
-		       __func__, hh->prim, hh->id, l2->sapi, l2->tei);
+		printk(KERN_DEBUG "%s: %s prim(%x) id(%x) sapi(%d) tei(%d)\n",
+		    __func__, mISDNDevName4ch(&l2->ch), hh->prim, hh->id,
+		    l2->sapi, l2->tei);
 	if (hh->prim == DL_INTERN_MSG) {
 		struct mISDNhead *chh = hh + 1; /* saved copy */
 
 		*hh = *chh;
 		if (*debug & DEBUG_L2_RECV)
 			printk(KERN_DEBUG "%s: prim(%x) id(%x) internal msg\n",
-				__func__, hh->prim, hh->id);
+				mISDNDevName4ch(&l2->ch), hh->prim, hh->id);
 	}
 	switch (hh->prim) {
 	case PH_DATA_IND:
@@ -2053,7 +2061,8 @@ tei_l2(struct layer2 *l2, u_int cmd, u_long arg)
 	int		ret = -EINVAL;
 
 	if (*debug & DEBUG_L2_TEI)
-		printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd);
+		printk(KERN_DEBUG "%s: cmd(%x) in %s\n",
+		    mISDNDevName4ch(&l2->ch), cmd, __func__);
 	switch (cmd) {
 	case (MDL_ASSIGN_REQ):
 		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg);
@@ -2066,7 +2075,8 @@ tei_l2(struct layer2 *l2, u_int cmd, u_long arg)
 		break;
 	case (MDL_ERROR_RSP):
 		/* ETS 300-125 5.3.2.1 Test: TC13010 */
-		printk(KERN_NOTICE "MDL_ERROR|REQ (tei_l2)\n");
+		printk(KERN_NOTICE "%s: MDL_ERROR|REQ (tei_l2)\n",
+		    mISDNDevName4ch(&l2->ch));
 		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL);
 		break;
 	}
@@ -2098,7 +2108,8 @@ l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
 	u_int			info;
 
 	if (*debug & DEBUG_L2_CTRL)
-		printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd);
+		printk(KERN_DEBUG "%s: %s cmd(%x)\n",
+		    mISDNDevName4ch(ch), __func__, cmd);
 
 	switch (cmd) {
 	case OPEN_CHANNEL:
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index 322d316..f474f40 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -37,7 +37,7 @@
  */
 #define	MISDN_MAJOR_VERSION	1
 #define	MISDN_MINOR_VERSION	1
-#define MISDN_RELEASE		27
+#define MISDN_RELEASE		28
 
 /* primitives for information exchange
  * generell format
@@ -598,6 +598,7 @@ static inline struct mISDNdevice *dev_to_mISDN(struct device *dev)
 extern void	set_channel_address(struct mISDNchannel *, u_int, u_int);
 extern void	mISDN_clock_update(struct mISDNclock *, int, struct timeval *);
 extern unsigned short mISDN_clock_get(void);
+extern const char *mISDNDevName4ch(struct mISDNchannel *);
 
 #endif /* __KERNEL__ */
 #endif /* mISDNIF_H */
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 05/28] mISDN: Using FLG_ACTIVE flag to determine if layer 1 is active or not.
From: Karsten Keil @ 2012-03-17  9:41 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

From: Andreas Eversberg <andreas@eversberg.eu>

Signed-off-by: Andreas Eversberg <andreas@eversberg.eu>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
 drivers/isdn/hardware/mISDN/hfcmulti.c |   25 ++++++++++---------------
 1 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index c4e7fda..cc978e8 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -1619,10 +1619,16 @@ hfcmulti_leds(struct hfc_multi *hc)
 		 * 2 red steady:   TE mode deactivate
 		 * left green:     L1 active
 		 * left red:       frame sync, but no L1
-		 * right green:    L2 active
+		 * todo right green:    L2 active
 		 */
-		if (hc->chan[hc->dslot].sync != 2) { /* no frame sync */
-			if (hc->chan[hc->dslot].dch->dev.D.protocol
+		dch = hc->chan[hc->dslot].dch;
+		if (test_bit(FLG_ACTIVE, &dch->Flags)) {
+			led[0] = 0;
+			led[1] = 0;
+			led[2] = 0;
+			led[3] = 1;
+		} else {
+			if (dch->dev.D.protocol
 			    != ISDN_P_NT_E1) {
 				led[0] = 1;
 				led[1] = 1;
@@ -1635,12 +1641,6 @@ hfcmulti_leds(struct hfc_multi *hc)
 			}
 			led[2] = 0;
 			led[3] = 0;
-		} else { /* with frame sync */
-			/* TODO make it work */
-			led[0] = 0;
-			led[1] = 0;
-			led[2] = 0;
-			led[3] = 1;
 		}
 		leds = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF;
 		/* leds are inverted */
@@ -4062,14 +4062,9 @@ open_dchannel(struct hfc_multi *hc, struct dchannel *dch,
 		hfcmulti_initmode(dch);
 		spin_unlock_irqrestore(&hc->lock, flags);
 	}
-
-	if (((rq->protocol == ISDN_P_NT_S0) && (dch->state == 3)) ||
-	    ((rq->protocol == ISDN_P_TE_S0) && (dch->state == 7)) ||
-	    ((rq->protocol == ISDN_P_NT_E1) && (dch->state == 1)) ||
-	    ((rq->protocol == ISDN_P_TE_E1) && (dch->state == 1))) {
+	if (test_bit(FLG_ACTIVE, &dch->Flags))
 		_queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY,
 			    0, NULL, GFP_KERNEL);
-	}
 	rq->ch = &dch->dev.D;
 	if (!try_module_get(THIS_MODULE))
 		printk(KERN_WARNING "%s:cannot get module\n", __func__);
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 03/28] mISDN: Fixed false interruption of audio during bridging change.
From: Karsten Keil @ 2012-03-17  9:34 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, isdn4linux

From: Andreas Eversberg <jolly@eversberg.eu>
Transmitted audio data was interrupted if a bridge was enabled or disabled.
Now transmission seamlessly continues during that action.
Fix in hfcmulti.ko

Signed-off-by: Andreas Eversberg <jolly@eversberg.eu>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
---
 drivers/isdn/hardware/mISDN/hfcmulti.c |   24 ++++++++++++++++--------
 1 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 0332231..c4e7fda 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -3018,8 +3018,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx,
 			HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF);
 			HFC_outb(hc, A_SUBCH_CFG, 0);
 			HFC_outb(hc, A_IRQ_MSK, 0);
-			HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
-			HFC_wait(hc);
+			if (hc->chan[ch].protocol != protocol) {
+				HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+				HFC_wait(hc);
+			}
 			HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) +
 					       ((ch % 4) * 4) + 1) << 1) | 1);
 			HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1) | 1);
@@ -3039,8 +3041,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx,
 			HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF);
 			HFC_outb(hc, A_SUBCH_CFG, 0);
 			HFC_outb(hc, A_IRQ_MSK, 0);
-			HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
-			HFC_wait(hc);
+			if (hc->chan[ch].protocol != protocol) {
+				HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+				HFC_wait(hc);
+			}
 			/* tx silence */
 			HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
 			HFC_outb(hc, R_SLOT, (((ch / 4) * 8) +
@@ -3059,8 +3063,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx,
 					 V_HDLC_TRP | V_IFF);
 			HFC_outb(hc, A_SUBCH_CFG, 0);
 			HFC_outb(hc, A_IRQ_MSK, 0);
-			HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
-			HFC_wait(hc);
+			if (hc->chan[ch].protocol != protocol) {
+				HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+				HFC_wait(hc);
+			}
 			/* tx silence */
 			HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
 			/* enable RX fifo */
@@ -3075,8 +3081,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx,
 					 V_HDLC_TRP);
 			HFC_outb(hc, A_SUBCH_CFG, 0);
 			HFC_outb(hc, A_IRQ_MSK, 0);
-			HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
-			HFC_wait(hc);
+			if (hc->chan[ch].protocol != protocol) {
+				HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+				HFC_wait(hc);
+			}
 		}
 		if (hc->ctype != HFC_TYPE_E1) {
 			hc->hw.a_st_ctrl0[hc->chan[ch].port] |=
-- 
1.7.3.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox