Commit 4c9d7912 authored by Grzegorz Daniluk's avatar Grzegorz Daniluk Committed by Alessandro Rubini

kernel/wr_pstats: dump whole cntrs overflow information in irq handler

On higher storm of traffic, in the time between scheduling the tasklet and
executing it, I was loosing cntrs overflow information already (was overwritten
by all-the-time-incrementing counters in HDL).
parent 8ff7b4d6
......@@ -53,6 +53,7 @@ struct cntrs_dev {
/* circular bufer for passing Port's IRQ mask between irq handler and
* the tasklet */
uint32_t port_irqs[PSTATS_IRQBUFSZ];
uint64_t overflows[PSTATS_IRQBUFSZ][PSTATS_NPORTS];
volatile int irqs_head;
int irqs_tail;
};
......@@ -118,7 +119,7 @@ static uint64_t pstats_irq_cntrs(int port)
static void pstats_tlet_fn(unsigned long arg)
{
uint32_t irqs;
uint64_t cntrs_ov;
uint64_t *cntrs_ov;
int port, cntr;
unsigned int *ptr;
struct cntrs_dev *device = (struct cntrs_dev *)arg;
......@@ -130,44 +131,59 @@ static void pstats_tlet_fn(unsigned long arg)
device->irqs_tail += PSTATS_IRQBUFSZ;
}
irqs = device->port_irqs[device->irqs_tail++ % PSTATS_IRQBUFSZ];
/* level 1 of IRQs is device->port_irqs where each bit set to 1 says
* there is at least one overflowed counter on the port correcponding
* to the bit */
for (port = 0; port < pstats_nports; ++port) {
if (!(irqs>>port & 0x01))
continue; /*there is no irq from this port*/
/* Level 2 of IRQs is reading additional IRQ flags register for
* each port that has bit in device->port_irqs set to 1. This
* register is a set of IRQ flags per-counter for a given port.
* That means, when i-th bit in cntrs_ov is set, i-th counter
* for this port has to be incremented by 1<<PSTATS_MSB_SHIFT */
spin_lock(&device->port_mutex[port]);
cntrs_ov = pstats_irq_cntrs(port);
for (cntr = 0; cntr < PSTATS_CNT_PP; ++cntr) {
/*decode counters overflow flags to increment coutners*/
if (cntrs_ov>>cntr & 0x01) {
ptr = cntr_idx(device->cntrs, port, cntr);
*ptr += 1<<PSTATS_MSB_SHIFT;
}
}
spin_unlock(&device->port_mutex[port]);
}
while(device->irqs_tail != device->irqs_head) {
//printk(KERN_WARNING "tlet head=%d, tail=%d\n", device->irqs_head, device->irqs_tail);
irqs = device->port_irqs[device->irqs_tail];
/* level 1 of IRQs is device->port_irqs where each bit set to 1 says
* there is at least one overflowed counter on the port correcponding
* to the bit */
//printk("irqs %5x\n", irqs);
for (port = 0; port < pstats_nports; ++port) {
if (!(irqs>>port & 0x01))
continue; /*there is no irq from this port*/
/* Level 2 of IRQs is reading additional IRQ flags register for
* each port that has bit in device->port_irqs set to 1. This
* register is a set of IRQ flags per-counter for a given port.
* That means, when i-th bit in cntrs_ov is set, i-th counter
* for this port has to be incremented by 1<<PSTATS_MSB_SHIFT */
spin_lock(&device->port_mutex[port]);
cntrs_ov = &(device->overflows[device->irqs_tail][port]);
//if(port==0)
// printk(KERN_WARNING "cntrs_ov: %08x %08x\n", (uint32_t)((*cntrs_ov)>>32 & 0xffffffff),
// (uint32_t)((*cntrs_ov) & 0x00ffffffffLL));
for (cntr = 0; cntr < PSTATS_CNT_PP; ++cntr) {
/*decode counters overflow flags to increment coutners*/
if ((*cntrs_ov)>>cntr & 0x01) {
ptr = cntr_idx(device->cntrs, port, cntr);
*ptr += 1<<PSTATS_MSB_SHIFT;
}
}
spin_unlock(&device->port_mutex[port]);
}
device->irqs_tail = (device->irqs_tail+1) % PSTATS_IRQBUFSZ;
}
}
DECLARE_TASKLET(proc_ports, pstats_tlet_fn, (unsigned long)&pstats_dev);
static irqreturn_t pstats_irq_handler(int irq, void *devid)
{
struct cntrs_dev *device = (struct cntrs_dev *)devid;
uint32_t irqs;
uint32_t irqs, i;
irqs = pstats_irq_status();
pstats_irq_disable(PSTATS_ALL_MSK);
pstats_irq_clear(irqs);
device->port_irqs[device->irqs_head++ % PSTATS_IRQBUFSZ] = irqs;
device->port_irqs[device->irqs_head] = irqs;
/* dump all overflow information so that we don't lose any if tasklet is
* delayed */
for(i=0; i<pstats_nports; ++i)
device->overflows[device->irqs_head][i] = pstats_irq_cntrs(i);
device->irqs_head = (device->irqs_head + 1) % PSTATS_IRQBUFSZ;
//device->port_irqs[device->irqs_head++ % PSTATS_IRQBUFSZ] = irqs;
tasklet_schedule(&proc_ports);
pstats_irq_enable(portmsk);
......
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