aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/via-velocity.c
diff options
context:
space:
mode:
authorSimon Kagstrom <simon.kagstrom@netinsight.net>2010-02-09 18:38:25 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-10 13:55:02 -0500
commit3f2e8d9f13246382fbda6f03178eef867a9bfbe2 (patch)
tree69ef8e92e70e8739e5121e7705a696bc63691d38 /drivers/net/via-velocity.c
parent39c2ff43ea3830ccc693f965abdace96e514b1c5 (diff)
via-velocity: Fix races on shared interrupts
This patch fixes two potential races in the velocity driver: * Move the ACK and error handler to the interrupt handler. This fixes a potential race with shared interrupts when the other device interrupts before the NAPI poll handler has finished. As the velocity driver hasn't acked it's own interrupt, it will then steal the interrupt from the other device. * Use spin_lock_irqsave in velocity_poll. In the current code, the interrupt handler will deadlock if e.g., the NAPI poll handler is executing when an interrupt (for another device) comes in since it tries to take the already held lock. Also unlock the spinlock only after enabling the interrupt in velocity_poll. The error path is moved to the interrupt handler since this is where the ISR is checked now. Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net> Signed-off-by: Anders Grafstrom <anders.grafstrom@netinsight.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/via-velocity.c')
-rw-r--r--drivers/net/via-velocity.c21
1 files changed, 10 insertions, 11 deletions
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 54bafdab1f9d..317aa34b21cf 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -2148,16 +2148,9 @@ static int velocity_poll(struct napi_struct *napi, int budget)
2148 struct velocity_info *vptr = container_of(napi, 2148 struct velocity_info *vptr = container_of(napi,
2149 struct velocity_info, napi); 2149 struct velocity_info, napi);
2150 unsigned int rx_done; 2150 unsigned int rx_done;
2151 u32 isr_status; 2151 unsigned long flags;
2152
2153 spin_lock(&vptr->lock);
2154 isr_status = mac_read_isr(vptr->mac_regs);
2155
2156 /* Ack the interrupt */
2157 mac_write_isr(vptr->mac_regs, isr_status);
2158 if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
2159 velocity_error(vptr, isr_status);
2160 2152
2153 spin_lock_irqsave(&vptr->lock, flags);
2161 /* 2154 /*
2162 * Do rx and tx twice for performance (taken from the VIA 2155 * Do rx and tx twice for performance (taken from the VIA
2163 * out-of-tree driver). 2156 * out-of-tree driver).
@@ -2167,13 +2160,12 @@ static int velocity_poll(struct napi_struct *napi, int budget)
2167 rx_done += velocity_rx_srv(vptr, budget - rx_done); 2160 rx_done += velocity_rx_srv(vptr, budget - rx_done);
2168 velocity_tx_srv(vptr); 2161 velocity_tx_srv(vptr);
2169 2162
2170 spin_unlock(&vptr->lock);
2171
2172 /* If budget not fully consumed, exit the polling mode */ 2163 /* If budget not fully consumed, exit the polling mode */
2173 if (rx_done < budget) { 2164 if (rx_done < budget) {
2174 napi_complete(napi); 2165 napi_complete(napi);
2175 mac_enable_int(vptr->mac_regs); 2166 mac_enable_int(vptr->mac_regs);
2176 } 2167 }
2168 spin_unlock_irqrestore(&vptr->lock, flags);
2177 2169
2178 return rx_done; 2170 return rx_done;
2179} 2171}
@@ -2203,10 +2195,17 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance)
2203 return IRQ_NONE; 2195 return IRQ_NONE;
2204 } 2196 }
2205 2197
2198 /* Ack the interrupt */
2199 mac_write_isr(vptr->mac_regs, isr_status);
2200
2206 if (likely(napi_schedule_prep(&vptr->napi))) { 2201 if (likely(napi_schedule_prep(&vptr->napi))) {
2207 mac_disable_int(vptr->mac_regs); 2202 mac_disable_int(vptr->mac_regs);
2208 __napi_schedule(&vptr->napi); 2203 __napi_schedule(&vptr->napi);
2209 } 2204 }
2205
2206 if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
2207 velocity_error(vptr, isr_status);
2208
2210 spin_unlock(&vptr->lock); 2209 spin_unlock(&vptr->lock);
2211 2210
2212 return IRQ_HANDLED; 2211 return IRQ_HANDLED;