SSID: Respect ASCII character Label.
[tomato.git] / release / src / et / sys / etc.c
blob92c70106c6395edf00f1c4bc30ed3df4f6de2e46
1 /*
2 * Common [OS-independent] portion of
3 * Broadcom Home Networking Division 10/100 Mbit/s Ethernet
4 * Device Driver.
6 * Copyright 2006, 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: etc.c,v 1.1.1.1 2007/03/20 12:22:00 roly Exp $
16 #include <typedefs.h>
17 #include <osl.h>
18 #include <bcmendian.h>
19 #include <proto/ethernet.h>
20 #include <proto/vlan.h>
21 #include <proto/bcmip.h>
22 #include <bcmenetmib.h>
23 #include <bcmenetrxh.h>
24 #include <bcmenetphy.h>
25 #include <et_dbg.h>
26 #include <etc.h>
27 #include <et_export.h>
28 #include <bcmutils.h>
30 #ifdef ETROBO
31 #ifndef _sbutils_h_
32 typedef const struct sb_pub sb_t;
33 #endif
34 #include <bcmrobo.h>
35 #endif /* ETROBO */
37 uint32 et_msg_level =
40 /* local prototypes */
41 static void etc_loopback(etc_info_t *etc, int on);
43 /* find the chip opsvec for this chip */
44 struct chops*
45 etc_chipmatch(uint vendor, uint device)
48 extern struct chops bcm47xx_et_chops;
49 if (bcm47xx_et_chops.id(vendor, device))
50 return (&bcm47xx_et_chops);
52 return (NULL);
55 void*
56 etc_attach(void *et, uint vendor, uint device, uint unit, void *osh, void *regsva)
58 etc_info_t *etc;
60 ET_TRACE(("et%d: etc_attach: vendor 0x%x device 0x%x\n", unit, vendor, device));
62 /* some code depends on packed structures */
63 ASSERT(sizeof(struct ether_addr) == ETHER_ADDR_LEN);
64 ASSERT(sizeof(struct ether_header) == ETHER_HDR_LEN);
66 /* allocate etc_info_t state structure */
67 if ((etc = (etc_info_t*) MALLOC(osh, sizeof(etc_info_t))) == NULL) {
68 ET_ERROR(("et%d: etc_attach: out of memory, malloced %d bytes\n", unit,
69 MALLOCED(osh)));
70 return (NULL);
72 bzero((char*)etc, sizeof(etc_info_t));
74 etc->et = et;
75 etc->unit = unit;
76 etc->osh = osh;
77 etc->vendorid = (uint16) vendor;
78 etc->deviceid = (uint16) device;
79 etc->forcespeed = ET_AUTO;
80 etc->linkstate = FALSE;
82 /* set chip opsvec */
83 etc->chops = etc_chipmatch(vendor, device);
84 ASSERT(etc->chops);
86 /* chip attach */
87 if ((etc->ch = (*etc->chops->attach)(etc, osh, regsva)) == NULL) {
88 ET_ERROR(("et%d: chipattach error\n", unit));
89 goto fail;
92 return ((void*)etc);
94 fail:
95 etc_detach(etc);
96 return (NULL);
99 void
100 etc_detach(etc_info_t *etc)
102 if (etc == NULL)
103 return;
105 /* free chip private state */
106 if (etc->ch) {
107 (*etc->chops->detach)(etc->ch);
108 etc->chops = etc->ch = NULL;
111 MFREE(etc->osh, etc, sizeof(etc_info_t));
114 void
115 etc_reset(etc_info_t *etc)
117 ET_TRACE(("et%d: etc_reset\n", etc->unit));
119 etc->reset++;
121 /* reset the chip */
122 (*etc->chops->reset)(etc->ch);
124 /* free any posted tx packets */
125 (*etc->chops->txreclaim)(etc->ch, TRUE);
127 #ifdef DMA
128 /* free any posted rx packets */
129 (*etc->chops->rxreclaim)(etc->ch);
130 #endif /* DMA */
133 void
134 etc_init(etc_info_t *etc)
136 ET_TRACE(("et%d: etc_init\n", etc->unit));
138 ASSERT(etc->pioactive == NULL);
139 ASSERT(!ETHER_ISNULLADDR(&etc->cur_etheraddr));
140 ASSERT(!ETHER_ISMULTI(&etc->cur_etheraddr));
142 /* init the chip */
143 (*etc->chops->init)(etc->ch, TRUE);
146 /* mark interface up */
147 void
148 etc_up(etc_info_t *etc)
150 etc->up = TRUE;
152 et_init(etc->et);
155 /* mark interface down */
156 uint
157 etc_down(etc_info_t *etc, int reset)
159 uint callback;
161 callback = 0;
163 etc->up = FALSE;
164 if (reset)
165 et_reset(etc->et);
167 /* suppress link state changes during power management mode changes */
168 if (etc->linkstate) {
169 etc->linkstate = FALSE;
170 if (!etc->pm_modechange)
171 et_link_down(etc->et);
174 return (callback);
177 /* common ioctl handler. return: 0=ok, -1=error */
179 etc_ioctl(etc_info_t *etc, int cmd, void *arg)
181 int error;
182 int val;
183 int *vec = (int*)arg;
185 error = 0;
187 val = arg ? *(int*)arg : 0;
189 ET_TRACE(("et%d: etc_ioctl: cmd 0x%x\n", etc->unit, cmd));
191 switch (cmd) {
192 case ETCUP:
193 et_up(etc->et);
194 break;
196 case ETCDOWN:
197 et_down(etc->et, TRUE);
198 break;
200 case ETCLOOP:
201 etc_loopback(etc, val);
202 break;
204 case ETCDUMP:
205 if (et_msg_level & 0x10000)
206 bcmdumplog((char *)arg, 4096);
207 break;
209 case ETCSETMSGLEVEL:
210 et_msg_level = val;
211 break;
213 case ETCPROMISC:
214 etc_promisc(etc, val);
215 break;
217 case ETCQOS:
218 etc_qos(etc, val);
219 break;
221 case ETCSPEED:
222 if ((val != ET_AUTO) && (val != ET_10HALF) && (val != ET_10FULL) &&
223 (val != ET_100HALF) && (val != ET_100FULL))
224 goto err;
225 etc->forcespeed = val;
227 /* explicitly reset the phy */
228 (*etc->chops->phyreset)(etc->ch, etc->phyaddr);
230 /* request restart autonegotiation if we're reverting to adv mode */
231 if ((etc->forcespeed == ET_AUTO) & etc->advertise)
232 etc->needautoneg = TRUE;
234 et_init(etc->et);
235 break;
237 case ETCPHYRD:
238 if (vec) {
239 vec[1] = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, vec[0]);
240 ET_TRACE(("etc_ioctl: ETCPHYRD of reg 0x%x => 0x%x\n", vec[0], vec[1]));
242 break;
244 case ETCPHYRD2:
245 if (vec) {
246 uint phyaddr, reg;
247 phyaddr = vec[0] >> 16;
248 if (phyaddr < MAXEPHY) {
249 reg = vec[0] & 0xffff;
250 vec[1] = (*etc->chops->phyrd)(etc->ch, phyaddr, reg);
251 ET_TRACE(("etc_ioctl: ETCPHYRD2 of phy 0x%x, reg 0x%x => 0x%x\n",
252 phyaddr, reg, vec[1]));
255 break;
257 case ETCPHYWR:
258 if (vec) {
259 ET_TRACE(("etc_ioctl: ETCPHYWR to reg 0x%x <= 0x%x\n", vec[0], vec[1]));
260 (*etc->chops->phywr)(etc->ch, etc->phyaddr, vec[0], (uint16)vec[1]);
262 break;
264 case ETCPHYWR2:
265 if (vec) {
266 uint phyaddr, reg;
267 phyaddr = vec[0] >> 16;
268 if (phyaddr < MAXEPHY) {
269 reg = vec[0] & 0xffff;
270 (*etc->chops->phywr)(etc->ch, phyaddr, reg, (uint16)vec[1]);
271 ET_TRACE(("etc_ioctl: ETCPHYWR2 to phy 0x%x, reg 0x%x <= 0x%x\n",
272 phyaddr, reg, vec[1]));
275 break;
277 #ifdef ETROBO
278 case ETCROBORD:
279 if (etc->robo && vec) {
280 uint page, reg;
281 uint16 val;
282 robo_info_t *robo = (robo_info_t *)etc->robo;
284 page = vec[0] >> 16;
285 reg = vec[0] & 0xffff;
286 val = -1;
287 robo->ops->read_reg(etc->robo, page, reg, &val, 2);
288 vec[1] = val;
289 ET_TRACE(("etc_ioctl: ETCROBORD of page 0x%x, reg 0x%x => 0x%x\n",
290 page, reg, val));
292 break;
294 case ETCROBOWR:
295 if (etc->robo && vec) {
296 uint page, reg;
297 uint16 val;
298 robo_info_t *robo = (robo_info_t *)etc->robo;
300 page = vec[0] >> 16;
301 reg = vec[0] & 0xffff;
302 val = vec[1];
303 robo->ops->write_reg(etc->robo, page, vec[0], &val, 2);
304 ET_TRACE(("etc_ioctl: ETCROBOWR to page 0x%x, reg 0x%x <= 0x%x\n",
305 page, reg, val));
307 break;
308 #endif /* ETROBO */
311 default:
312 err:
313 error = -1;
316 return (error);
319 /* called once per second */
320 void
321 etc_watchdog(etc_info_t *etc)
323 uint16 control;
324 uint16 status;
325 uint16 adv;
326 uint16 lpa;
328 etc->now++;
330 /* no local phy registers */
331 if (etc->phyaddr == EPHY_NOREG) {
332 control = CTL_SPEED | CTL_DUPLEX;
333 status = STAT_LINK;
334 } else {
335 control = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 0);
336 status = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 1);
339 /* check for bad mdio read */
340 if (control == 0xffff || status == 0xffff) {
341 ET_ERROR(("et%d: etc_watchdog: bad mdio read: phyaddr %d mdcport %d\n",
342 etc->unit, etc->phyaddr, etc->mdcport));
343 return;
346 /* update current speed and duplex */
347 if (control & CTL_ANENAB) {
348 adv = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 4);
349 lpa = (*etc->chops->phyrd)(etc->ch, etc->phyaddr, 5);
351 if ((adv & ADV_100FULL) && (lpa & LPA_100FULL)) {
352 etc->speed = 100;
353 etc->duplex = 1;
354 } else if ((adv & ADV_100HALF) && (lpa & LPA_100HALF)) {
355 etc->speed = 100;
356 etc->duplex = 0;
357 } else if ((adv & ADV_10FULL) && (lpa & LPA_10FULL)) {
358 etc->speed = 10;
359 etc->duplex = 1;
360 } else {
361 etc->speed = 10;
362 etc->duplex = 0;
364 } else {
365 etc->speed = (control & CTL_SPEED) ? 100 : 10;
366 etc->duplex = (control & CTL_DUPLEX) ? 1 : 0;
369 /* monitor link state */
370 if (!etc->linkstate && (status & STAT_LINK)) {
371 etc->linkstate = TRUE;
373 if (etc->pm_modechange)
374 etc->pm_modechange = FALSE;
375 else
377 et_link_up(etc->et);
380 else if (etc->linkstate && !(status & STAT_LINK)) {
381 etc->linkstate = FALSE;
382 if (!etc->pm_modechange)
384 et_link_down(etc->et);
388 /* keep emac txcontrol duplex bit consistent with current phy duplex */
389 (*etc->chops->duplexupd)(etc->ch);
391 /* check for remote fault error */
392 if (status & STAT_REMFAULT) {
393 ET_ERROR(("et%d: remote fault\n", etc->unit));
396 /* check for jabber error */
397 if (status & STAT_JAB) {
398 ET_ERROR(("et%d: jabber\n", etc->unit));
402 * Read chip mib counters occationally before the 16bit ones can wrap.
403 * We don't use the high-rate mib counters.
405 if ((etc->now % 30) == 0)
406 (*etc->chops->statsupd)(etc->ch);
409 static void
410 etc_loopback(etc_info_t *etc, int on)
412 ET_TRACE(("et%d: etc_loopback: %d\n", etc->unit, on));
414 etc->loopbk = (bool) on;
415 et_init(etc->et);
418 void
419 etc_promisc(etc_info_t *etc, uint on)
421 ET_TRACE(("et%d: etc_promisc: %d\n", etc->unit, on));
423 etc->promisc = (bool) on;
424 et_init(etc->et);
427 void
428 etc_qos(etc_info_t *etc, uint on)
430 ET_TRACE(("et%d: etc_qos: %d\n", etc->unit, on));
432 etc->qos = (bool) on;
433 et_init(etc->et);
437 uint
438 etc_totlen(etc_info_t *etc, void *p)
440 uint total;
442 total = 0;
443 for (; p; p = PKTNEXT(etc->osh, p))
444 total += PKTLEN(etc->osh, p);
445 return (total);