File: /usr/src/linux/drivers/net/hplance.c

1     /* hplance.c  : the  Linux/hp300/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/sched.h>
11     #include <linux/types.h>
12     #include <linux/interrupt.h>
13     #include <linux/ptrace.h>
14     #include <linux/ioport.h>
15     #include <linux/slab.h>
16     #include <linux/string.h>
17     #include <linux/delay.h>
18     #include <linux/init.h>
19     #include <linux/errno.h>
20     #include <asm/system.h>
21     #include <asm/io.h>
22     #include <asm/pgtable.h>
23     
24     /* Used for the temporal inet entries and routing */
25     #include <linux/socket.h>
26     #include <linux/route.h>
27     
28     #include <linux/dio.h>
29     
30     #include <linux/netdevice.h>
31     #include <linux/etherdevice.h>
32     #include <linux/skbuff.h>
33     
34     #include "hplance.h"
35     
36     /* We have 16834 bytes of RAM for the init block and buffers. This places
37      * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx
38      * buffers and 2 Tx buffers.
39      */
40     #define LANCE_LOG_TX_BUFFERS 1
41     #define LANCE_LOG_RX_BUFFERS 3
42     
43     #include "7990.h"                                 /* use generic LANCE code */
44     
45     /* Our private data structure */
46     struct hplance_private {
47       struct lance_private lance;
48       unsigned int scode;
49       void *base;
50     };
51     
52     /* function prototypes... This is easy because all the grot is in the
53      * generic LANCE support. All we have to support is probing for boards,
54      * plus board-specific init, open and close actions. 
55      * Oh, and we need to tell the generic code how to read and write LANCE registers...
56      */
57     int hplance_probe(struct net_device *dev);
58     static int hplance_init(struct net_device *dev, int scode);
59     static int hplance_open(struct net_device *dev);
60     static int hplance_close(struct net_device *dev);
61     static void hplance_writerap(struct hplance_private *lp, unsigned short value);
62     static void hplance_writerdp(struct hplance_private *lp, unsigned short value);
63     static unsigned short hplance_readrdp(struct hplance_private *lp);
64     
65     #ifdef MODULE
66     static struct hplance_private *root_hplance_dev;
67     #endif
68     
69     /* Find all the HP Lance boards and initialise them... */
70     int __init hplance_probe(struct net_device *dev)
71     {
72             int cards = 0, called = 0;
73     
74             if (!MACH_IS_HP300 || called)
75                     return(ENODEV);
76             called++;
77             
78             /* Isn't DIO nice? */
79             for(;;)
80             {
81                     int v, scode = dio_find(DIO_ID_LAN);
82                                     
83                     if (!scode)
84                             break;
85                     
86                     if(cards)
87                             dev = NULL;      /* don't trash previous device, make a new one */
88                     cards++;
89                     
90                     v = hplance_init(dev, scode);
91                     if (v)                            /* error, abort immediately */
92                             return v;
93             }
94             /* OK, return success, or ENODEV if we didn't find any cards */
95             if (!cards)
96                     return -ENODEV;
97             return 0;
98     }
99     
100     /* Initialise a single lance board at the given select code */
101     static int __init hplance_init(struct net_device *dev, int scode)
102     {
103             /* const char *name = dio_scodetoname(scode); */
104             static const char name[] = "HP LANCE";
105             void *va = dio_scodetoviraddr(scode);
106             struct hplance_private *lp;
107             int i;
108             
109     #ifdef MODULE
110     	dev = init_etherdev(0, sizeof(struct hplance_private));
111     	if (!dev)
112     		return -ENOMEM;
113     #else
114     	dev->priv = kmalloc(sizeof(struct hplance_private), GFP_KERNEL);
115     	if (dev->priv == NULL)
116     		return -ENOMEM;
117     	memset(dev->priv, 0, sizeof(struct hplance_private));
118     #endif
119     	SET_MODULE_OWNER(dev);
120     
121             printk("%s: HP LANCE; select code %d, addr", dev->name, scode);
122     
123             /* reset the board */
124             writeb(0xff,va+DIO_IDOFF);
125             udelay(100);                              /* ariba! ariba! udelay! udelay! */
126     
127             /* Fill the dev fields */
128             dev->base_addr = (unsigned long)va;
129             dev->open = &hplance_open;
130             dev->stop = &hplance_close;
131             dev->hard_start_xmit = &lance_start_xmit;
132             dev->get_stats = &lance_get_stats;
133             dev->set_multicast_list = &lance_set_multicast;
134             dev->dma = 0;
135             
136             for (i=0; i<6; i++)
137             {
138                     /* The NVRAM holds our ethernet address, one nibble per byte,
139                      * at bytes NVRAMOFF+1,3,5,7,9...
140                      */
141                     dev->dev_addr[i] = ((readb(va + HPLANCE_NVRAMOFF + i*4 + 1) & 0xF) << 4)
142                             | (readb(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
143                     printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]);
144             }
145             
146             lp = (struct hplance_private *)dev->priv;
147             lp->lance.name = (char*)name;                   /* discards const, shut up gcc */
148             lp->lance.ll = (struct lance_regs *)(va + HPLANCE_REGOFF);
149             lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */
150             lp->lance.lance_init_block = 0;                 /* LANCE addr of same RAM */
151             lp->lance.busmaster_regval = LE_C3_BSWP;        /* we're bigendian */
152             lp->lance.irq = dio_scodetoipl(scode);
153             lp->lance.writerap = hplance_writerap;
154             lp->lance.writerdp = hplance_writerdp;
155             lp->lance.readrdp = hplance_readrdp;
156             lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
157             lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
158             lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
159             lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
160             lp->scode = scode;
161     	lp->base = va;
162             ether_setup(dev);
163     	printk(", irq %d\n", lp->lance.irq);
164     
165     #ifdef MODULE
166             dev->ifindex = dev_new_index();
167             lp->next_module = root_hplance_dev;
168             root_hplance_dev = lp;
169     #endif /* MODULE */
170     
171             dio_config_board(scode);                  /* tell bus scanning code this one's taken */
172             return 0;
173     }
174     
175     /* This is disgusting. We have to check the DIO status register for ack every
176      * time we read or write the LANCE registers.
177      */
178     static void hplance_writerap(struct hplance_private *lp, unsigned short value)
179     {
180             struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
181             do {
182                     lp->lance.ll->rap = value;
183             } while ((hpregs->status & LE_ACK) == 0);
184     }
185     
186     static void hplance_writerdp(struct hplance_private *lp, unsigned short value)
187     {
188             struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
189             do {
190                     lp->lance.ll->rdp = value;
191             } while ((hpregs->status & LE_ACK) == 0);
192     }
193     
194     static unsigned short hplance_readrdp(struct hplance_private *lp)
195     {
196             unsigned short val;
197             struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
198             do {
199                     val = lp->lance.ll->rdp;
200             } while ((hpregs->status & LE_ACK) == 0);
201             return val;
202     }
203     
204     static int hplance_open(struct net_device *dev)
205     {
206             int status;
207             struct hplance_private *lp = (struct hplance_private *)dev->priv;
208             struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
209             
210             status = lance_open(dev);                 /* call generic lance open code */
211             if (status)
212                     return status;
213             /* enable interrupts at board level. */
214             writeb(LE_IE, &(hpregs->status));
215     
216             return 0;
217     }
218     
219     static int hplance_close(struct net_device *dev)
220     {
221             struct hplance_private *lp = (struct hplance_private *)dev->priv;
222             struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
223             writeb(0,&(hpregs->status));              /* disable interrupts at boardlevel */
224             lance_close(dev);
225             return 0;
226     }
227     
228     #ifdef MODULE
229     int init_module(void)
230     {
231             root_lance_dev = NULL;
232             return hplance_probe(NULL);
233     }
234     
235     void cleanup_module(void)
236     {
237             /* Walk the chain of devices, unregistering them */
238             struct hplance_private *lp;
239             while (root_hplance_dev) {
240                     lp = root_hplance_dev->next_module;
241                     dio_unconfig_board(lp->scode);
242                     unregister_netdev(root_lance_dev->dev);
243                     kfree(root_lance_dev->dev);
244                     root_lance_dev = lp;
245             }
246     }
247     
248     #endif /* MODULE */
249