root/src/linux/brcm/linux.v24_2/drivers/net/et/etc.c

Revision 8761, 7.4 kB (checked in by BrainSlayer, 3 years ago)

commit newer linux.v24 kernel code (some parts missing, will be added in the next days)

Line 
1 /*
2  * Common [OS-independent] portion of
3  * Broadcom Home Networking Division 10/100 Mbit/s Ethernet
4  * Device Driver.
5  *
6  * Copyright 2004, Broadcom Corporation   
7  * All Rights Reserved.                   
8  *                                       
9  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;     
10  * the contents of this file may not be disclosed to third parties, copied   
11  * or duplicated in any form, in whole or in part, without the prior         
12  * written permission of Broadcom Corporation.                               
13  * $Id$
14  */
15
16 #include <osl.h>
17 #include <bcmendian.h>
18 #include <proto/ethernet.h>
19 #include <bcmenetmib.h>
20 #include <bcmenetrxh.h>
21 #include <bcmenetphy.h>
22 #include <et_dbg.h>
23 #include <etc.h>
24 #include <et_export.h>
25 #include <bcmutils.h>
26
27 int et_msg_level =
28         0;
29
30 /* local prototypes */
31 static void etc_loopback(etc_info_t *etc, int on);
32
33 /* find the chip opsvec for this chip */
34 struct chops*
35 etc_chipmatch(uint vendor, uint device)
36 {
37         {
38         extern struct chops bcm47xx_et_chops;
39         if (bcm47xx_et_chops.id(vendor, device))
40                 return (&bcm47xx_et_chops);
41         }
42         return (NULL);
43 }
44
45 void*
46 etc_attach(void *et, uint vendor, uint device, uint unit, void *osh, void *regsva)
47 {
48         etc_info_t *etc;
49
50         ET_TRACE(("et%d: etc_attach: vendor 0x%x device 0x%x\n", unit, vendor, device));
51
52         /* some code depends on packed structures */
53         ASSERT(sizeof (struct ether_addr) == ETHER_ADDR_LEN);
54         ASSERT(sizeof (struct ether_header) == ETHER_HDR_LEN);
55
56         /* allocate etc_info_t state structure */
57         if ((etc = (etc_info_t*) MALLOC(osh, sizeof (etc_info_t))) == NULL) {
58                 ET_ERROR(("et%d: etc_attach: out of memory, malloced %d bytes\n", unit, MALLOCED(osh)));
59                 return (NULL);
60         }
61         bzero((char*)etc, sizeof (etc_info_t));
62
63         etc->et = et;
64         etc->unit = unit;
65         etc->osh = osh;
66         etc->vendorid = (uint16) vendor;
67         etc->deviceid = (uint16) device;
68         etc->forcespeed = ET_AUTO;
69         etc->linkstate = FALSE;
70
71         /* set chip opsvec */
72         etc->chops = etc_chipmatch(vendor, device);
73         ASSERT(etc->chops);
74
75         /* chip attach */
76         if ((etc->ch = (*etc->chops->attach)(etc, osh, regsva)) == NULL) {
77                 ET_ERROR(("et%d: chipattach error\n", unit));
78                 goto fail;
79         }
80
81         return ((void*)etc);
82
83 fail:
84         etc_detach(etc);
85         return (NULL);
86 }
87
88 void
89 etc_detach(etc_info_t *etc)
90 {
91         if (etc == NULL)
92                 return;
93
94         /* free chip private state */
95         if (etc->ch) {
96                 (*etc->chops->detach)(etc->ch);
97                 etc->chops = etc->ch = NULL;
98         }
99
100         MFREE(etc->osh, etc, sizeof (etc_info_t));
101 }
102
103 void
104 etc_reset(etc_info_t *etc)
105 {
106         ET_TRACE(("et%d: etc_reset\n", etc->unit));
107
108         etc->reset++;
109
110         /* reset the chip */
111         (*etc->chops->reset)(etc->ch);
112
113         /* free any posted tx packets */
114         (*etc->chops->txreclaim)(etc->ch, TRUE);
115
116 #ifdef DMA
117         /* free any posted rx packets */
118         (*etc->chops->rxreclaim)(etc->ch);
119 #endif
120 }
121
122 void
123 etc_init(etc_info_t *etc)
124 {
125         ET_TRACE(("et%d: etc_init\n", etc->unit));
126
127         ASSERT(etc->pioactive == NULL);
128         ASSERT(!ETHER_ISNULLADDR(&etc->cur_etheraddr));
129         ASSERT(!ETHER_ISMULTI(&etc->cur_etheraddr));
130
131         /* init the chip */
132         (*etc->chops->init)(etc->ch, TRUE);
133 }
134
135 /* mark interface up */
136 void
137 etc_up(etc_info_t *etc)
138 {
139         etc->up = TRUE;
140
141         et_init(etc->et);
142 }
143
144 /* mark interface down */
145 uint
146 etc_down(etc_info_t *etc, int reset)
147 {
148         uint callback;
149
150         callback = 0;
151
152         etc->up = FALSE;
153         if (reset)
154                 et_reset(etc->et);
155
156         /* suppress link state changes during power management mode changes */
157         if (etc->linkstate) {
158                 etc->linkstate = FALSE;
159                 if (!etc->pm_modechange)
160                         et_link_down(etc->et);
161         }
162
163         return (callback);
164 }
165
166 /* common ioctl handler.  return: 0=ok, -1=error */
167 int
168 etc_ioctl(etc_info_t *etc, int cmd, void *arg)
169 {
170         int error;
171         int val;
172         int *vec = (int*)arg;
173
174         error = 0;
175
176         val = arg? *(int*)arg: 0;
177
178         ET_TRACE(("et%d: etc_ioctl: cmd 0x%x\n", etc->unit, cmd));
179
180         switch (cmd) {
181         case ETCUP:
182                 et_up(etc->et);
183                 break;
184
185         case ETCDOWN:
186                 et_down(etc->et, TRUE);
187                 break;
188
189         case ETCLOOP:
190                 etc_loopback(etc, val);
191                 break;
192
193         case ETCDUMP:
194                 if (et_msg_level & 0x10000)
195                         bcmdumplog((uchar*)arg, 4096);
196                 break;
197
198         case ETCSETMSGLEVEL:
199                 et_msg_level = val;
200                 break;
201
202         case ETCPROMISC:
203                 etc_promisc(etc, val);
204                 break;
205
206         case ETCQOS:
207                 etc_qos(etc, val);
208                 break;
209
210         case ETCSPEED:
211                 if ((val != ET_AUTO) && (val != ET_10HALF) && (val != ET_10FULL)
212                         && (val != ET_100HALF) && (val != ET_100FULL))
213                         goto err;
214                 etc->forcespeed = val;
215
216                 /* explicitly reset the phy */
217                 (*etc->chops->phyreset)(etc->ch, etc->phyaddr);
218
219                 /* request restart autonegotiation if we're reverting to adv mode */
220                 if ((etc->forcespeed == ET_AUTO) & etc->advertise)
221                         etc->needautoneg = TRUE;
222
223                 et_init(etc->et);
224                 break;
225
226         case ETCPHYRD:
227                 if (vec)
228                         vec[1] = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, vec[0]);
229                 break;
230
231         case ETCPHYWR:
232                 if (vec)
233                         (*etc->chops->phywr)(etc->ch, etc->phyaddr, vec[0], (uint16) vec[1]);
234                 break;
235                
236         default:
237         err:
238                 error = -1;
239         }
240
241         return (error);
242 }
243
244 /* called once per second */
245 void
246 etc_watchdog(etc_info_t *etc)
247 {
248         uint16 control;
249         uint16 status;
250         uint16 adv;
251         uint16 lpa;
252
253         etc->now++;
254
255         /* no local phy registers */
256         if (etc->phyaddr == EPHY_NOREG) {
257                 control = CTL_SPEED | CTL_DUPLEX;
258                 status = STAT_LINK;
259         } else {
260                 control = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 0);
261                 status = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 1);
262         }
263
264         /* check for bad mdio read */
265         if (control == 0xffff || status == 0xffff) {
266                 ET_ERROR(("et%d: etc_watchdog: bad mdio read: phyaddr %d mdcport %d\n",
267                         etc->unit, etc->phyaddr, etc->mdcport));
268                 return;
269         }
270
271         /* update current speed and duplex */
272         if (control & CTL_ANENAB) {
273                 adv = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 4);
274                 lpa = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 5);
275        
276                 if ((adv & ADV_100FULL) && (lpa & LPA_100FULL)) {
277                         etc->speed = 100;
278                         etc->duplex = 1;
279                 } else if ((adv & ADV_100HALF) && (lpa & LPA_100HALF)) {
280                         etc->speed = 100;
281                         etc->duplex = 0;
282                 } else if ((adv & ADV_10FULL) && (lpa & LPA_10FULL)) {
283                         etc->speed = 10;
284                         etc->duplex = 1;
285                 } else {
286                         etc->speed = 10;
287                         etc->duplex = 0;
288                 }
289         } else {
290                 etc->speed = (control & CTL_SPEED) ? 100 : 10;
291                 etc->duplex = (control & CTL_DUPLEX) ? 1 : 0;
292         }
293
294         /* monitor link state */
295         if (!etc->linkstate && (status & STAT_LINK)) {
296                 etc->linkstate = TRUE;
297
298                 if (etc->pm_modechange)
299                         etc->pm_modechange = FALSE;
300                 else
301                 {
302                         et_link_up(etc->et);
303                 }
304         }
305         else if (etc->linkstate && !(status & STAT_LINK)) {
306                 etc->linkstate = FALSE;
307                 if (!etc->pm_modechange)
308                 {
309                         et_link_down(etc->et);
310                 }       
311         }
312
313         /* keep emac txcontrol duplex bit consistent with current phy duplex */
314         (*etc->chops->duplexupd)(etc->ch);
315
316         /* check for remote fault error */
317         if (status & STAT_REMFAULT) {
318                 ET_ERROR(("et%d: remote fault\n", etc->unit));
319         }
320
321         /* check for jabber error */
322         if (status & STAT_JAB) {
323                 ET_ERROR(("et%d: jabber\n", etc->unit));
324         }
325
326         /*
327          * Read chip mib counters occationally before the 16bit ones can wrap.
328          * We don't use the high-rate mib counters.
329          */
330         if ((etc->now % 30) == 0)
331                 (*etc->chops->statsupd)(etc->ch);
332 }
333
334 static void
335 etc_loopback(etc_info_t *etc, int on)
336 {
337         ET_TRACE(("et%d: etc_loopback: %d\n", etc->unit, on));
338
339         etc->loopbk = (bool) on;
340         et_init(etc->et);
341 }
342
343 void
344 etc_promisc(etc_info_t *etc, uint on)
345 {
346         ET_TRACE(("et%d: etc_promisc: %d\n", etc->unit, on));
347
348         etc->promisc = (bool) on;
349         et_init(etc->et);
350 }
351
352 void
353 etc_qos(etc_info_t *etc, uint on)
354 {
355         ET_TRACE(("et%d: etc_qos: %d\n", etc->unit, on));
356
357         etc->qos = (bool) on;
358         et_init(etc->et);
359 }
360
361
362 uint
363 etc_totlen(etc_info_t *etc, void *p)
364 {
365         uint total;
366
367         total = 0;
368         for (; p; p = PKTNEXT(etc->et, p))
369                 total += PKTLEN(etc->et, p);
370         return (total);
371 }
372
Note: See TracBrowser for help on using the browser.