diff options
author | Finn Thain <fthain@telegraphics.com.au> | 2005-08-20 01:53:22 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-08-23 01:32:12 -0400 |
commit | efcce839360fb3a7b6dedeacaec80f68b0f2d052 (patch) | |
tree | 7ddeeb994619d0c29f3a9c7ac923a376dec413f5 /drivers/net/jazzsonic.c | |
parent | 2600636065406dc14948ac2d2913c66c51be80d5 (diff) |
[PATCH] macsonic/jazzsonic network drivers update
The purpose of this patch:
- Adopt the DMA API (jazzsonic, macsonic & core driver).
- Adopt the driver model (macsonic).
This part was cribbed from jazzsonic. As a consequence, macsonic once
again works as a module. Driver model is also used by the DMA calls.
- Support 16 bit cards (macsonic & core driver, also affects jazzsonic)
This code was adapted from the mac68k linux 2.2 kernel, where it has
languished for a long time.
- Support more 32-bit mac cards (macsonic)
Also from mac68k repo.
- Zero-copy buffer handling (core driver)
Provides a nice performance improvement. The new algorithm incidentally
helped to replace the old Jazz DMA code.
The patch was tested on a variety of macs (several 32-bit quadra built-in
NICs, a 16-bit LC PDS NIC and a 16-bit comm-slot NIC), and also on MIPS
Jazz.
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Acked-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net/jazzsonic.c')
-rw-r--r-- | drivers/net/jazzsonic.c | 186 |
1 files changed, 74 insertions, 112 deletions
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 7fec613e1675..8423cb6875f0 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c | |||
@@ -1,5 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * sonic.c | 2 | * jazzsonic.c |
3 | * | ||
4 | * (C) 2005 Finn Thain | ||
5 | * | ||
6 | * Converted to DMA API, and (from the mac68k project) introduced | ||
7 | * dhd's support for 16-bit cards. | ||
3 | * | 8 | * |
4 | * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de) | 9 | * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de) |
5 | * | 10 | * |
@@ -28,8 +33,8 @@ | |||
28 | #include <linux/netdevice.h> | 33 | #include <linux/netdevice.h> |
29 | #include <linux/etherdevice.h> | 34 | #include <linux/etherdevice.h> |
30 | #include <linux/skbuff.h> | 35 | #include <linux/skbuff.h> |
31 | #include <linux/bitops.h> | ||
32 | #include <linux/device.h> | 36 | #include <linux/device.h> |
37 | #include <linux/dma-mapping.h> | ||
33 | 38 | ||
34 | #include <asm/bootinfo.h> | 39 | #include <asm/bootinfo.h> |
35 | #include <asm/system.h> | 40 | #include <asm/system.h> |
@@ -44,22 +49,20 @@ static struct platform_device *jazz_sonic_device; | |||
44 | 49 | ||
45 | #define SONIC_MEM_SIZE 0x100 | 50 | #define SONIC_MEM_SIZE 0x100 |
46 | 51 | ||
47 | #define SREGS_PAD(n) u16 n; | ||
48 | |||
49 | #include "sonic.h" | 52 | #include "sonic.h" |
50 | 53 | ||
51 | /* | 54 | /* |
52 | * Macros to access SONIC registers | 55 | * Macros to access SONIC registers |
53 | */ | 56 | */ |
54 | #define SONIC_READ(reg) (*((volatile unsigned int *)base_addr+reg)) | 57 | #define SONIC_READ(reg) (*((volatile unsigned int *)dev->base_addr+reg)) |
55 | 58 | ||
56 | #define SONIC_WRITE(reg,val) \ | 59 | #define SONIC_WRITE(reg,val) \ |
57 | do { \ | 60 | do { \ |
58 | *((volatile unsigned int *)base_addr+(reg)) = (val); \ | 61 | *((volatile unsigned int *)dev->base_addr+(reg)) = (val); \ |
59 | } while (0) | 62 | } while (0) |
60 | 63 | ||
61 | 64 | ||
62 | /* use 0 for production, 1 for verification, >2 for debug */ | 65 | /* use 0 for production, 1 for verification, >1 for debug */ |
63 | #ifdef SONIC_DEBUG | 66 | #ifdef SONIC_DEBUG |
64 | static unsigned int sonic_debug = SONIC_DEBUG; | 67 | static unsigned int sonic_debug = SONIC_DEBUG; |
65 | #else | 68 | #else |
@@ -85,18 +88,18 @@ static unsigned short known_revisions[] = | |||
85 | 0xffff /* end of list */ | 88 | 0xffff /* end of list */ |
86 | }; | 89 | }; |
87 | 90 | ||
88 | static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr, | 91 | static int __init sonic_probe1(struct net_device *dev) |
89 | unsigned int irq) | ||
90 | { | 92 | { |
91 | static unsigned version_printed; | 93 | static unsigned version_printed; |
92 | unsigned int silicon_revision; | 94 | unsigned int silicon_revision; |
93 | unsigned int val; | 95 | unsigned int val; |
94 | struct sonic_local *lp; | 96 | struct sonic_local *lp = netdev_priv(dev); |
95 | int err = -ENODEV; | 97 | int err = -ENODEV; |
96 | int i; | 98 | int i; |
97 | 99 | ||
98 | if (!request_mem_region(base_addr, SONIC_MEM_SIZE, jazz_sonic_string)) | 100 | if (!request_mem_region(dev->base_addr, SONIC_MEM_SIZE, jazz_sonic_string)) |
99 | return -EBUSY; | 101 | return -EBUSY; |
102 | |||
100 | /* | 103 | /* |
101 | * get the Silicon Revision ID. If this is one of the known | 104 | * get the Silicon Revision ID. If this is one of the known |
102 | * one assume that we found a SONIC ethernet controller at | 105 | * one assume that we found a SONIC ethernet controller at |
@@ -120,11 +123,7 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr, | |||
120 | if (sonic_debug && version_printed++ == 0) | 123 | if (sonic_debug && version_printed++ == 0) |
121 | printk(version); | 124 | printk(version); |
122 | 125 | ||
123 | printk("%s: Sonic ethernet found at 0x%08lx, ", dev->name, base_addr); | 126 | printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ", lp->device->bus_id, dev->base_addr); |
124 | |||
125 | /* Fill in the 'dev' fields. */ | ||
126 | dev->base_addr = base_addr; | ||
127 | dev->irq = irq; | ||
128 | 127 | ||
129 | /* | 128 | /* |
130 | * Put the sonic into software reset, then | 129 | * Put the sonic into software reset, then |
@@ -138,84 +137,44 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr, | |||
138 | dev->dev_addr[i*2+1] = val >> 8; | 137 | dev->dev_addr[i*2+1] = val >> 8; |
139 | } | 138 | } |
140 | 139 | ||
141 | printk("HW Address "); | ||
142 | for (i = 0; i < 6; i++) { | ||
143 | printk("%2.2x", dev->dev_addr[i]); | ||
144 | if (i<5) | ||
145 | printk(":"); | ||
146 | } | ||
147 | |||
148 | printk(" IRQ %d\n", irq); | ||
149 | |||
150 | err = -ENOMEM; | 140 | err = -ENOMEM; |
151 | 141 | ||
152 | /* Initialize the device structure. */ | 142 | /* Initialize the device structure. */ |
153 | if (dev->priv == NULL) { | ||
154 | /* | ||
155 | * the memory be located in the same 64kb segment | ||
156 | */ | ||
157 | lp = NULL; | ||
158 | i = 0; | ||
159 | do { | ||
160 | lp = kmalloc(sizeof(*lp), GFP_KERNEL); | ||
161 | if ((unsigned long) lp >> 16 | ||
162 | != ((unsigned long)lp + sizeof(*lp) ) >> 16) { | ||
163 | /* FIXME, free the memory later */ | ||
164 | kfree(lp); | ||
165 | lp = NULL; | ||
166 | } | ||
167 | } while (lp == NULL && i++ < 20); | ||
168 | |||
169 | if (lp == NULL) { | ||
170 | printk("%s: couldn't allocate memory for descriptors\n", | ||
171 | dev->name); | ||
172 | goto out; | ||
173 | } | ||
174 | 143 | ||
175 | memset(lp, 0, sizeof(struct sonic_local)); | 144 | lp->dma_bitmode = SONIC_BITMODE32; |
176 | |||
177 | /* get the virtual dma address */ | ||
178 | lp->cda_laddr = vdma_alloc(CPHYSADDR(lp),sizeof(*lp)); | ||
179 | if (lp->cda_laddr == ~0UL) { | ||
180 | printk("%s: couldn't get DMA page entry for " | ||
181 | "descriptors\n", dev->name); | ||
182 | goto out1; | ||
183 | } | ||
184 | |||
185 | lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda); | ||
186 | lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda); | ||
187 | lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra); | ||
188 | |||
189 | /* allocate receive buffer area */ | ||
190 | /* FIXME, maybe we should use skbs */ | ||
191 | lp->rba = kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL); | ||
192 | if (!lp->rba) { | ||
193 | printk("%s: couldn't allocate receive buffers\n", | ||
194 | dev->name); | ||
195 | goto out2; | ||
196 | } | ||
197 | 145 | ||
198 | /* get virtual dma address */ | 146 | /* Allocate the entire chunk of memory for the descriptors. |
199 | lp->rba_laddr = vdma_alloc(CPHYSADDR(lp->rba), | 147 | Note that this cannot cross a 64K boundary. */ |
200 | SONIC_NUM_RRS * SONIC_RBSIZE); | 148 | if ((lp->descriptors = dma_alloc_coherent(lp->device, |
201 | if (lp->rba_laddr == ~0UL) { | 149 | SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), |
202 | printk("%s: couldn't get DMA page entry for receive " | 150 | &lp->descriptors_laddr, GFP_KERNEL)) == NULL) { |
203 | "buffers\n",dev->name); | 151 | printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id); |
204 | goto out3; | 152 | goto out; |
205 | } | ||
206 | |||
207 | /* now convert pointer to KSEG1 pointer */ | ||
208 | lp->rba = (char *)KSEG1ADDR(lp->rba); | ||
209 | flush_cache_all(); | ||
210 | dev->priv = (struct sonic_local *)KSEG1ADDR(lp); | ||
211 | } | 153 | } |
212 | 154 | ||
213 | lp = (struct sonic_local *)dev->priv; | 155 | /* Now set up the pointers to point to the appropriate places */ |
156 | lp->cda = lp->descriptors; | ||
157 | lp->tda = lp->cda + (SIZEOF_SONIC_CDA | ||
158 | * SONIC_BUS_SCALE(lp->dma_bitmode)); | ||
159 | lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS | ||
160 | * SONIC_BUS_SCALE(lp->dma_bitmode)); | ||
161 | lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS | ||
162 | * SONIC_BUS_SCALE(lp->dma_bitmode)); | ||
163 | |||
164 | lp->cda_laddr = lp->descriptors_laddr; | ||
165 | lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA | ||
166 | * SONIC_BUS_SCALE(lp->dma_bitmode)); | ||
167 | lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS | ||
168 | * SONIC_BUS_SCALE(lp->dma_bitmode)); | ||
169 | lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS | ||
170 | * SONIC_BUS_SCALE(lp->dma_bitmode)); | ||
171 | |||
214 | dev->open = sonic_open; | 172 | dev->open = sonic_open; |
215 | dev->stop = sonic_close; | 173 | dev->stop = sonic_close; |
216 | dev->hard_start_xmit = sonic_send_packet; | 174 | dev->hard_start_xmit = sonic_send_packet; |
217 | dev->get_stats = sonic_get_stats; | 175 | dev->get_stats = sonic_get_stats; |
218 | dev->set_multicast_list = &sonic_multicast_list; | 176 | dev->set_multicast_list = &sonic_multicast_list; |
177 | dev->tx_timeout = sonic_tx_timeout; | ||
219 | dev->watchdog_timeo = TX_TIMEOUT; | 178 | dev->watchdog_timeo = TX_TIMEOUT; |
220 | 179 | ||
221 | /* | 180 | /* |
@@ -226,14 +185,8 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr, | |||
226 | SONIC_WRITE(SONIC_MPT,0xffff); | 185 | SONIC_WRITE(SONIC_MPT,0xffff); |
227 | 186 | ||
228 | return 0; | 187 | return 0; |
229 | out3: | ||
230 | kfree(lp->rba); | ||
231 | out2: | ||
232 | vdma_free(lp->cda_laddr); | ||
233 | out1: | ||
234 | kfree(lp); | ||
235 | out: | 188 | out: |
236 | release_region(base_addr, SONIC_MEM_SIZE); | 189 | release_region(dev->base_addr, SONIC_MEM_SIZE); |
237 | return err; | 190 | return err; |
238 | } | 191 | } |
239 | 192 | ||
@@ -245,7 +198,6 @@ static int __init jazz_sonic_probe(struct device *device) | |||
245 | { | 198 | { |
246 | struct net_device *dev; | 199 | struct net_device *dev; |
247 | struct sonic_local *lp; | 200 | struct sonic_local *lp; |
248 | unsigned long base_addr; | ||
249 | int err = 0; | 201 | int err = 0; |
250 | int i; | 202 | int i; |
251 | 203 | ||
@@ -255,21 +207,26 @@ static int __init jazz_sonic_probe(struct device *device) | |||
255 | if (mips_machgroup != MACH_GROUP_JAZZ) | 207 | if (mips_machgroup != MACH_GROUP_JAZZ) |
256 | return -ENODEV; | 208 | return -ENODEV; |
257 | 209 | ||
258 | dev = alloc_etherdev(0); | 210 | dev = alloc_etherdev(sizeof(struct sonic_local)); |
259 | if (!dev) | 211 | if (!dev) |
260 | return -ENOMEM; | 212 | return -ENOMEM; |
261 | 213 | ||
214 | lp = netdev_priv(dev); | ||
215 | lp->device = device; | ||
216 | SET_NETDEV_DEV(dev, device); | ||
217 | SET_MODULE_OWNER(dev); | ||
218 | |||
262 | netdev_boot_setup_check(dev); | 219 | netdev_boot_setup_check(dev); |
263 | base_addr = dev->base_addr; | ||
264 | 220 | ||
265 | if (base_addr >= KSEG0) { /* Check a single specified location. */ | 221 | if (dev->base_addr >= KSEG0) { /* Check a single specified location. */ |
266 | err = sonic_probe1(dev, base_addr, dev->irq); | 222 | err = sonic_probe1(dev); |
267 | } else if (base_addr != 0) { /* Don't probe at all. */ | 223 | } else if (dev->base_addr != 0) { /* Don't probe at all. */ |
268 | err = -ENXIO; | 224 | err = -ENXIO; |
269 | } else { | 225 | } else { |
270 | for (i = 0; sonic_portlist[i].port; i++) { | 226 | for (i = 0; sonic_portlist[i].port; i++) { |
271 | int io = sonic_portlist[i].port; | 227 | dev->base_addr = sonic_portlist[i].port; |
272 | if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0) | 228 | dev->irq = sonic_portlist[i].irq; |
229 | if (sonic_probe1(dev) == 0) | ||
273 | break; | 230 | break; |
274 | } | 231 | } |
275 | if (!sonic_portlist[i].port) | 232 | if (!sonic_portlist[i].port) |
@@ -281,14 +238,17 @@ static int __init jazz_sonic_probe(struct device *device) | |||
281 | if (err) | 238 | if (err) |
282 | goto out1; | 239 | goto out1; |
283 | 240 | ||
241 | printk("%s: MAC ", dev->name); | ||
242 | for (i = 0; i < 6; i++) { | ||
243 | printk("%2.2x", dev->dev_addr[i]); | ||
244 | if (i < 5) | ||
245 | printk(":"); | ||
246 | } | ||
247 | printk(" IRQ %d\n", dev->irq); | ||
248 | |||
284 | return 0; | 249 | return 0; |
285 | 250 | ||
286 | out1: | 251 | out1: |
287 | lp = dev->priv; | ||
288 | vdma_free(lp->rba_laddr); | ||
289 | kfree(lp->rba); | ||
290 | vdma_free(lp->cda_laddr); | ||
291 | kfree(lp); | ||
292 | release_region(dev->base_addr, SONIC_MEM_SIZE); | 252 | release_region(dev->base_addr, SONIC_MEM_SIZE); |
293 | out: | 253 | out: |
294 | free_netdev(dev); | 254 | free_netdev(dev); |
@@ -296,21 +256,22 @@ out: | |||
296 | return err; | 256 | return err; |
297 | } | 257 | } |
298 | 258 | ||
299 | /* | 259 | MODULE_DESCRIPTION("Jazz SONIC ethernet driver"); |
300 | * SONIC uses a normal IRQ | 260 | module_param(sonic_debug, int, 0); |
301 | */ | 261 | MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)"); |
302 | #define sonic_request_irq request_irq | ||
303 | #define sonic_free_irq free_irq | ||
304 | 262 | ||
305 | #define sonic_chiptomem(x) KSEG1ADDR(vdma_log2phys(x)) | 263 | #define SONIC_IRQ_FLAG SA_INTERRUPT |
306 | 264 | ||
307 | #include "sonic.c" | 265 | #include "sonic.c" |
308 | 266 | ||
309 | static int __devexit jazz_sonic_device_remove (struct device *device) | 267 | static int __devexit jazz_sonic_device_remove (struct device *device) |
310 | { | 268 | { |
311 | struct net_device *dev = device->driver_data; | 269 | struct net_device *dev = device->driver_data; |
270 | struct sonic_local* lp = netdev_priv(dev); | ||
312 | 271 | ||
313 | unregister_netdev (dev); | 272 | unregister_netdev (dev); |
273 | dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), | ||
274 | lp->descriptors, lp->descriptors_laddr); | ||
314 | release_region (dev->base_addr, SONIC_MEM_SIZE); | 275 | release_region (dev->base_addr, SONIC_MEM_SIZE); |
315 | free_netdev (dev); | 276 | free_netdev (dev); |
316 | 277 | ||
@@ -323,7 +284,7 @@ static struct device_driver jazz_sonic_driver = { | |||
323 | .probe = jazz_sonic_probe, | 284 | .probe = jazz_sonic_probe, |
324 | .remove = __devexit_p(jazz_sonic_device_remove), | 285 | .remove = __devexit_p(jazz_sonic_device_remove), |
325 | }; | 286 | }; |
326 | 287 | ||
327 | static void jazz_sonic_platform_release (struct device *device) | 288 | static void jazz_sonic_platform_release (struct device *device) |
328 | { | 289 | { |
329 | struct platform_device *pldev; | 290 | struct platform_device *pldev; |
@@ -336,10 +297,11 @@ static void jazz_sonic_platform_release (struct device *device) | |||
336 | static int __init jazz_sonic_init_module(void) | 297 | static int __init jazz_sonic_init_module(void) |
337 | { | 298 | { |
338 | struct platform_device *pldev; | 299 | struct platform_device *pldev; |
300 | int err; | ||
339 | 301 | ||
340 | if (driver_register(&jazz_sonic_driver)) { | 302 | if ((err = driver_register(&jazz_sonic_driver))) { |
341 | printk(KERN_ERR "Driver registration failed\n"); | 303 | printk(KERN_ERR "Driver registration failed\n"); |
342 | return -ENOMEM; | 304 | return err; |
343 | } | 305 | } |
344 | 306 | ||
345 | jazz_sonic_device = NULL; | 307 | jazz_sonic_device = NULL; |