diff options
Diffstat (limited to 'drivers/net/mvme147.c')
-rw-r--r-- | drivers/net/mvme147.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c new file mode 100644 index 000000000000..56a82d8ee8f5 --- /dev/null +++ b/drivers/net/mvme147.c | |||
@@ -0,0 +1,203 @@ | |||
1 | /* mvme147.c : the Linux/mvme147/lance ethernet driver | ||
2 | * | ||
3 | * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk> | ||
4 | * Based on the Sun Lance driver and the NetBSD HP Lance driver | ||
5 | * Uses the generic 7990.c LANCE code. | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/ioport.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/string.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/errno.h> | ||
18 | /* Used for the temporal inet entries and routing */ | ||
19 | #include <linux/socket.h> | ||
20 | #include <linux/route.h> | ||
21 | #include <linux/netdevice.h> | ||
22 | #include <linux/etherdevice.h> | ||
23 | #include <linux/skbuff.h> | ||
24 | |||
25 | #include <asm/system.h> | ||
26 | #include <asm/io.h> | ||
27 | #include <asm/pgtable.h> | ||
28 | #include <asm/mvme147hw.h> | ||
29 | |||
30 | /* We have 16834 bytes of RAM for the init block and buffers. This places | ||
31 | * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx | ||
32 | * buffers and 2 Tx buffers. | ||
33 | */ | ||
34 | #define LANCE_LOG_TX_BUFFERS 1 | ||
35 | #define LANCE_LOG_RX_BUFFERS 3 | ||
36 | |||
37 | #include "7990.h" /* use generic LANCE code */ | ||
38 | |||
39 | /* Our private data structure */ | ||
40 | struct m147lance_private { | ||
41 | struct lance_private lance; | ||
42 | unsigned long ram; | ||
43 | }; | ||
44 | |||
45 | /* function prototypes... This is easy because all the grot is in the | ||
46 | * generic LANCE support. All we have to support is probing for boards, | ||
47 | * plus board-specific init, open and close actions. | ||
48 | * Oh, and we need to tell the generic code how to read and write LANCE registers... | ||
49 | */ | ||
50 | static int m147lance_open(struct net_device *dev); | ||
51 | static int m147lance_close(struct net_device *dev); | ||
52 | static void m147lance_writerap(struct lance_private *lp, unsigned short value); | ||
53 | static void m147lance_writerdp(struct lance_private *lp, unsigned short value); | ||
54 | static unsigned short m147lance_readrdp(struct lance_private *lp); | ||
55 | |||
56 | typedef void (*writerap_t)(void *, unsigned short); | ||
57 | typedef void (*writerdp_t)(void *, unsigned short); | ||
58 | typedef unsigned short (*readrdp_t)(void *); | ||
59 | |||
60 | /* Initialise the one and only on-board 7990 */ | ||
61 | struct net_device * __init mvme147lance_probe(int unit) | ||
62 | { | ||
63 | struct net_device *dev; | ||
64 | static int called; | ||
65 | static const char name[] = "MVME147 LANCE"; | ||
66 | struct m147lance_private *lp; | ||
67 | u_long *addr; | ||
68 | u_long address; | ||
69 | int err; | ||
70 | |||
71 | if (!MACH_IS_MVME147 || called) | ||
72 | return ERR_PTR(-ENODEV); | ||
73 | called++; | ||
74 | |||
75 | dev = alloc_etherdev(sizeof(struct m147lance_private)); | ||
76 | if (!dev) | ||
77 | return ERR_PTR(-ENOMEM); | ||
78 | |||
79 | if (unit >= 0) | ||
80 | sprintf(dev->name, "eth%d", unit); | ||
81 | |||
82 | SET_MODULE_OWNER(dev); | ||
83 | |||
84 | /* Fill the dev fields */ | ||
85 | dev->base_addr = (unsigned long)MVME147_LANCE_BASE; | ||
86 | dev->open = &m147lance_open; | ||
87 | dev->stop = &m147lance_close; | ||
88 | dev->hard_start_xmit = &lance_start_xmit; | ||
89 | dev->get_stats = &lance_get_stats; | ||
90 | dev->set_multicast_list = &lance_set_multicast; | ||
91 | dev->tx_timeout = &lance_tx_timeout; | ||
92 | dev->dma = 0; | ||
93 | |||
94 | addr=(u_long *)ETHERNET_ADDRESS; | ||
95 | address = *addr; | ||
96 | dev->dev_addr[0]=0x08; | ||
97 | dev->dev_addr[1]=0x00; | ||
98 | dev->dev_addr[2]=0x3e; | ||
99 | address=address>>8; | ||
100 | dev->dev_addr[5]=address&0xff; | ||
101 | address=address>>8; | ||
102 | dev->dev_addr[4]=address&0xff; | ||
103 | address=address>>8; | ||
104 | dev->dev_addr[3]=address&0xff; | ||
105 | |||
106 | printk("%s: MVME147 at 0x%08lx, irq %d, Hardware Address %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
107 | dev->name, dev->base_addr, MVME147_LANCE_IRQ, | ||
108 | dev->dev_addr[0], | ||
109 | dev->dev_addr[1], dev->dev_addr[2], | ||
110 | dev->dev_addr[3], dev->dev_addr[4], | ||
111 | dev->dev_addr[5]); | ||
112 | |||
113 | lp = (struct m147lance_private *)dev->priv; | ||
114 | lp->ram = __get_dma_pages(GFP_ATOMIC, 3); /* 16K */ | ||
115 | if (!lp->ram) | ||
116 | { | ||
117 | printk("%s: No memory for LANCE buffers\n", dev->name); | ||
118 | free_netdev(dev); | ||
119 | return ERR_PTR(-ENOMEM); | ||
120 | } | ||
121 | |||
122 | lp->lance.name = (char*)name; /* discards const, shut up gcc */ | ||
123 | lp->lance.base = dev->base_addr; | ||
124 | lp->lance.init_block = (struct lance_init_block *)(lp->ram); /* CPU addr */ | ||
125 | lp->lance.lance_init_block = (struct lance_init_block *)(lp->ram); /* LANCE addr of same RAM */ | ||
126 | lp->lance.busmaster_regval = LE_C3_BSWP; /* we're bigendian */ | ||
127 | lp->lance.irq = MVME147_LANCE_IRQ; | ||
128 | lp->lance.writerap = (writerap_t)m147lance_writerap; | ||
129 | lp->lance.writerdp = (writerdp_t)m147lance_writerdp; | ||
130 | lp->lance.readrdp = (readrdp_t)m147lance_readrdp; | ||
131 | lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS; | ||
132 | lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS; | ||
133 | lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK; | ||
134 | lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK; | ||
135 | |||
136 | err = register_netdev(dev); | ||
137 | if (err) { | ||
138 | free_pages(lp->ram, 3); | ||
139 | free_netdev(dev); | ||
140 | return ERR_PTR(err); | ||
141 | } | ||
142 | |||
143 | return dev; | ||
144 | } | ||
145 | |||
146 | static void m147lance_writerap(struct lance_private *lp, unsigned short value) | ||
147 | { | ||
148 | out_be16(lp->base + LANCE_RAP, value); | ||
149 | } | ||
150 | |||
151 | static void m147lance_writerdp(struct lance_private *lp, unsigned short value) | ||
152 | { | ||
153 | out_be16(lp->base + LANCE_RDP, value); | ||
154 | } | ||
155 | |||
156 | static unsigned short m147lance_readrdp(struct lance_private *lp) | ||
157 | { | ||
158 | return in_be16(lp->base + LANCE_RDP); | ||
159 | } | ||
160 | |||
161 | static int m147lance_open(struct net_device *dev) | ||
162 | { | ||
163 | int status; | ||
164 | |||
165 | status = lance_open(dev); /* call generic lance open code */ | ||
166 | if (status) | ||
167 | return status; | ||
168 | /* enable interrupts at board level. */ | ||
169 | m147_pcc->lan_cntrl=0; /* clear the interrupts (if any) */ | ||
170 | m147_pcc->lan_cntrl=0x08 | 0x04; /* Enable irq 4 */ | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static int m147lance_close(struct net_device *dev) | ||
176 | { | ||
177 | /* disable interrupts at boardlevel */ | ||
178 | m147_pcc->lan_cntrl=0x0; /* disable interrupts */ | ||
179 | lance_close(dev); | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | #ifdef MODULE | ||
184 | MODULE_LICENSE("GPL"); | ||
185 | |||
186 | static struct net_device *dev_mvme147_lance; | ||
187 | int init_module(void) | ||
188 | { | ||
189 | dev_mvme147_lance = mvme147lance_probe(-1); | ||
190 | if (IS_ERR(dev_mvme147_lance)) | ||
191 | return PTR_ERR(dev_mvme147_lance); | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | void cleanup_module(void) | ||
196 | { | ||
197 | struct m147lance_private *lp = dev_mvme147_lance->priv; | ||
198 | unregister_netdev(dev_mvme147_lance); | ||
199 | free_pages(lp->ram, 3); | ||
200 | free_netdev(dev_mvme147_lance); | ||
201 | } | ||
202 | |||
203 | #endif /* MODULE */ | ||