dmaengine.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V4 0/3] dmaengine: dw-axi-dmac: support parallel memory <--> peripheral transfers
@ 2021-07-20 17:47 pandith.n
  2021-07-20 17:47 ` [PATCH V4 1/3] dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel pandith.n
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: pandith.n @ 2021-07-20 17:47 UTC (permalink / raw)
  To: Eugeniy.Paltsev, vkoul, dmaengine
  Cc: lakshmi.bai.raja.subramanian, kris.pan,
	mallikarjunappa.sangannavar, Srikanth.Thokala, Pandith N

From: Pandith N <pandith.n@intel.com>

Added support for multiple DMA_MEM_TO_DEV, DMA_DEV_TO_MEM transfers in
parallel. Peripherals can use DMA for both transmit and receive
operations in parallel.

To setup DMA handshaking, the peripheral source number to be programmed
in respective channel select slot of AXIDMA_CTRL_DMA_HS_SEL. No need to
check for free slot in dw_axi_dma_set_hw_channel().

The channel slot used in AXIDMA_CTRL_DMA_HS_SEL needs to be set in
src_per/dst_per of CHx_CFG register

Burst length, DMA HW capability set in dt-binding is now used in driver.

Changes since v1:
Added new macro, magic mask for HW handshake select.
Typos in commit message are corrected

Changes since v2:
Split the patch as follows
Patch 1: Remove free slot check algorithm in dw_axi_dma_set_hw_channel()
Patch 2: The channel slot used needs to be set in CHx_CFG src/dst_per
Patch 3: Usage of burst length HW capability

Changes in v3:
Patch 1: Added description for hardware handshake settings

Pandith N (3):
  dmaengine: dw-axi-dmac: Remove free slot check algorithm in
    dw_axi_dma_set_hw_channel
  dmaengine: dw-axi-dmac: support parallel memory <--> peripheral
    transfers
  dmaengine: dw-axi-dmac: Burst length settings

 .../dma/dw-axi-dmac/dw-axi-dmac-platform.c    | 56 +++++++++----------
 drivers/dma/dw-axi-dmac/dw-axi-dmac.h         |  4 ++
 2 files changed, 29 insertions(+), 31 deletions(-)

-- 
2.17.1


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

* [PATCH V4 1/3] dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel
  2021-07-20 17:47 [PATCH V4 0/3] dmaengine: dw-axi-dmac: support parallel memory <--> peripheral transfers pandith.n
@ 2021-07-20 17:47 ` pandith.n
  2021-07-28  7:22   ` Vinod Koul
  2021-07-20 17:47 ` [PATCH V4 2/3] dmaengine: dw-axi-dmac: support parallel memory <--> peripheral transfers pandith.n
  2021-07-20 17:47 ` [PATCH V4 3/3] dmaengine: dw-axi-dmac: Burst length settings pandith.n
  2 siblings, 1 reply; 6+ messages in thread
From: pandith.n @ 2021-07-20 17:47 UTC (permalink / raw)
  To: Eugeniy.Paltsev, vkoul, dmaengine
  Cc: lakshmi.bai.raja.subramanian, kris.pan,
	mallikarjunappa.sangannavar, Srikanth.Thokala, Pandith N

From: Pandith N <pandith.n@intel.com>

Removed free slot check algorithm in dw_axi_dma_set_hw_channel. For 8
DMA channels, use respective handshake slot in DMA_HS_SEL APB register.

For every channel, an dedicated slot is provided in  hardware handshake
register AXIDMA_CTRL_DMA_HS_SEL_n. Peripheral source number is
programmed in respective channel slots.

Signed-off-by: Pandith N <pandith.n@intel.com>
Tested-by: Pan Kris <kris.pan@intel.com>
---
 .../dma/dw-axi-dmac/dw-axi-dmac-platform.c    | 49 +++++++------------
 drivers/dma/dw-axi-dmac/dw-axi-dmac.h         |  2 +
 2 files changed, 21 insertions(+), 30 deletions(-)

diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index d9e4ac3edb4e..6b871e20ae27 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -470,19 +470,14 @@ static void dma_chan_free_chan_resources(struct dma_chan *dchan)
 	pm_runtime_put(chan->chip->dev);
 }
 
-static void dw_axi_dma_set_hw_channel(struct axi_dma_chip *chip,
-				      u32 handshake_num, bool set)
+static int dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set)
 {
-	unsigned long start = 0;
-	unsigned long reg_value;
-	unsigned long reg_mask;
-	unsigned long reg_set;
-	unsigned long mask;
-	unsigned long val;
+	struct axi_dma_chip *chip = chan->chip;
+	unsigned long reg_value, val;
 
 	if (!chip->apb_regs) {
 		dev_dbg(chip->dev, "apb_regs not initialized\n");
-		return;
+		return -EINVAL;
 	}
 
 	/*
@@ -490,26 +485,22 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chip *chip,
 	 * Lock the DMA channel by assign a handshake number to the channel.
 	 * Unlock the DMA channel by assign 0x3F to the channel.
 	 */
-	if (set) {
-		reg_set = UNUSED_CHANNEL;
-		val = handshake_num;
-	} else {
-		reg_set = handshake_num;
+	if (set)
+		val = chan->hw_handshake_num;
+	else
 		val = UNUSED_CHANNEL;
-	}
 
 	reg_value = lo_hi_readq(chip->apb_regs + DMAC_APB_HW_HS_SEL_0);
 
-	for_each_set_clump8(start, reg_mask, &reg_value, 64) {
-		if (reg_mask == reg_set) {
-			mask = GENMASK_ULL(start + 7, start);
-			reg_value &= ~mask;
-			reg_value |= rol64(val, start);
-			lo_hi_writeq(reg_value,
-				     chip->apb_regs + DMAC_APB_HW_HS_SEL_0);
-			break;
-		}
-	}
+	/* Channel is already allocated, set handshake as per channel ID */
+	/* 64 bit write should handle for 8 channels */
+
+	reg_value &= ~(DMA_APB_HS_SEL_MASK <<
+			(chan->id * DMA_APB_HS_SEL_BIT_SIZE));
+	reg_value |= (val << (chan->id * DMA_APB_HS_SEL_BIT_SIZE));
+	lo_hi_writeq(reg_value, chip->apb_regs + DMAC_APB_HW_HS_SEL_0);
+
+	return 0;
 }
 
 /*
@@ -742,7 +733,7 @@ dw_axi_dma_chan_prep_cyclic(struct dma_chan *dchan, dma_addr_t dma_addr,
 		llp = hw_desc->llp;
 	} while (total_segments);
 
-	dw_axi_dma_set_hw_channel(chan->chip, chan->hw_handshake_num, true);
+	dw_axi_dma_set_hw_channel(chan, true);
 
 	return vchan_tx_prep(&chan->vc, &desc->vd, flags);
 
@@ -822,7 +813,7 @@ dw_axi_dma_chan_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
 		llp = hw_desc->llp;
 	} while (num_sgs);
 
-	dw_axi_dma_set_hw_channel(chan->chip, chan->hw_handshake_num, true);
+	dw_axi_dma_set_hw_channel(chan, true);
 
 	return vchan_tx_prep(&chan->vc, &desc->vd, flags);
 
@@ -1098,8 +1089,7 @@ static int dma_chan_terminate_all(struct dma_chan *dchan)
 			 "%s failed to stop\n", axi_chan_name(chan));
 
 	if (chan->direction != DMA_MEM_TO_MEM)
-		dw_axi_dma_set_hw_channel(chan->chip,
-					  chan->hw_handshake_num, false);
+		dw_axi_dma_set_hw_channel(chan, false);
 	if (chan->direction == DMA_MEM_TO_DEV)
 		dw_axi_dma_set_byte_halfword(chan, false);
 
@@ -1365,7 +1355,6 @@ static int dw_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-
 	INIT_LIST_HEAD(&dw->dma.channels);
 	for (i = 0; i < hdata->nr_channels; i++) {
 		struct axi_dma_chan *chan = &dw->chan[i];
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
index b69897887c76..358f553cafe9 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
@@ -184,6 +184,8 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan)
 #define DMAC_APB_HALFWORD_WR_CH_EN	0x020 /* DMAC Halfword write enables */
 
 #define UNUSED_CHANNEL		0x3F /* Set unused DMA channel to 0x3F */
+#define DMA_APB_HS_SEL_BIT_SIZE	0x08 /* HW handshake bits per channel */
+#define DMA_APB_HS_SEL_MASK	0xFF /* HW handshake select masks */
 #define MAX_BLOCK_SIZE		0x1000 /* 1024 blocks * 4 bytes data width */
 
 /* DMAC_CFG */
-- 
2.17.1


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

* [PATCH V4 2/3] dmaengine: dw-axi-dmac: support parallel memory <--> peripheral transfers
  2021-07-20 17:47 [PATCH V4 0/3] dmaengine: dw-axi-dmac: support parallel memory <--> peripheral transfers pandith.n
  2021-07-20 17:47 ` [PATCH V4 1/3] dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel pandith.n
@ 2021-07-20 17:47 ` pandith.n
  2021-07-20 17:47 ` [PATCH V4 3/3] dmaengine: dw-axi-dmac: Burst length settings pandith.n
  2 siblings, 0 replies; 6+ messages in thread
From: pandith.n @ 2021-07-20 17:47 UTC (permalink / raw)
  To: Eugeniy.Paltsev, vkoul, dmaengine
  Cc: lakshmi.bai.raja.subramanian, kris.pan,
	mallikarjunappa.sangannavar, Srikanth.Thokala, Pandith N

From: Pandith N <pandith.n@intel.com>

Added support for multiple DMA_MEM_TO_DEV, DMA_DEV_TO_MEM transfers in
parallel. This is required for peripherals using DMA for transmit and
receive operations at the same time. APB slot number needs to be
programmed in channel hardware handshaking interface

Signed-off-by: Pandith N <pandith.n@intel.com>
Tested-by: Pan Kris <kris.pan@intel.com>
---
 drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 4 ++++
 drivers/dma/dw-axi-dmac/dw-axi-dmac.h          | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index 6b871e20ae27..2c9a3cc204e2 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -363,12 +363,16 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
 			DWAXIDMAC_TT_FC_MEM_TO_PER_DST :
 			DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC)
 			<< CH_CFG_H_TT_FC_POS;
+		if (chan->chip->apb_regs)
+			reg |= (chan->id << CH_CFG_H_DST_PER_POS);
 		break;
 	case DMA_DEV_TO_MEM:
 		reg |= (chan->config.device_fc ?
 			DWAXIDMAC_TT_FC_PER_TO_MEM_SRC :
 			DWAXIDMAC_TT_FC_PER_TO_MEM_DMAC)
 			<< CH_CFG_H_TT_FC_POS;
+		if (chan->chip->apb_regs)
+			reg |= (chan->id << CH_CFG_H_SRC_PER_POS);
 		break;
 	default:
 		break;
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
index 358f553cafe9..380005afde16 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
@@ -258,6 +258,8 @@ enum {
 
 /* CH_CFG_H */
 #define CH_CFG_H_PRIORITY_POS		17
+#define CH_CFG_H_DST_PER_POS		12
+#define CH_CFG_H_SRC_PER_POS		7
 #define CH_CFG_H_HS_SEL_DST_POS		4
 #define CH_CFG_H_HS_SEL_SRC_POS		3
 enum {
-- 
2.17.1


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

* [PATCH V4 3/3] dmaengine: dw-axi-dmac: Burst length settings
  2021-07-20 17:47 [PATCH V4 0/3] dmaengine: dw-axi-dmac: support parallel memory <--> peripheral transfers pandith.n
  2021-07-20 17:47 ` [PATCH V4 1/3] dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel pandith.n
  2021-07-20 17:47 ` [PATCH V4 2/3] dmaengine: dw-axi-dmac: support parallel memory <--> peripheral transfers pandith.n
@ 2021-07-20 17:47 ` pandith.n
  2 siblings, 0 replies; 6+ messages in thread
From: pandith.n @ 2021-07-20 17:47 UTC (permalink / raw)
  To: Eugeniy.Paltsev, vkoul, dmaengine
  Cc: lakshmi.bai.raja.subramanian, kris.pan,
	mallikarjunappa.sangannavar, Srikanth.Thokala, Pandith N

From: Pandith N <pandith.n@intel.com>

Burst length, DMA HW capability set in dt-binding is now used in driver.

Signed-off-by: Pandith N <pandith.n@intel.com>
Tested-by: Pan Kris <kris.pan@intel.com>
---
 drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index 2c9a3cc204e2..aace3751c56e 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -1290,7 +1290,7 @@ static int parse_device_properties(struct axi_dma_chip *chip)
 			return -EINVAL;
 
 		chip->dw->hdata->restrict_axi_burst_len = true;
-		chip->dw->hdata->axi_rw_burst_len = tmp - 1;
+		chip->dw->hdata->axi_rw_burst_len = tmp;
 	}
 
 	return 0;
@@ -1379,6 +1379,7 @@ static int dw_probe(struct platform_device *pdev)
 
 	/* DMA capabilities */
 	dw->dma.chancnt = hdata->nr_channels;
+	dw->dma.max_burst = hdata->axi_rw_burst_len;
 	dw->dma.src_addr_widths = AXI_DMA_BUSWIDTHS;
 	dw->dma.dst_addr_widths = AXI_DMA_BUSWIDTHS;
 	dw->dma.directions = BIT(DMA_MEM_TO_MEM);
-- 
2.17.1


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

* Re: [PATCH V4 1/3] dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel
  2021-07-20 17:47 ` [PATCH V4 1/3] dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel pandith.n
@ 2021-07-28  7:22   ` Vinod Koul
  2021-07-29 10:35     ` N, Pandith
  0 siblings, 1 reply; 6+ messages in thread
From: Vinod Koul @ 2021-07-28  7:22 UTC (permalink / raw)
  To: pandith.n
  Cc: Eugeniy.Paltsev, dmaengine, lakshmi.bai.raja.subramanian,
	kris.pan, mallikarjunappa.sangannavar, Srikanth.Thokala

On 20-07-21, 23:17, pandith.n@intel.com wrote:
> From: Pandith N <pandith.n@intel.com>
> 
> Removed free slot check algorithm in dw_axi_dma_set_hw_channel. For 8
> DMA channels, use respective handshake slot in DMA_HS_SEL APB register.
> 
> For every channel, an dedicated slot is provided in  hardware handshake
> register AXIDMA_CTRL_DMA_HS_SEL_n. Peripheral source number is
> programmed in respective channel slots.
> 
> Signed-off-by: Pandith N <pandith.n@intel.com>
> Tested-by: Pan Kris <kris.pan@intel.com>
> ---
>  .../dma/dw-axi-dmac/dw-axi-dmac-platform.c    | 49 +++++++------------
>  drivers/dma/dw-axi-dmac/dw-axi-dmac.h         |  2 +
>  2 files changed, 21 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> index d9e4ac3edb4e..6b871e20ae27 100644
> --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> @@ -470,19 +470,14 @@ static void dma_chan_free_chan_resources(struct dma_chan *dchan)
>  	pm_runtime_put(chan->chip->dev);
>  }
>  
> -static void dw_axi_dma_set_hw_channel(struct axi_dma_chip *chip,
> -				      u32 handshake_num, bool set)
> +static int dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set)

what is point of returning error if that is not checked and action taken
in caller?

>  {
> -	unsigned long start = 0;
> -	unsigned long reg_value;
> -	unsigned long reg_mask;
> -	unsigned long reg_set;
> -	unsigned long mask;
> -	unsigned long val;
> +	struct axi_dma_chip *chip = chan->chip;
> +	unsigned long reg_value, val;
>  
>  	if (!chip->apb_regs) {
>  		dev_dbg(chip->dev, "apb_regs not initialized\n");
> -		return;
> +		return -EINVAL;

should the above log not be error now?
-- 
~Vinod

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

* RE: [PATCH V4 1/3] dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel
  2021-07-28  7:22   ` Vinod Koul
@ 2021-07-29 10:35     ` N, Pandith
  0 siblings, 0 replies; 6+ messages in thread
From: N, Pandith @ 2021-07-29 10:35 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Eugeniy.Paltsev, dmaengine, Raja Subramanian, Lakshmi Bai, Pan,
	Kris, Sangannavar, Mallikarjunappa, Thokala, Srikanth



> -----Original Message-----
> From: Vinod Koul <vkoul@kernel.org>
> Sent: Wednesday, July 28, 2021 12:53 PM
> To: N, Pandith <pandith.n@intel.com>
> Cc: Eugeniy.Paltsev@synopsys.com; dmaengine@vger.kernel.org; Raja
> Subramanian, Lakshmi Bai <lakshmi.bai.raja.subramanian@intel.com>; Pan, Kris
> <kris.pan@intel.com>; Sangannavar, Mallikarjunappa
> <mallikarjunappa.sangannavar@intel.com>; Thokala, Srikanth
> <srikanth.thokala@intel.com>
> Subject: Re: [PATCH V4 1/3] dmaengine: dw-axi-dmac: Remove free slot check
> algorithm in dw_axi_dma_set_hw_channel
> 
> On 20-07-21, 23:17, pandith.n@intel.com wrote:
> > From: Pandith N <pandith.n@intel.com>
> >
> > Removed free slot check algorithm in dw_axi_dma_set_hw_channel. For 8
> > DMA channels, use respective handshake slot in DMA_HS_SEL APB register.
> >
> > For every channel, an dedicated slot is provided in  hardware
> > handshake register AXIDMA_CTRL_DMA_HS_SEL_n. Peripheral source number
> > is programmed in respective channel slots.
> >
> > Signed-off-by: Pandith N <pandith.n@intel.com>
> > Tested-by: Pan Kris <kris.pan@intel.com>
> > ---
> >  .../dma/dw-axi-dmac/dw-axi-dmac-platform.c    | 49 +++++++------------
> >  drivers/dma/dw-axi-dmac/dw-axi-dmac.h         |  2 +
> >  2 files changed, 21 insertions(+), 30 deletions(-)
> >
> > diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> > b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> > index d9e4ac3edb4e..6b871e20ae27 100644
> > --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> > +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> > @@ -470,19 +470,14 @@ static void dma_chan_free_chan_resources(struct
> dma_chan *dchan)
> >  	pm_runtime_put(chan->chip->dev);
> >  }
> >
> > -static void dw_axi_dma_set_hw_channel(struct axi_dma_chip *chip,
> > -				      u32 handshake_num, bool set)
> > +static int dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool
> > +set)
> 
> what is point of returning error if that is not checked and action taken in caller?
> 
Yes, change of function return type is not required here.  API signature will be:
static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set)
> >  {
> > -	unsigned long start = 0;
> > -	unsigned long reg_value;
> > -	unsigned long reg_mask;
> > -	unsigned long reg_set;
> > -	unsigned long mask;
> > -	unsigned long val;
> > +	struct axi_dma_chip *chip = chan->chip;
> > +	unsigned long reg_value, val;
> >
> >  	if (!chip->apb_regs) {
> >  		dev_dbg(chip->dev, "apb_regs not initialized\n");
> > -		return;
> > +		return -EINVAL;
> 
> should the above log not be error now?
Will change this to dev_err
> --
> ~Vinod

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

end of thread, other threads:[~2021-07-29 10:36 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-20 17:47 [PATCH V4 0/3] dmaengine: dw-axi-dmac: support parallel memory <--> peripheral transfers pandith.n
2021-07-20 17:47 ` [PATCH V4 1/3] dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel pandith.n
2021-07-28  7:22   ` Vinod Koul
2021-07-29 10:35     ` N, Pandith
2021-07-20 17:47 ` [PATCH V4 2/3] dmaengine: dw-axi-dmac: support parallel memory <--> peripheral transfers pandith.n
2021-07-20 17:47 ` [PATCH V4 3/3] dmaengine: dw-axi-dmac: Burst length settings pandith.n

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).