diff options
author | Matheos Worku <Matheos.Worku@Sun.COM> | 2008-01-05 02:48:26 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-09 02:29:54 -0500 |
commit | 406f353c857e4b2dbddb7cd20c67941d829b8b15 (patch) | |
tree | f2d8ae4a0c41b48ad947dd59d32efca2fdf0d26a /drivers/net/niu.c | |
parent | cdf71a10c7b6432d9b48e292cca2c62a0b9fa6cf (diff) |
[NIU]: Fix slowpath interrupt handling.
niu_slowpath_interrupt() expects values to be setup in lp->{v0,v1,v2}
but they aren't. That's only done by niu_schedule_napi() which is
done later in the interrupt path.
If niu_rx_error() returns zero, and v0 is clear, hit the
RX_DMA_CTL_STATE register with a RX_DMA_CTL_STAT_MEX.
Only emit verbose RX error logs if a fatal channel or port error is
signalled. Other cases will be recorded into statistics by
niu_log_rxchan_errors().
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/niu.c')
-rw-r--r-- | drivers/net/niu.c | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c index abfc61c3a38c..32ed87d54706 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c | |||
@@ -2508,15 +2508,19 @@ static int niu_rx_error(struct niu *np, struct rx_ring_info *rp) | |||
2508 | u64 stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel)); | 2508 | u64 stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel)); |
2509 | int err = 0; | 2509 | int err = 0; |
2510 | 2510 | ||
2511 | dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n", | ||
2512 | np->dev->name, rp->rx_channel, (unsigned long long) stat); | ||
2513 | |||
2514 | niu_log_rxchan_errors(np, rp, stat); | ||
2515 | 2511 | ||
2516 | if (stat & (RX_DMA_CTL_STAT_CHAN_FATAL | | 2512 | if (stat & (RX_DMA_CTL_STAT_CHAN_FATAL | |
2517 | RX_DMA_CTL_STAT_PORT_FATAL)) | 2513 | RX_DMA_CTL_STAT_PORT_FATAL)) |
2518 | err = -EINVAL; | 2514 | err = -EINVAL; |
2519 | 2515 | ||
2516 | if (err) { | ||
2517 | dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n", | ||
2518 | np->dev->name, rp->rx_channel, | ||
2519 | (unsigned long long) stat); | ||
2520 | |||
2521 | niu_log_rxchan_errors(np, rp, stat); | ||
2522 | } | ||
2523 | |||
2520 | nw64(RX_DMA_CTL_STAT(rp->rx_channel), | 2524 | nw64(RX_DMA_CTL_STAT(rp->rx_channel), |
2521 | stat & RX_DMA_CTL_WRITE_CLEAR_ERRS); | 2525 | stat & RX_DMA_CTL_WRITE_CLEAR_ERRS); |
2522 | 2526 | ||
@@ -2749,13 +2753,16 @@ static int niu_device_error(struct niu *np) | |||
2749 | return -ENODEV; | 2753 | return -ENODEV; |
2750 | } | 2754 | } |
2751 | 2755 | ||
2752 | static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp) | 2756 | static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp, |
2757 | u64 v0, u64 v1, u64 v2) | ||
2753 | { | 2758 | { |
2754 | u64 v0 = lp->v0; | 2759 | |
2755 | u64 v1 = lp->v1; | ||
2756 | u64 v2 = lp->v2; | ||
2757 | int i, err = 0; | 2760 | int i, err = 0; |
2758 | 2761 | ||
2762 | lp->v0 = v0; | ||
2763 | lp->v1 = v1; | ||
2764 | lp->v2 = v2; | ||
2765 | |||
2759 | if (v1 & 0x00000000ffffffffULL) { | 2766 | if (v1 & 0x00000000ffffffffULL) { |
2760 | u32 rx_vec = (v1 & 0xffffffff); | 2767 | u32 rx_vec = (v1 & 0xffffffff); |
2761 | 2768 | ||
@@ -2764,8 +2771,13 @@ static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp) | |||
2764 | 2771 | ||
2765 | if (rx_vec & (1 << rp->rx_channel)) { | 2772 | if (rx_vec & (1 << rp->rx_channel)) { |
2766 | int r = niu_rx_error(np, rp); | 2773 | int r = niu_rx_error(np, rp); |
2767 | if (r) | 2774 | if (r) { |
2768 | err = r; | 2775 | err = r; |
2776 | } else { | ||
2777 | if (!v0) | ||
2778 | nw64(RX_DMA_CTL_STAT(rp->rx_channel), | ||
2779 | RX_DMA_CTL_STAT_MEX); | ||
2780 | } | ||
2769 | } | 2781 | } |
2770 | } | 2782 | } |
2771 | } | 2783 | } |
@@ -2803,7 +2815,7 @@ static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp) | |||
2803 | if (err) | 2815 | if (err) |
2804 | niu_enable_interrupts(np, 0); | 2816 | niu_enable_interrupts(np, 0); |
2805 | 2817 | ||
2806 | return -EINVAL; | 2818 | return err; |
2807 | } | 2819 | } |
2808 | 2820 | ||
2809 | static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp, | 2821 | static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp, |
@@ -2905,7 +2917,7 @@ static irqreturn_t niu_interrupt(int irq, void *dev_id) | |||
2905 | } | 2917 | } |
2906 | 2918 | ||
2907 | if (unlikely((v0 & ((u64)1 << LDN_MIF)) || v1 || v2)) { | 2919 | if (unlikely((v0 & ((u64)1 << LDN_MIF)) || v1 || v2)) { |
2908 | int err = niu_slowpath_interrupt(np, lp); | 2920 | int err = niu_slowpath_interrupt(np, lp, v0, v1, v2); |
2909 | if (err) | 2921 | if (err) |
2910 | goto out; | 2922 | goto out; |
2911 | } | 2923 | } |