Commit 7b6da7fe authored by Sudeep Holla's avatar Sudeep Holla Committed by Jassi Brar

mailbox: pcc: Use PCC mailbox channel pointer instead of standard

Now that we have all the shared memory region information populated in
the pcc_mbox_chan, let us propagate the pointer to the same as the
return value to pcc_mbox_request channel.

This eliminates the need for the individual users of PCC mailbox to
parse the PCCT subspace entries and fetch the shmem information. This
also eliminates the need for PCC mailbox controller to set con_priv to
PCCT subspace entries. This is required as con_priv is private to the
controller driver to attach private data associated with the channel and
not meant to be used by the mailbox client/users.

Let us convert all the users of pcc_mbox_{request,free}_channel to use
new interface.

Cc: Jean Delvare <jdelvare@suse.com>
Signed-off-by: default avatarSudeep Holla <sudeep.holla@arm.com>
Acked-by: default avatarWolfram Sang <wsa@kernel.org>
Acked-by: default avatarGuenter Roeck <linux@roeck-us.net>
Signed-off-by: default avatarJassi Brar <jaswinder.singh@linaro.org>
parent 0f2591e2
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
#include <acpi/cppc_acpi.h> #include <acpi/cppc_acpi.h>
struct cppc_pcc_data { struct cppc_pcc_data {
struct mbox_chan *pcc_channel; struct pcc_mbox_chan *pcc_channel;
void __iomem *pcc_comm_addr; void __iomem *pcc_comm_addr;
bool pcc_channel_acquired; bool pcc_channel_acquired;
unsigned int deadline_us; unsigned int deadline_us;
...@@ -295,7 +295,7 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd) ...@@ -295,7 +295,7 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd)
pcc_ss_data->platform_owns_pcc = true; pcc_ss_data->platform_owns_pcc = true;
/* Ring doorbell */ /* Ring doorbell */
ret = mbox_send_message(pcc_ss_data->pcc_channel, &cmd); ret = mbox_send_message(pcc_ss_data->pcc_channel->mchan, &cmd);
if (ret < 0) { if (ret < 0) {
pr_err("Err sending PCC mbox message. ss: %d cmd:%d, ret:%d\n", pr_err("Err sending PCC mbox message. ss: %d cmd:%d, ret:%d\n",
pcc_ss_id, cmd, ret); pcc_ss_id, cmd, ret);
...@@ -308,10 +308,10 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd) ...@@ -308,10 +308,10 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd)
if (pcc_ss_data->pcc_mrtt) if (pcc_ss_data->pcc_mrtt)
pcc_ss_data->last_cmd_cmpl_time = ktime_get(); pcc_ss_data->last_cmd_cmpl_time = ktime_get();
if (pcc_ss_data->pcc_channel->mbox->txdone_irq) if (pcc_ss_data->pcc_channel->mchan->mbox->txdone_irq)
mbox_chan_txdone(pcc_ss_data->pcc_channel, ret); mbox_chan_txdone(pcc_ss_data->pcc_channel->mchan, ret);
else else
mbox_client_txdone(pcc_ss_data->pcc_channel, ret); mbox_client_txdone(pcc_ss_data->pcc_channel->mchan, ret);
end: end:
if (cmd == CMD_WRITE) { if (cmd == CMD_WRITE) {
...@@ -493,46 +493,33 @@ EXPORT_SYMBOL_GPL(acpi_get_psd_map); ...@@ -493,46 +493,33 @@ EXPORT_SYMBOL_GPL(acpi_get_psd_map);
static int register_pcc_channel(int pcc_ss_idx) static int register_pcc_channel(int pcc_ss_idx)
{ {
struct acpi_pcct_hw_reduced *cppc_ss; struct pcc_mbox_chan *pcc_chan;
u64 usecs_lat; u64 usecs_lat;
if (pcc_ss_idx >= 0) { if (pcc_ss_idx >= 0) {
pcc_data[pcc_ss_idx]->pcc_channel = pcc_chan = pcc_mbox_request_channel(&cppc_mbox_cl, pcc_ss_idx);
pcc_mbox_request_channel(&cppc_mbox_cl, pcc_ss_idx);
if (IS_ERR(pcc_data[pcc_ss_idx]->pcc_channel)) { if (IS_ERR(pcc_chan)) {
pr_err("Failed to find PCC channel for subspace %d\n", pr_err("Failed to find PCC channel for subspace %d\n",
pcc_ss_idx); pcc_ss_idx);
return -ENODEV; return -ENODEV;
} }
/* pcc_data[pcc_ss_idx]->pcc_channel = pcc_chan;
* The PCC mailbox controller driver should
* have parsed the PCCT (global table of all
* PCC channels) and stored pointers to the
* subspace communication region in con_priv.
*/
cppc_ss = (pcc_data[pcc_ss_idx]->pcc_channel)->con_priv;
if (!cppc_ss) {
pr_err("No PCC subspace found for %d CPPC\n",
pcc_ss_idx);
return -ENODEV;
}
/* /*
* cppc_ss->latency is just a Nominal value. In reality * cppc_ss->latency is just a Nominal value. In reality
* the remote processor could be much slower to reply. * the remote processor could be much slower to reply.
* So add an arbitrary amount of wait on top of Nominal. * So add an arbitrary amount of wait on top of Nominal.
*/ */
usecs_lat = NUM_RETRIES * cppc_ss->latency; usecs_lat = NUM_RETRIES * pcc_chan->latency;
pcc_data[pcc_ss_idx]->deadline_us = usecs_lat; pcc_data[pcc_ss_idx]->deadline_us = usecs_lat;
pcc_data[pcc_ss_idx]->pcc_mrtt = cppc_ss->min_turnaround_time; pcc_data[pcc_ss_idx]->pcc_mrtt = pcc_chan->min_turnaround_time;
pcc_data[pcc_ss_idx]->pcc_mpar = cppc_ss->max_access_rate; pcc_data[pcc_ss_idx]->pcc_mpar = pcc_chan->max_access_rate;
pcc_data[pcc_ss_idx]->pcc_nominal = cppc_ss->latency; pcc_data[pcc_ss_idx]->pcc_nominal = pcc_chan->latency;
pcc_data[pcc_ss_idx]->pcc_comm_addr = pcc_data[pcc_ss_idx]->pcc_comm_addr =
acpi_os_ioremap(cppc_ss->base_address, cppc_ss->length); acpi_os_ioremap(pcc_chan->shmem_base_addr,
pcc_chan->shmem_size);
if (!pcc_data[pcc_ss_idx]->pcc_comm_addr) { if (!pcc_data[pcc_ss_idx]->pcc_comm_addr) {
pr_err("Failed to ioremap PCC comm region mem for %d\n", pr_err("Failed to ioremap PCC comm region mem for %d\n",
pcc_ss_idx); pcc_ss_idx);
......
...@@ -93,6 +93,7 @@ struct slimpro_resp_msg { ...@@ -93,6 +93,7 @@ struct slimpro_resp_msg {
struct xgene_hwmon_dev { struct xgene_hwmon_dev {
struct device *dev; struct device *dev;
struct mbox_chan *mbox_chan; struct mbox_chan *mbox_chan;
struct pcc_mbox_chan *pcc_chan;
struct mbox_client mbox_client; struct mbox_client mbox_client;
int mbox_idx; int mbox_idx;
...@@ -652,7 +653,7 @@ static int xgene_hwmon_probe(struct platform_device *pdev) ...@@ -652,7 +653,7 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
goto out_mbox_free; goto out_mbox_free;
} }
} else { } else {
struct acpi_pcct_hw_reduced *cppc_ss; struct pcc_mbox_chan *pcc_chan;
const struct acpi_device_id *acpi_id; const struct acpi_device_id *acpi_id;
int version; int version;
...@@ -671,26 +672,16 @@ static int xgene_hwmon_probe(struct platform_device *pdev) ...@@ -671,26 +672,16 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
} }
cl->rx_callback = xgene_hwmon_pcc_rx_cb; cl->rx_callback = xgene_hwmon_pcc_rx_cb;
ctx->mbox_chan = pcc_mbox_request_channel(cl, ctx->mbox_idx); pcc_chan = pcc_mbox_request_channel(cl, ctx->mbox_idx);
if (IS_ERR(ctx->mbox_chan)) { if (IS_ERR(pcc_chan)) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"PPC channel request failed\n"); "PPC channel request failed\n");
rc = -ENODEV; rc = -ENODEV;
goto out_mbox_free; goto out_mbox_free;
} }
/* ctx->pcc_chan = pcc_chan;
* The PCC mailbox controller driver should ctx->mbox_chan = pcc_chan->mchan;
* have parsed the PCCT (global table of all
* PCC channels) and stored pointers to the
* subspace communication region in con_priv.
*/
cppc_ss = ctx->mbox_chan->con_priv;
if (!cppc_ss) {
dev_err(&pdev->dev, "PPC subspace not found\n");
rc = -ENODEV;
goto out;
}
if (!ctx->mbox_chan->mbox->txdone_irq) { if (!ctx->mbox_chan->mbox->txdone_irq) {
dev_err(&pdev->dev, "PCC IRQ not supported\n"); dev_err(&pdev->dev, "PCC IRQ not supported\n");
...@@ -702,16 +693,16 @@ static int xgene_hwmon_probe(struct platform_device *pdev) ...@@ -702,16 +693,16 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
* This is the shared communication region * This is the shared communication region
* for the OS and Platform to communicate over. * for the OS and Platform to communicate over.
*/ */
ctx->comm_base_addr = cppc_ss->base_address; ctx->comm_base_addr = pcc_chan->shmem_base_addr;
if (ctx->comm_base_addr) { if (ctx->comm_base_addr) {
if (version == XGENE_HWMON_V2) if (version == XGENE_HWMON_V2)
ctx->pcc_comm_addr = (void __force *)ioremap( ctx->pcc_comm_addr = (void __force *)ioremap(
ctx->comm_base_addr, ctx->comm_base_addr,
cppc_ss->length); pcc_chan->shmem_size);
else else
ctx->pcc_comm_addr = memremap( ctx->pcc_comm_addr = memremap(
ctx->comm_base_addr, ctx->comm_base_addr,
cppc_ss->length, pcc_chan->shmem_size,
MEMREMAP_WB); MEMREMAP_WB);
} else { } else {
dev_err(&pdev->dev, "Failed to get PCC comm region\n"); dev_err(&pdev->dev, "Failed to get PCC comm region\n");
...@@ -727,11 +718,11 @@ static int xgene_hwmon_probe(struct platform_device *pdev) ...@@ -727,11 +718,11 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
} }
/* /*
* cppc_ss->latency is just a Nominal value. In reality * pcc_chan->latency is just a Nominal value. In reality
* the remote processor could be much slower to reply. * the remote processor could be much slower to reply.
* So add an arbitrary amount of wait on top of Nominal. * So add an arbitrary amount of wait on top of Nominal.
*/ */
ctx->usecs_lat = PCC_NUM_RETRIES * cppc_ss->latency; ctx->usecs_lat = PCC_NUM_RETRIES * pcc_chan->latency;
} }
ctx->hwmon_dev = hwmon_device_register_with_groups(ctx->dev, ctx->hwmon_dev = hwmon_device_register_with_groups(ctx->dev,
...@@ -757,7 +748,7 @@ static int xgene_hwmon_probe(struct platform_device *pdev) ...@@ -757,7 +748,7 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
if (acpi_disabled) if (acpi_disabled)
mbox_free_channel(ctx->mbox_chan); mbox_free_channel(ctx->mbox_chan);
else else
pcc_mbox_free_channel(ctx->mbox_chan); pcc_mbox_free_channel(ctx->pcc_chan);
out_mbox_free: out_mbox_free:
kfifo_free(&ctx->async_msg_fifo); kfifo_free(&ctx->async_msg_fifo);
...@@ -773,7 +764,7 @@ static int xgene_hwmon_remove(struct platform_device *pdev) ...@@ -773,7 +764,7 @@ static int xgene_hwmon_remove(struct platform_device *pdev)
if (acpi_disabled) if (acpi_disabled)
mbox_free_channel(ctx->mbox_chan); mbox_free_channel(ctx->mbox_chan);
else else
pcc_mbox_free_channel(ctx->mbox_chan); pcc_mbox_free_channel(ctx->pcc_chan);
return 0; return 0;
} }
......
...@@ -103,6 +103,7 @@ struct slimpro_i2c_dev { ...@@ -103,6 +103,7 @@ struct slimpro_i2c_dev {
struct i2c_adapter adapter; struct i2c_adapter adapter;
struct device *dev; struct device *dev;
struct mbox_chan *mbox_chan; struct mbox_chan *mbox_chan;
struct pcc_mbox_chan *pcc_chan;
struct mbox_client mbox_client; struct mbox_client mbox_client;
int mbox_idx; int mbox_idx;
struct completion rd_complete; struct completion rd_complete;
...@@ -466,7 +467,7 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) ...@@ -466,7 +467,7 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev)
return PTR_ERR(ctx->mbox_chan); return PTR_ERR(ctx->mbox_chan);
} }
} else { } else {
struct acpi_pcct_hw_reduced *cppc_ss; struct pcc_mbox_chan *pcc_chan;
const struct acpi_device_id *acpi_id; const struct acpi_device_id *acpi_id;
int version = XGENE_SLIMPRO_I2C_V1; int version = XGENE_SLIMPRO_I2C_V1;
...@@ -483,24 +484,14 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) ...@@ -483,24 +484,14 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev)
cl->tx_block = false; cl->tx_block = false;
cl->rx_callback = slimpro_i2c_pcc_rx_cb; cl->rx_callback = slimpro_i2c_pcc_rx_cb;
ctx->mbox_chan = pcc_mbox_request_channel(cl, ctx->mbox_idx); pcc_chan = pcc_mbox_request_channel(cl, ctx->mbox_idx);
if (IS_ERR(ctx->mbox_chan)) { if (IS_ERR(pcc_chan)) {
dev_err(&pdev->dev, "PCC mailbox channel request failed\n"); dev_err(&pdev->dev, "PCC mailbox channel request failed\n");
return PTR_ERR(ctx->mbox_chan); return PTR_ERR(ctx->pcc_chan);
} }
/* ctx->pcc_chan = pcc_chan;
* The PCC mailbox controller driver should ctx->mbox_chan = pcc_chan->mchan;
* have parsed the PCCT (global table of all
* PCC channels) and stored pointers to the
* subspace communication region in con_priv.
*/
cppc_ss = ctx->mbox_chan->con_priv;
if (!cppc_ss) {
dev_err(&pdev->dev, "PPC subspace not found\n");
rc = -ENOENT;
goto mbox_err;
}
if (!ctx->mbox_chan->mbox->txdone_irq) { if (!ctx->mbox_chan->mbox->txdone_irq) {
dev_err(&pdev->dev, "PCC IRQ not supported\n"); dev_err(&pdev->dev, "PCC IRQ not supported\n");
...@@ -512,17 +503,17 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) ...@@ -512,17 +503,17 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev)
* This is the shared communication region * This is the shared communication region
* for the OS and Platform to communicate over. * for the OS and Platform to communicate over.
*/ */
ctx->comm_base_addr = cppc_ss->base_address; ctx->comm_base_addr = pcc_chan->shmem_base_addr;
if (ctx->comm_base_addr) { if (ctx->comm_base_addr) {
if (version == XGENE_SLIMPRO_I2C_V2) if (version == XGENE_SLIMPRO_I2C_V2)
ctx->pcc_comm_addr = memremap( ctx->pcc_comm_addr = memremap(
ctx->comm_base_addr, ctx->comm_base_addr,
cppc_ss->length, pcc_chan->shmem_size,
MEMREMAP_WT); MEMREMAP_WT);
else else
ctx->pcc_comm_addr = memremap( ctx->pcc_comm_addr = memremap(
ctx->comm_base_addr, ctx->comm_base_addr,
cppc_ss->length, pcc_chan->shmem_size,
MEMREMAP_WB); MEMREMAP_WB);
} else { } else {
dev_err(&pdev->dev, "Failed to get PCC comm region\n"); dev_err(&pdev->dev, "Failed to get PCC comm region\n");
...@@ -561,7 +552,7 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) ...@@ -561,7 +552,7 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev)
if (acpi_disabled) if (acpi_disabled)
mbox_free_channel(ctx->mbox_chan); mbox_free_channel(ctx->mbox_chan);
else else
pcc_mbox_free_channel(ctx->mbox_chan); pcc_mbox_free_channel(ctx->pcc_chan);
return rc; return rc;
} }
...@@ -575,7 +566,7 @@ static int xgene_slimpro_i2c_remove(struct platform_device *pdev) ...@@ -575,7 +566,7 @@ static int xgene_slimpro_i2c_remove(struct platform_device *pdev)
if (acpi_disabled) if (acpi_disabled)
mbox_free_channel(ctx->mbox_chan); mbox_free_channel(ctx->mbox_chan);
else else
pcc_mbox_free_channel(ctx->mbox_chan); pcc_mbox_free_channel(ctx->pcc_chan);
return 0; return 0;
} }
......
...@@ -79,24 +79,9 @@ struct pcc_chan_info { ...@@ -79,24 +79,9 @@ struct pcc_chan_info {
int db_irq; int db_irq;
}; };
#define to_pcc_chan_info(c) container_of(c, struct pcc_chan_info, chan)
static struct pcc_chan_info *chan_info; static struct pcc_chan_info *chan_info;
static struct mbox_controller pcc_mbox_ctrl = {}; static struct mbox_controller pcc_mbox_ctrl = {};
/**
* get_pcc_channel - Given a PCC subspace idx, get
* the respective mbox_channel.
* @id: PCC subspace index.
*
* Return: ERR_PTR(errno) if error, else pointer
* to mbox channel.
*/
static struct mbox_chan *get_pcc_channel(int id)
{
if (id < 0 || id >= pcc_mbox_ctrl.num_chans)
return ERR_PTR(-ENOENT);
return &pcc_mbox_channels[id];
}
/* /*
* PCC can be used with perf critical drivers such as CPPC * PCC can be used with perf critical drivers such as CPPC
...@@ -239,31 +224,25 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) ...@@ -239,31 +224,25 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
* ACPI package. This is used to lookup the array of PCC * ACPI package. This is used to lookup the array of PCC
* subspaces as parsed by the PCC Mailbox controller. * subspaces as parsed by the PCC Mailbox controller.
* *
* Return: Pointer to the Mailbox Channel if successful or * Return: Pointer to the PCC Mailbox Channel if successful or ERR_PTR.
* ERR_PTR.
*/ */
struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl, struct pcc_mbox_chan *
int subspace_id) pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id)
{ {
struct pcc_chan_info *pchan; struct pcc_chan_info *pchan;
struct device *dev = pcc_mbox_ctrl.dev; struct device *dev = pcc_mbox_ctrl.dev;
struct mbox_chan *chan; struct mbox_chan *chan;
unsigned long flags; unsigned long flags;
/* if (subspace_id < 0 || subspace_id >= pcc_mbox_ctrl.num_chans)
* Each PCC Subspace is a Mailbox Channel. return ERR_PTR(-ENOENT);
* The PCC Clients get their PCC Subspace ID
* from their own tables and pass it here.
* This returns a pointer to the PCC subspace
* for the Client to operate on.
*/
chan = get_pcc_channel(subspace_id);
pchan = chan_info + subspace_id;
chan = pchan->chan.mchan;
if (IS_ERR(chan) || chan->cl) { if (IS_ERR(chan) || chan->cl) {
dev_err(dev, "Channel not found for idx: %d\n", subspace_id); dev_err(dev, "Channel not found for idx: %d\n", subspace_id);
return ERR_PTR(-EBUSY); return ERR_PTR(-EBUSY);
} }
pchan = chan_info + subspace_id;
spin_lock_irqsave(&chan->lock, flags); spin_lock_irqsave(&chan->lock, flags);
chan->msg_free = 0; chan->msg_free = 0;
...@@ -285,38 +264,32 @@ struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl, ...@@ -285,38 +264,32 @@ struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl,
if (unlikely(rc)) { if (unlikely(rc)) {
dev_err(dev, "failed to register PCC interrupt %d\n", dev_err(dev, "failed to register PCC interrupt %d\n",
pchan->db_irq); pchan->db_irq);
pcc_mbox_free_channel(chan); pcc_mbox_free_channel(&pchan->chan);
chan = ERR_PTR(rc); return ERR_PTR(rc);
} }
} }
return chan; return &pchan->chan;
} }
EXPORT_SYMBOL_GPL(pcc_mbox_request_channel); EXPORT_SYMBOL_GPL(pcc_mbox_request_channel);
/** /**
* pcc_mbox_free_channel - Clients call this to free their Channel. * pcc_mbox_free_channel - Clients call this to free their Channel.
* *
* @chan: Pointer to the mailbox channel as returned by * @pchan: Pointer to the PCC mailbox channel as returned by
* pcc_mbox_request_channel() * pcc_mbox_request_channel()
*/ */
void pcc_mbox_free_channel(struct mbox_chan *chan) void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan)
{ {
u32 id = chan - pcc_mbox_channels; struct pcc_chan_info *pchan_info = to_pcc_chan_info(pchan);
struct pcc_chan_info *pchan; struct mbox_chan *chan = pchan->mchan;
unsigned long flags; unsigned long flags;
if (!chan || !chan->cl) if (!chan || !chan->cl)
return; return;
if (id >= pcc_mbox_ctrl.num_chans) { if (pchan_info->db_irq > 0)
pr_debug("pcc_mbox_free_channel: Invalid mbox_chan passed\n"); devm_free_irq(chan->mbox->dev, pchan_info->db_irq, chan);
return;
}
pchan = chan_info + id;
if (pchan->db_irq > 0)
devm_free_irq(chan->mbox->dev, pchan->db_irq, chan);
spin_lock_irqsave(&chan->lock, flags); spin_lock_irqsave(&chan->lock, flags);
chan->cl = NULL; chan->cl = NULL;
......
...@@ -20,16 +20,16 @@ struct pcc_mbox_chan { ...@@ -20,16 +20,16 @@ struct pcc_mbox_chan {
#define MAX_PCC_SUBSPACES 256 #define MAX_PCC_SUBSPACES 256
#ifdef CONFIG_PCC #ifdef CONFIG_PCC
extern struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl, extern struct pcc_mbox_chan *
int subspace_id); pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id);
extern void pcc_mbox_free_channel(struct mbox_chan *chan); extern void pcc_mbox_free_channel(struct pcc_mbox_chan *chan);
#else #else
static inline struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl, static inline struct pcc_mbox_chan *
int subspace_id) pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id)
{ {
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
static inline void pcc_mbox_free_channel(struct mbox_chan *chan) { } static inline void pcc_mbox_free_channel(struct pcc_mbox_chan *chan) { }
#endif #endif
#endif /* _PCC_H */ #endif /* _PCC_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment