diff options
Diffstat (limited to 'drivers/net/ixp2000/ixpdev.c')
-rw-r--r-- | drivers/net/ixp2000/ixpdev.c | 39 |
1 files changed, 25 insertions, 14 deletions
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index d9ce1aef148a..6c0dd49149d0 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c | |||
@@ -74,9 +74,9 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
74 | } | 74 | } |
75 | 75 | ||
76 | 76 | ||
77 | static int ixpdev_rx(struct net_device *dev, int *budget) | 77 | static int ixpdev_rx(struct net_device *dev, int processed, int budget) |
78 | { | 78 | { |
79 | while (*budget > 0) { | 79 | while (processed < budget) { |
80 | struct ixpdev_rx_desc *desc; | 80 | struct ixpdev_rx_desc *desc; |
81 | struct sk_buff *skb; | 81 | struct sk_buff *skb; |
82 | void *buf; | 82 | void *buf; |
@@ -122,29 +122,34 @@ static int ixpdev_rx(struct net_device *dev, int *budget) | |||
122 | 122 | ||
123 | err: | 123 | err: |
124 | ixp2000_reg_write(RING_RX_PENDING, _desc); | 124 | ixp2000_reg_write(RING_RX_PENDING, _desc); |
125 | dev->quota--; | 125 | processed++; |
126 | (*budget)--; | ||
127 | } | 126 | } |
128 | 127 | ||
129 | return 1; | 128 | return processed; |
130 | } | 129 | } |
131 | 130 | ||
132 | /* dev always points to nds[0]. */ | 131 | /* dev always points to nds[0]. */ |
133 | static int ixpdev_poll(struct net_device *dev, int *budget) | 132 | static int ixpdev_poll(struct napi_struct *napi, int budget) |
134 | { | 133 | { |
134 | struct ixpdev_priv *ip = container_of(napi, struct ixpdev_priv, napi); | ||
135 | struct net_device *dev = ip->dev; | ||
136 | int rx; | ||
137 | |||
135 | /* @@@ Have to stop polling when nds[0] is administratively | 138 | /* @@@ Have to stop polling when nds[0] is administratively |
136 | * downed while we are polling. */ | 139 | * downed while we are polling. */ |
140 | rx = 0; | ||
137 | do { | 141 | do { |
138 | ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff); | 142 | ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff); |
139 | 143 | ||
140 | if (ixpdev_rx(dev, budget)) | 144 | rx = ixpdev_rx(dev, rx, budget); |
141 | return 1; | 145 | if (rx >= budget) |
146 | break; | ||
142 | } while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff); | 147 | } while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff); |
143 | 148 | ||
144 | netif_rx_complete(dev); | 149 | netif_rx_complete(dev, napi); |
145 | ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff); | 150 | ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff); |
146 | 151 | ||
147 | return 0; | 152 | return rx; |
148 | } | 153 | } |
149 | 154 | ||
150 | static void ixpdev_tx_complete(void) | 155 | static void ixpdev_tx_complete(void) |
@@ -199,9 +204,12 @@ static irqreturn_t ixpdev_interrupt(int irq, void *dev_id) | |||
199 | * Any of the eight receive units signaled RX? | 204 | * Any of the eight receive units signaled RX? |
200 | */ | 205 | */ |
201 | if (status & 0x00ff) { | 206 | if (status & 0x00ff) { |
207 | struct net_device *dev = nds[0]; | ||
208 | struct ixpdev_priv *ip = netdev_priv(dev); | ||
209 | |||
202 | ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff); | 210 | ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff); |
203 | if (likely(__netif_rx_schedule_prep(nds[0]))) { | 211 | if (likely(napi_schedule_prep(&ip->napi))) { |
204 | __netif_rx_schedule(nds[0]); | 212 | __netif_rx_schedule(dev, &ip->napi); |
205 | } else { | 213 | } else { |
206 | printk(KERN_CRIT "ixp2000: irq while polling!!\n"); | 214 | printk(KERN_CRIT "ixp2000: irq while polling!!\n"); |
207 | } | 215 | } |
@@ -232,11 +240,13 @@ static int ixpdev_open(struct net_device *dev) | |||
232 | struct ixpdev_priv *ip = netdev_priv(dev); | 240 | struct ixpdev_priv *ip = netdev_priv(dev); |
233 | int err; | 241 | int err; |
234 | 242 | ||
243 | napi_enable(&ip->napi); | ||
235 | if (!nds_open++) { | 244 | if (!nds_open++) { |
236 | err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt, | 245 | err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt, |
237 | IRQF_SHARED, "ixp2000_eth", nds); | 246 | IRQF_SHARED, "ixp2000_eth", nds); |
238 | if (err) { | 247 | if (err) { |
239 | nds_open--; | 248 | nds_open--; |
249 | napi_disable(&ip->napi); | ||
240 | return err; | 250 | return err; |
241 | } | 251 | } |
242 | 252 | ||
@@ -254,6 +264,7 @@ static int ixpdev_close(struct net_device *dev) | |||
254 | struct ixpdev_priv *ip = netdev_priv(dev); | 264 | struct ixpdev_priv *ip = netdev_priv(dev); |
255 | 265 | ||
256 | netif_stop_queue(dev); | 266 | netif_stop_queue(dev); |
267 | napi_disable(&ip->napi); | ||
257 | set_port_admin_status(ip->channel, 0); | 268 | set_port_admin_status(ip->channel, 0); |
258 | 269 | ||
259 | if (!--nds_open) { | 270 | if (!--nds_open) { |
@@ -274,7 +285,6 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv) | |||
274 | return NULL; | 285 | return NULL; |
275 | 286 | ||
276 | dev->hard_start_xmit = ixpdev_xmit; | 287 | dev->hard_start_xmit = ixpdev_xmit; |
277 | dev->poll = ixpdev_poll; | ||
278 | dev->open = ixpdev_open; | 288 | dev->open = ixpdev_open; |
279 | dev->stop = ixpdev_close; | 289 | dev->stop = ixpdev_close; |
280 | #ifdef CONFIG_NET_POLL_CONTROLLER | 290 | #ifdef CONFIG_NET_POLL_CONTROLLER |
@@ -282,9 +292,10 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv) | |||
282 | #endif | 292 | #endif |
283 | 293 | ||
284 | dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; | 294 | dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; |
285 | dev->weight = 64; | ||
286 | 295 | ||
287 | ip = netdev_priv(dev); | 296 | ip = netdev_priv(dev); |
297 | ip->dev = dev; | ||
298 | netif_napi_add(dev, &ip->napi, ixpdev_poll, 64); | ||
288 | ip->channel = channel; | 299 | ip->channel = channel; |
289 | ip->tx_queue_entries = 0; | 300 | ip->tx_queue_entries = 0; |
290 | 301 | ||