1 /* $NetBSD: if_ex_cardbus.c,v 1.45 2008/06/24 19:44:52 drochner Exp $ */
4 * Copyright (c) 1998 and 1999
5 * HAYAKAWA Koichi. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY HAYAKAWA KOICHI ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL TAKESHI OHASHI OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * CardBus specific routines for 3Com 3C575-family CardBus ethernet adapter
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: if_ex_cardbus.c,v 1.45 2008/06/24 19:44:52 drochner Exp $");
36 /* #define EX_DEBUG 4 */ /* define to report information for debugging */
38 #include <sys/param.h>
39 #include <sys/systm.h>
41 #include <sys/socket.h>
42 #include <sys/ioctl.h>
43 #include <sys/errno.h>
44 #include <sys/syslog.h>
45 #include <sys/select.h>
46 #include <sys/device.h>
49 #include <net/if_dl.h>
50 #include <net/if_ether.h>
51 #include <net/if_media.h>
56 #include <dev/cardbus/cardbusvar.h>
57 #include <dev/pci/pcidevs.h>
59 #include <dev/mii/miivar.h>
61 #include <dev/ic/elink3var.h>
62 #include <dev/ic/elink3reg.h>
63 #include <dev/ic/elinkxlreg.h>
64 #include <dev/ic/elinkxlvar.h>
66 #if defined DEBUG && !defined EX_DEBUG
71 #define DPRINTF(a) printf a
76 #define CARDBUS_3C575BTX_FUNCSTAT_PCIREG CARDBUS_BASE2_REG /* means 0x18 */
77 #define EX_CB_INTR 4 /* intr acknowledge reg. CardBus only */
78 #define EX_CB_INTR_ACK 0x8000 /* intr acknowledge bit */
80 int ex_cardbus_match(device_t
, cfdata_t
, void *);
81 void ex_cardbus_attach(device_t
, device_t
, void *);
82 int ex_cardbus_detach(device_t
, int);
83 void ex_cardbus_intr_ack(struct ex_softc
*);
85 int ex_cardbus_enable(struct ex_softc
*);
86 void ex_cardbus_disable(struct ex_softc
*);
88 struct ex_cardbus_softc
{
89 struct ex_softc sc_softc
;
91 cardbus_devfunc_t sc_ct
;
92 cardbus_intr_line_t sc_intrline
;
93 uint8_t sc_cardbus_flags
;
94 #define EX_REATTACH 0x01
95 #define EX_ABSENT 0x02
97 #define EX_CB_BOOMERANG 1
98 #define EX_CB_CYCLONE 2
100 /* CardBus function status space. 575B requests it. */
101 bus_space_tag_t sc_funct
;
102 bus_space_handle_t sc_funch
;
103 bus_size_t sc_funcsize
;
105 bus_size_t sc_mapsize
; /* the size of mapped bus space region */
109 int sc_csr
; /* CSR bits */
110 int sc_bar_reg
; /* which BAR to use */
111 pcireg_t sc_bar_val
; /* value of the BAR */
112 int sc_bar_reg1
; /* which BAR to use */
113 pcireg_t sc_bar_val1
; /* value of the BAR */
117 CFATTACH_DECL_NEW(ex_cardbus
, sizeof(struct ex_cardbus_softc
),
118 ex_cardbus_match
, ex_cardbus_attach
, ex_cardbus_detach
, ex_activate
);
120 const struct ex_cardbus_product
{
121 uint32_t ecp_prodid
; /* CardBus product ID */
122 int ecp_flags
; /* initial softc flags */
123 pcireg_t ecp_csr
; /* PCI CSR flags */
124 int ecp_cardtype
; /* card type */
125 const char *ecp_name
; /* device name */
126 } ex_cardbus_products
[] = {
127 { PCI_PRODUCT_3COM_3C575TX
,
128 EX_CONF_MII
| EX_CONF_EEPROM_OFF
| EX_CONF_EEPROM_8BIT
,
129 CARDBUS_COMMAND_IO_ENABLE
| CARDBUS_COMMAND_MASTER_ENABLE
,
131 "3c575-TX Ethernet" },
133 { PCI_PRODUCT_3COM_3C575BTX
,
134 EX_CONF_90XB
|EX_CONF_MII
|EX_CONF_INV_LED_POLARITY
|
135 EX_CONF_EEPROM_OFF
| EX_CONF_EEPROM_8BIT
,
136 CARDBUS_COMMAND_IO_ENABLE
| CARDBUS_COMMAND_MEM_ENABLE
|
137 CARDBUS_COMMAND_MASTER_ENABLE
,
139 "3c575B-TX Ethernet" },
141 { PCI_PRODUCT_3COM_3C575CTX
,
142 EX_CONF_90XB
| EX_CONF_PHY_POWER
| EX_CONF_EEPROM_OFF
|
144 CARDBUS_COMMAND_IO_ENABLE
| CARDBUS_COMMAND_MEM_ENABLE
|
145 CARDBUS_COMMAND_MASTER_ENABLE
,
147 "3c575CT Ethernet" },
149 { PCI_PRODUCT_3COM_3C656_E
,
150 EX_CONF_90XB
| EX_CONF_PHY_POWER
| EX_CONF_EEPROM_OFF
|
151 EX_CONF_EEPROM_8BIT
| EX_CONF_INV_LED_POLARITY
,
152 CARDBUS_COMMAND_IO_ENABLE
| CARDBUS_COMMAND_MEM_ENABLE
|
153 CARDBUS_COMMAND_MASTER_ENABLE
,
155 "3c656-TX Ethernet" },
157 { PCI_PRODUCT_3COM_3C656B_E
,
158 EX_CONF_90XB
| EX_CONF_PHY_POWER
| EX_CONF_EEPROM_OFF
|
159 EX_CONF_EEPROM_8BIT
| EX_CONF_INV_LED_POLARITY
,
160 CARDBUS_COMMAND_IO_ENABLE
| CARDBUS_COMMAND_MEM_ENABLE
|
161 CARDBUS_COMMAND_MASTER_ENABLE
,
163 "3c656B-TX Ethernet" },
165 { PCI_PRODUCT_3COM_3C656C_E
,
166 EX_CONF_90XB
| EX_CONF_PHY_POWER
| EX_CONF_EEPROM_OFF
|
168 CARDBUS_COMMAND_IO_ENABLE
| CARDBUS_COMMAND_MEM_ENABLE
|
169 CARDBUS_COMMAND_MASTER_ENABLE
,
171 "3c656C-TX Ethernet" },
181 void ex_cardbus_setup(struct ex_cardbus_softc
*);
183 const struct ex_cardbus_product
*ex_cardbus_lookup
184 (const struct cardbus_attach_args
*);
186 const struct ex_cardbus_product
*
187 ex_cardbus_lookup(const struct cardbus_attach_args
*ca
)
189 const struct ex_cardbus_product
*ecp
;
191 if (CARDBUS_VENDOR(ca
->ca_id
) != PCI_VENDOR_3COM
)
194 for (ecp
= ex_cardbus_products
; ecp
->ecp_name
!= NULL
; ecp
++)
195 if (CARDBUS_PRODUCT(ca
->ca_id
) == ecp
->ecp_prodid
)
201 ex_cardbus_match(device_t parent
, cfdata_t cf
, void *aux
)
203 struct cardbus_attach_args
*ca
= aux
;
205 if (ex_cardbus_lookup(ca
) != NULL
)
212 ex_cardbus_attach(device_t parent
, device_t self
, void *aux
)
214 struct ex_cardbus_softc
*csc
= device_private(self
);
215 struct ex_softc
*sc
= &csc
->sc_softc
;
216 struct cardbus_attach_args
*ca
= aux
;
217 cardbus_devfunc_t ct
= ca
->ca_ct
;
220 cardbus_chipset_tag_t cc
= ct
->ct_cc
;
222 const struct ex_cardbus_product
*ecp
;
223 bus_addr_t adr
, adr1
;
227 sc
->ex_bustype
= EX_BUS_CARDBUS
;
228 sc
->sc_dmat
= ca
->ca_dmat
;
229 csc
->sc_ct
= ca
->ca_ct
;
230 csc
->sc_intrline
= ca
->ca_intrline
;
231 csc
->sc_tag
= ca
->ca_tag
;
233 ecp
= ex_cardbus_lookup(ca
);
236 panic("ex_cardbus_attach: impossible");
239 aprint_normal(": 3Com %s\n", ecp
->ecp_name
);
241 sc
->ex_conf
= ecp
->ecp_flags
;
242 csc
->sc_cardtype
= ecp
->ecp_cardtype
;
243 csc
->sc_csr
= ecp
->ecp_csr
;
245 if (Cardbus_mapreg_map(ct
, CARDBUS_BASE0_REG
, CARDBUS_MAPREG_TYPE_IO
, 0,
246 &sc
->sc_iot
, &sc
->sc_ioh
, &adr
, &csc
->sc_mapsize
) == 0) {
249 (*ct
->ct_cf
->cardbus_io_open
)(cc
, 0, adr
, adr
+ csc
->sc_mapsize
);
251 csc
->sc_bar_reg
= CARDBUS_BASE0_REG
;
252 csc
->sc_bar_val
= adr
| CARDBUS_MAPREG_TYPE_IO
;
254 if (csc
->sc_cardtype
== EX_CB_CYCLONE
) {
255 /* Map CardBus function status window. */
256 if (Cardbus_mapreg_map(ct
,
257 CARDBUS_3C575BTX_FUNCSTAT_PCIREG
,
258 CARDBUS_MAPREG_TYPE_MEM
, 0,
259 &csc
->sc_funct
, &csc
->sc_funch
,
260 &adr1
, &csc
->sc_funcsize
) == 0) {
263 CARDBUS_3C575BTX_FUNCSTAT_PCIREG
;
265 adr1
| CARDBUS_MAPREG_TYPE_MEM
;
268 aprint_error_dev(self
, "unable to map function "
273 /* Setup interrupt acknowledge hook */
274 sc
->intr_ack
= ex_cardbus_intr_ack
;
278 aprint_naive(": can't map i/o space\n");
282 /* Power management hooks. */
283 sc
->enable
= ex_cardbus_enable
;
284 sc
->disable
= ex_cardbus_disable
;
287 * Handle power management nonsense and
288 * initialize the configuration registers.
290 ex_cardbus_setup(csc
);
294 if (csc
->sc_cardtype
== EX_CB_CYCLONE
)
295 bus_space_write_4(csc
->sc_funct
, csc
->sc_funch
,
296 EX_CB_INTR
, EX_CB_INTR_ACK
);
298 Cardbus_function_disable(csc
->sc_ct
);
302 ex_cardbus_intr_ack(struct ex_softc
*sc
)
304 struct ex_cardbus_softc
*csc
= (struct ex_cardbus_softc
*)sc
;
306 bus_space_write_4(csc
->sc_funct
, csc
->sc_funch
, EX_CB_INTR
,
311 ex_cardbus_detach(device_t self
, int arg
)
313 struct ex_cardbus_softc
*csc
= device_private(self
);
314 struct ex_softc
*sc
= &csc
->sc_softc
;
315 struct cardbus_devfunc
*ct
= csc
->sc_ct
;
318 #if defined(DIAGNOSTIC)
320 panic("%s: data structure lacks", device_xname(self
));
327 * Unhook the interrupt handler.
329 cardbus_intr_disestablish(ct
->ct_cc
, ct
->ct_cf
, sc
->sc_ih
);
331 if (csc
->sc_cardtype
== EX_CB_CYCLONE
) {
332 Cardbus_mapreg_unmap(ct
,
333 CARDBUS_3C575BTX_FUNCSTAT_PCIREG
,
334 csc
->sc_funct
, csc
->sc_funch
, csc
->sc_funcsize
);
337 Cardbus_mapreg_unmap(ct
, CARDBUS_BASE0_REG
, sc
->sc_iot
,
338 sc
->sc_ioh
, csc
->sc_mapsize
);
344 ex_cardbus_enable(struct ex_softc
*sc
)
346 struct ex_cardbus_softc
*csc
= (struct ex_cardbus_softc
*)sc
;
347 cardbus_function_tag_t cf
= csc
->sc_ct
->ct_cf
;
348 cardbus_chipset_tag_t cc
= csc
->sc_ct
->ct_cc
;
350 Cardbus_function_enable(csc
->sc_ct
);
351 ex_cardbus_setup(csc
);
353 sc
->sc_ih
= cardbus_intr_establish(cc
, cf
, csc
->sc_intrline
,
354 IPL_NET
, ex_intr
, sc
);
355 if (NULL
== sc
->sc_ih
) {
356 aprint_error_dev(sc
->sc_dev
, "couldn't establish interrupt\n");
364 ex_cardbus_disable(struct ex_softc
*sc
)
366 struct ex_cardbus_softc
*csc
= (struct ex_cardbus_softc
*)sc
;
367 cardbus_function_tag_t cf
= csc
->sc_ct
->ct_cf
;
368 cardbus_chipset_tag_t cc
= csc
->sc_ct
->ct_cc
;
370 cardbus_intr_disestablish(cc
, cf
, sc
->sc_ih
);
373 Cardbus_function_disable(csc
->sc_ct
);
378 ex_cardbus_setup(struct ex_cardbus_softc
*csc
)
380 cardbus_devfunc_t ct
= csc
->sc_ct
;
381 cardbus_chipset_tag_t cc
= ct
->ct_cc
;
382 cardbus_function_tag_t cf
= ct
->ct_cf
;
385 (void)cardbus_set_powerstate(ct
, csc
->sc_tag
, PCI_PWR_D0
);
387 /* Program the BAR */
388 cardbus_conf_write(cc
, cf
, csc
->sc_tag
,
389 csc
->sc_bar_reg
, csc
->sc_bar_val
);
390 /* Make sure the right access type is on the CardBus bridge. */
391 (ct
->ct_cf
->cardbus_ctrl
)(cc
, CARDBUS_IO_ENABLE
);
392 if (csc
->sc_cardtype
== EX_CB_CYCLONE
) {
393 /* Program the BAR */
394 cardbus_conf_write(cc
, cf
, csc
->sc_tag
,
395 csc
->sc_bar_reg1
, csc
->sc_bar_val1
);
397 * Make sure CardBus brigde can access memory space. Usually
398 * memory access is enabled by BIOS, but some BIOSes do not
401 (ct
->ct_cf
->cardbus_ctrl
)(cc
, CARDBUS_MEM_ENABLE
);
403 (ct
->ct_cf
->cardbus_ctrl
)(cc
, CARDBUS_BM_ENABLE
);
405 /* Enable the appropriate bits in the CARDBUS CSR. */
406 reg
= cardbus_conf_read(cc
, cf
, csc
->sc_tag
,
407 CARDBUS_COMMAND_STATUS_REG
);
409 cardbus_conf_write(cc
, cf
, csc
->sc_tag
, CARDBUS_COMMAND_STATUS_REG
,
415 reg
= cardbus_conf_read(cc
, cf
, csc
->sc_tag
, CARDBUS_BHLC_REG
);
416 if (CARDBUS_LATTIMER(reg
) < 0x20) {
417 /* at least the value of latency timer should 0x20. */
418 DPRINTF(("if_ex_cardbus: lattimer 0x%x -> 0x20\n",
419 CARDBUS_LATTIMER(reg
)));
420 reg
&= ~(CARDBUS_LATTIMER_MASK
<< CARDBUS_LATTIMER_SHIFT
);
421 reg
|= (0x20 << CARDBUS_LATTIMER_SHIFT
);
422 cardbus_conf_write(cc
, cf
, csc
->sc_tag
, CARDBUS_BHLC_REG
, reg
);