linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] ath9k: Add a module parameter to set btcoex duty cycle
@ 2016-11-24  6:53 miaoqing
  2016-11-24  6:53 ` [PATCH 2/3] ath9k: export configurable parameters of PTA miaoqing
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: miaoqing @ 2016-11-24  6:53 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, ath9k-devel, Miaoqing Pan

From: Miaoqing Pan <miaoqing@codeaurora.org>

btcoex duty cyle allows user to balance the performance
between WLAN and BT.

Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
---
 drivers/net/wireless/ath/ath9k/gpio.c |  4 +---
 drivers/net/wireless/ath/ath9k/init.c | 10 ++++++++++
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index ddb2886..782a2f2 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -278,7 +278,7 @@ static void ath_init_btcoex_timer(struct ath_softc *sc)
 	struct ath_btcoex *btcoex = &sc->btcoex;
 
 	btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
-	btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
+	btcoex->btcoex_no_stomp = (100 - btcoex->duty_cycle) *
 		btcoex->btcoex_period / 100;
 	btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
 				   btcoex->btcoex_period / 100;
@@ -433,8 +433,6 @@ int ath9k_init_btcoex(struct ath_softc *sc)
 		break;
 	case ATH_BTCOEX_CFG_MCI:
 		ath_init_btcoex_timer(sc);
-
-		sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
 		INIT_LIST_HEAD(&sc->btcoex.mci.info);
 		ath9k_hw_btcoex_init_mci(ah);
 
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 368d9b3..8edd78b 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -73,6 +73,12 @@ struct ath9k_eeprom_ctx {
 
 #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
 
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+static int ath9k_btcoex_duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
+module_param_named(btcoex_duty_cycle, ath9k_btcoex_duty_cycle, int, 0444);
+MODULE_PARM_DESC(btcoex_duty_cycle, "BT coexistence duty cycle");
+#endif
+
 bool is_ath9k_unloaded;
 
 #ifdef CONFIG_MAC80211_LEDS
@@ -587,6 +593,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 	sc->sc_ah = ah;
 	sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET);
 	sc->tx99_power = MAX_RATE_POWER + 1;
+
 	init_waitqueue_head(&sc->tx_wait);
 	sc->cur_chan = &sc->chanctx[0];
 	if (!ath9k_is_chanctx_enabled())
@@ -602,6 +609,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 	common->btcoex_enabled = ath9k_btcoex_enable == 1;
 	common->disable_ani = false;
 
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+	sc->btcoex.duty_cycle = ath9k_btcoex_duty_cycle;
+#endif
 	/*
 	 * Platform quirks.
 	 */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] ath9k: export configurable parameters of PTA
  2016-11-24  6:53 [PATCH 1/3] ath9k: Add a module parameter to set btcoex duty cycle miaoqing
@ 2016-11-24  6:53 ` miaoqing
  2016-11-25 15:28   ` Valo, Kalle
  2016-11-24  6:53 ` [PATCH 3/3] ath9k: disable ACK_CTS for SOC chips in PTA mode miaoqing
  2016-11-25 15:25 ` [PATCH 1/3] ath9k: Add a module parameter to set btcoex duty cycle Valo, Kalle
  2 siblings, 1 reply; 5+ messages in thread
From: miaoqing @ 2016-11-24  6:53 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, ath9k-devel, Miaoqing Pan

From: Miaoqing Pan <miaoqing@codeaurora.org>

Export time_extend, pritority_time, first_slot_time, wl_active_time
and wl_qc_time those PTA(aka slotted mode) configurable parameters,
allow user to change/debug the timing easily.

Also set wl_active_time and wl_qc_time default value to 0, as in this
period WLAN chip may send out ACK, and it will corrupt the BT(or other)
received packet in the PTA cycle.

Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
---
 drivers/net/wireless/ath/ath9k/btcoex.c | 62 ++++++++-------------------------
 drivers/net/wireless/ath/ath9k/btcoex.h |  9 +++++
 drivers/net/wireless/ath/ath9k/init.c   | 26 ++++++++++++++
 3 files changed, 50 insertions(+), 47 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index 618c9df..6d15dd3 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -26,20 +26,6 @@ enum ath_bt_mode {
 	ATH_BT_COEX_MODE_DISABLED,      /* coexistence disabled */
 };
 
-struct ath_btcoex_config {
-	u8 bt_time_extend;
-	bool bt_txstate_extend;
-	bool bt_txframe_extend;
-	enum ath_bt_mode bt_mode; /* coexistence mode */
-	bool bt_quiet_collision;
-	bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/
-	u8 bt_priority_time;
-	u8 bt_first_slot_time;
-	bool bt_hold_rx_clear;
-	u8 wl_active_time;
-	u8 wl_qc_time;
-};
-
 static const u32 ar9003_wlan_weights[ATH_BTCOEX_STOMP_MAX]
 				    [AR9300_NUM_WLAN_WEIGHTS] = {
 	{ 0xfffffff0, 0xfffffff0, 0xfffffff0, 0xfffffff0 }, /* STOMP_ALL */
@@ -59,33 +45,16 @@ struct ath_btcoex_config {
 void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
 {
 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
-	const struct ath_btcoex_config ath_bt_config = {
-		.bt_time_extend = 0,
-		.bt_txstate_extend = true,
-		.bt_txframe_extend = true,
-		.bt_mode = ATH_BT_COEX_MODE_SLOTTED,
-		.bt_quiet_collision = true,
-		.bt_rxclear_polarity = true,
-		.bt_priority_time = 2,
-		.bt_first_slot_time = 5,
-		.bt_hold_rx_clear = true,
-		.wl_active_time = 0x20,
-		.wl_qc_time = 0x20,
-	};
-	bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity;
-	u8 time_extend = ath_bt_config.bt_time_extend;
-	u8 first_slot_time = ath_bt_config.bt_first_slot_time;
+	struct ath_btcoex_config *config = &btcoex_hw->config;
+	bool rxclear_polarity = true;
 
 	if (AR_SREV_9300_20_OR_LATER(ah))
-		rxclear_polarity = !ath_bt_config.bt_rxclear_polarity;
+		rxclear_polarity = false;
 
 	if (AR_SREV_SOC(ah)) {
-		first_slot_time = 0x1d;
-		time_extend = 0xa;
-
 		btcoex_hw->bt_coex_mode3 =
-			SM(ath_bt_config.wl_active_time, AR_BT_WL_ACTIVE_TIME) |
-			SM(ath_bt_config.wl_qc_time, AR_BT_WL_QC_TIME);
+			SM(config->wl_active_time, AR_BT_WL_ACTIVE_TIME) |
+			SM(config->wl_qc_time, AR_BT_WL_QC_TIME);
 
 		btcoex_hw->bt_coex_mode2 =
 			AR_BT_PROTECT_BT_AFTER_WAKEUP |
@@ -93,21 +62,20 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
 	}
 
 	btcoex_hw->bt_coex_mode =
-		(btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) |
-		SM(time_extend, AR_BT_TIME_EXTEND) |
-		SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
-		SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
-		SM(ath_bt_config.bt_mode, AR_BT_MODE) |
-		SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) |
+		AR_BT_TXSTATE_EXTEND |
+		AR_BT_TX_FRAME_EXTEND |
+		AR_BT_QUIET |
+		SM(ATH_BT_COEX_MODE_SLOTTED, AR_BT_MODE) |
 		SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) |
-		SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) |
-		SM(first_slot_time, AR_BT_FIRST_SLOT_TIME) |
+		SM(config->bt_time_extend, AR_BT_TIME_EXTEND) |
+		SM(config->bt_priority_time, AR_BT_PRIORITY_TIME) |
+		SM(config->bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) |
 		SM(qnum, AR_BT_QCU_THRESH);
 
 	btcoex_hw->bt_coex_mode2 |=
-		SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
-		SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
-		AR_BT_DISABLE_BT_ANT;
+		AR_BT_HOLD_RX_CLEAR |
+		AR_BT_DISABLE_BT_ANT |
+		SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH);
 }
 EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw);
 
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 1bdfa84..fb1ef04 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -104,6 +104,14 @@ struct ath9k_hw_aic {
 	u32 aic_cal_start_time;
 };
 
+struct ath_btcoex_config {
+	u8 bt_time_extend;
+	u8 bt_priority_time;
+	u8 bt_first_slot_time;
+	u8 wl_active_time;
+	u8 wl_qc_time;
+};
+
 struct ath_btcoex_hw {
 	enum ath_btcoex_scheme scheme;
 	struct ath9k_hw_mci mci;
@@ -119,6 +127,7 @@ struct ath_btcoex_hw {
 	u32 bt_weight[AR9300_NUM_BT_WEIGHTS];
 	u32 wlan_weight[AR9300_NUM_WLAN_WEIGHTS];
 	u8 tx_prio[ATH_BTCOEX_STOMP_MAX];
+	struct ath_btcoex_config config;
 };
 
 void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 8edd78b..74d2b7b 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -77,6 +77,26 @@ struct ath9k_eeprom_ctx {
 static int ath9k_btcoex_duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
 module_param_named(btcoex_duty_cycle, ath9k_btcoex_duty_cycle, int, 0444);
 MODULE_PARM_DESC(btcoex_duty_cycle, "BT coexistence duty cycle");
+
+static int ath9k_btcoex_time_extend;
+module_param_named(btcoex_time_extend, ath9k_btcoex_time_extend, int, 0444);
+MODULE_PARM_DESC(btcoex_time_extend, "BT coexistence time extend");
+
+static int ath9k_btcoex_priority_time = 2;
+module_param_named(btcoex_priority_time, ath9k_btcoex_priority_time, int, 0444);
+MODULE_PARM_DESC(btcoex_priority_time, "BT coexistence priority time");
+
+static int ath9k_btcoex_first_slot_time = 5;
+module_param_named(btcoex_first_slot_time, ath9k_btcoex_first_slot_time, int, 0444);
+MODULE_PARM_DESC(btcoex_first_slot_time, "BT coexistence first slot time");
+
+static int ath9k_btcoex_wl_active_time;
+module_param_named(btcoex_wl_active_time, ath9k_btcoex_wl_active_time, int, 0444);
+MODULE_PARM_DESC(btcoex_wl_active_time, "BT coexistence wlan active time");
+
+static int ath9k_btcoex_wl_qc_time;
+module_param_named(btcoex_wl_qc_time, ath9k_btcoex_wl_qc_time, int, 0444);
+MODULE_PARM_DESC(btcoex_wl_qc_time, "BT coexistence wlan quiet collision time");
 #endif
 
 bool is_ath9k_unloaded;
@@ -611,7 +631,13 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 	sc->btcoex.duty_cycle = ath9k_btcoex_duty_cycle;
+	ah->btcoex_hw.config.bt_time_extend = ath9k_btcoex_time_extend;
+	ah->btcoex_hw.config.bt_priority_time = ath9k_btcoex_priority_time;
+	ah->btcoex_hw.config.bt_first_slot_time = ath9k_btcoex_first_slot_time;
+	ah->btcoex_hw.config.wl_active_time = ath9k_btcoex_wl_active_time;
+	ah->btcoex_hw.config.wl_qc_time = ath9k_btcoex_wl_qc_time;
 #endif
+
 	/*
 	 * Platform quirks.
 	 */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] ath9k: disable ACK_CTS for SOC chips in PTA mode
  2016-11-24  6:53 [PATCH 1/3] ath9k: Add a module parameter to set btcoex duty cycle miaoqing
  2016-11-24  6:53 ` [PATCH 2/3] ath9k: export configurable parameters of PTA miaoqing
@ 2016-11-24  6:53 ` miaoqing
  2016-11-25 15:25 ` [PATCH 1/3] ath9k: Add a module parameter to set btcoex duty cycle Valo, Kalle
  2 siblings, 0 replies; 5+ messages in thread
From: miaoqing @ 2016-11-24  6:53 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, ath9k-devel, Miaoqing Pan

From: Miaoqing Pan <miaoqing@codeaurora.org>

If the ACK_CTS is enabled, MAC will send an ACK or CTS in response
to a received frame, but it is a interfering packet for the BT(or other)
in the PTA cycle, which will sufficient corrupt the received packets.

Only disable it for SOC chips in PTA(slotted) mode.

Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>
---
 drivers/net/wireless/ath/ath9k/btcoex.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index 6d15dd3..7e24640 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -290,6 +290,7 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
 	struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
 	u32  val;
 	int i;
+	int coex_mode = MS(btcoex->bt_coex_mode, AR_BT_MODE);
 
 	/*
 	 * Program coex mode and weight registers to
@@ -319,7 +320,11 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
 		REG_WRITE(ah, 0x50040, val);
 	}
 
-	REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
+	if (AR_SREV_SOC(ah) && (coex_mode == ATH_BT_COEX_MODE_SLOTTED))
+		REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 0);
+	else
+		REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
+
 	REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
 
 	ath9k_hw_gpio_request_out(ah, btcoex->wlanactive_gpio,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/3] ath9k: Add a module parameter to set btcoex duty cycle
  2016-11-24  6:53 [PATCH 1/3] ath9k: Add a module parameter to set btcoex duty cycle miaoqing
  2016-11-24  6:53 ` [PATCH 2/3] ath9k: export configurable parameters of PTA miaoqing
  2016-11-24  6:53 ` [PATCH 3/3] ath9k: disable ACK_CTS for SOC chips in PTA mode miaoqing
@ 2016-11-25 15:25 ` Valo, Kalle
  2 siblings, 0 replies; 5+ messages in thread
From: Valo, Kalle @ 2016-11-25 15:25 UTC (permalink / raw)
  To: miaoqing; +Cc: linux-wireless, ath9k-devel

miaoqing@codeaurora.org writes:

> From: Miaoqing Pan <miaoqing@codeaurora.org>
>
> btcoex duty cyle allows user to balance the performance
> between WLAN and BT.
>
> Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>

[...]

> --- a/drivers/net/wireless/ath/ath9k/init.c
> +++ b/drivers/net/wireless/ath/ath9k/init.c
> @@ -73,6 +73,12 @@ struct ath9k_eeprom_ctx {
> =20
>  #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
> =20
> +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
> +static int ath9k_btcoex_duty_cycle =3D ATH_BTCOEX_DEF_DUTY_CYCLE;
> +module_param_named(btcoex_duty_cycle, ath9k_btcoex_duty_cycle, int, 0444=
);
> +MODULE_PARM_DESC(btcoex_duty_cycle, "BT coexistence duty cycle");
> +#endif

I don't think module parameters are really meant for providing protocol
settings like this, especially as these would be global for all radios.
nl80211 (if used in production) or debugfs (if used only in testing) are
much better choises.

--=20
Kalle Valo=

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/3] ath9k: export configurable parameters of PTA
  2016-11-24  6:53 ` [PATCH 2/3] ath9k: export configurable parameters of PTA miaoqing
@ 2016-11-25 15:28   ` Valo, Kalle
  0 siblings, 0 replies; 5+ messages in thread
From: Valo, Kalle @ 2016-11-25 15:28 UTC (permalink / raw)
  To: miaoqing; +Cc: linux-wireless, ath9k-devel

miaoqing@codeaurora.org writes:

> From: Miaoqing Pan <miaoqing@codeaurora.org>
>
> Export time_extend, pritority_time, first_slot_time, wl_active_time
> and wl_qc_time those PTA(aka slotted mode) configurable parameters,
> allow user to change/debug the timing easily.
>
> Also set wl_active_time and wl_qc_time default value to 0, as in this
> period WLAN chip may send out ACK, and it will corrupt the BT(or other)
> received packet in the PTA cycle.
>
> Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org>

Please try to always write commit logs so that everyone will understand,
for example spelling out what PTA means would be nice.

> --- a/drivers/net/wireless/ath/ath9k/init.c
> +++ b/drivers/net/wireless/ath/ath9k/init.c
> @@ -77,6 +77,26 @@ struct ath9k_eeprom_ctx {
>  static int ath9k_btcoex_duty_cycle =3D ATH_BTCOEX_DEF_DUTY_CYCLE;
>  module_param_named(btcoex_duty_cycle, ath9k_btcoex_duty_cycle, int, 0444=
);
>  MODULE_PARM_DESC(btcoex_duty_cycle, "BT coexistence duty cycle");
> +
> +static int ath9k_btcoex_time_extend;
> +module_param_named(btcoex_time_extend, ath9k_btcoex_time_extend, int, 04=
44);
> +MODULE_PARM_DESC(btcoex_time_extend, "BT coexistence time extend");
> +
> +static int ath9k_btcoex_priority_time =3D 2;
> +module_param_named(btcoex_priority_time, ath9k_btcoex_priority_time, int=
, 0444);
> +MODULE_PARM_DESC(btcoex_priority_time, "BT coexistence priority time");
> +
> +static int ath9k_btcoex_first_slot_time =3D 5;
> +module_param_named(btcoex_first_slot_time, ath9k_btcoex_first_slot_time,=
 int, 0444);
> +MODULE_PARM_DESC(btcoex_first_slot_time, "BT coexistence first slot time=
");
> +
> +static int ath9k_btcoex_wl_active_time;
> +module_param_named(btcoex_wl_active_time, ath9k_btcoex_wl_active_time, i=
nt, 0444);
> +MODULE_PARM_DESC(btcoex_wl_active_time, "BT coexistence wlan active time=
");
> +
> +static int ath9k_btcoex_wl_qc_time;
> +module_param_named(btcoex_wl_qc_time, ath9k_btcoex_wl_qc_time, int, 0444=
);
> +MODULE_PARM_DESC(btcoex_wl_qc_time, "BT coexistence wlan quiet collision=
 time");
>  #endif

Same as with the previous patch, I don't think these should be set via
module parameters.

--=20
Kalle Valo=

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-11-25 15:28 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-24  6:53 [PATCH 1/3] ath9k: Add a module parameter to set btcoex duty cycle miaoqing
2016-11-24  6:53 ` [PATCH 2/3] ath9k: export configurable parameters of PTA miaoqing
2016-11-25 15:28   ` Valo, Kalle
2016-11-24  6:53 ` [PATCH 3/3] ath9k: disable ACK_CTS for SOC chips in PTA mode miaoqing
2016-11-25 15:25 ` [PATCH 1/3] ath9k: Add a module parameter to set btcoex duty cycle Valo, Kalle

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).