blob: 8c16ba672012b7ceb01c1fc07334e487012a2c3b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
2
3 A PCMCIA ethernet driver for SMC91c92-based cards.
4
5 This driver supports Megahertz PCMCIA ethernet cards; and
6 Megahertz, Motorola, Ositech, and Psion Dacom ethernet/modem
7 multifunction cards.
8
9 Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
10
11 smc91c92_cs.c 1.122 2002/10/25 06:26:39
12
13 This driver contains code written by Donald Becker
14 (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au),
15 David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman
16 (erik@vt.edu). Donald wrote the SMC 91c92 code using parts of
17 Erik's SMC 91c94 driver. Rowan wrote a similar driver, and I've
18 incorporated some parts of his driver here. I (Dave) wrote most
19 of the PCMCIA glue code, and the Ositech support code. Kelly
20 Stephens (kstephen@holli.com) added support for the Motorola
21 Mariner, with help from Allen Brost.
22
23 This software may be used and distributed according to the terms of
24 the GNU General Public License, incorporated herein by reference.
25
26======================================================================*/
27
28#include <linux/module.h>
29#include <linux/kernel.h>
30#include <linux/init.h>
31#include <linux/slab.h>
32#include <linux/string.h>
33#include <linux/timer.h>
34#include <linux/interrupt.h>
35#include <linux/delay.h>
36#include <linux/crc32.h>
37#include <linux/netdevice.h>
38#include <linux/etherdevice.h>
39#include <linux/skbuff.h>
40#include <linux/if_arp.h>
41#include <linux/ioport.h>
42#include <linux/ethtool.h>
43#include <linux/mii.h>
Marcelo Feitoza Parisi4851d3a2005-07-15 10:00:41 -070044#include <linux/jiffies.h>
Jaswinder Singh Rajput75bf7582009-03-30 20:19:54 +053045#include <linux/firmware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <pcmcia/cistpl.h>
48#include <pcmcia/cisreg.h>
49#include <pcmcia/ciscode.h>
50#include <pcmcia/ds.h>
Dominik Brodowski50db3fd2006-01-15 10:05:19 +010051#include <pcmcia/ss.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#include <asm/io.h>
54#include <asm/system.h>
55#include <asm/uaccess.h>
56
Linus Torvalds1da177e2005-04-16 15:20:36 -070057/*====================================================================*/
58
Arjan van de Venf71e1302006-03-03 21:33:57 -050059static const char *if_names[] = { "auto", "10baseT", "10base2"};
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Jaswinder Singh Rajput75bf7582009-03-30 20:19:54 +053061/* Firmware name */
62#define FIRMWARE_NAME "ositech/Xilinx7OD.bin"
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064/* Module parameters */
65
66MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver");
67MODULE_LICENSE("GPL");
Jaswinder Singh Rajput75bf7582009-03-30 20:19:54 +053068MODULE_FIRMWARE(FIRMWARE_NAME);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
71
72/*
73 Transceiver/media type.
74 0 = auto
75 1 = 10baseT (and autoselect if #define AUTOSELECT),
76 2 = AUI/10base2,
77*/
78INT_MODULE_PARM(if_port, 0);
79
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
81#define DRV_NAME "smc91c92_cs"
Andy Gospodarekd5b20692006-09-11 17:39:18 -040082#define DRV_VERSION "1.123"
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84/*====================================================================*/
85
86/* Operational parameter that usually are not changed. */
87
88/* Time in jiffies before concluding Tx hung */
89#define TX_TIMEOUT ((400*HZ)/1000)
90
91/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
92#define INTR_WORK 4
93
94/* Times to check the check the chip before concluding that it doesn't
95 currently have room for another Tx packet. */
96#define MEMORY_WAIT_TIME 8
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098struct smc_private {
Dominik Brodowskifd238232006-03-05 10:45:09 +010099 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 spinlock_t lock;
101 u_short manfid;
102 u_short cardid;
Stephen Hemminger6fb72982009-03-20 19:36:09 +0000103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 struct sk_buff *saved_skb;
105 int packets_waiting;
106 void __iomem *base;
107 u_short cfg;
108 struct timer_list media;
109 int watchdog, tx_err;
110 u_short media_status;
111 u_short fast_poll;
112 u_short link_status;
113 struct mii_if_info mii_if;
114 int duplex;
115 int rx_ovrn;
116};
117
118/* Special definitions for Megahertz multifunction cards */
119#define MEGAHERTZ_ISR 0x0380
120
121/* Special function registers for Motorola Mariner */
122#define MOT_LAN 0x0000
123#define MOT_UART 0x0020
124#define MOT_EEPROM 0x20
125
126#define MOT_NORMAL \
127(COR_LEVEL_REQ | COR_FUNC_ENA | COR_ADDR_DECODE | COR_IREQ_ENA)
128
129/* Special function registers for Ositech cards */
130#define OSITECH_AUI_CTL 0x0c
131#define OSITECH_PWRDOWN 0x0d
132#define OSITECH_RESET 0x0e
133#define OSITECH_ISR 0x0f
134#define OSITECH_AUI_PWR 0x0c
135#define OSITECH_RESET_ISR 0x0e
136
137#define OSI_AUI_PWR 0x40
138#define OSI_LAN_PWRDOWN 0x02
139#define OSI_MODEM_PWRDOWN 0x01
140#define OSI_LAN_RESET 0x02
141#define OSI_MODEM_RESET 0x01
142
143/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */
144#define BANK_SELECT 14 /* Window select register. */
145#define SMC_SELECT_BANK(x) { outw(x, ioaddr + BANK_SELECT); }
146
147/* Bank 0 registers. */
148#define TCR 0 /* transmit control register */
149#define TCR_CLEAR 0 /* do NOTHING */
150#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */
151#define TCR_PAD_EN 0x0080 /* pads short packets to 64 bytes */
152#define TCR_MONCSN 0x0400 /* Monitor Carrier. */
153#define TCR_FDUPLX 0x0800 /* Full duplex mode. */
154#define TCR_NORMAL TCR_ENABLE | TCR_PAD_EN
155
156#define EPH 2 /* Ethernet Protocol Handler report. */
157#define EPH_TX_SUC 0x0001
158#define EPH_SNGLCOL 0x0002
159#define EPH_MULCOL 0x0004
160#define EPH_LTX_MULT 0x0008
161#define EPH_16COL 0x0010
162#define EPH_SQET 0x0020
163#define EPH_LTX_BRD 0x0040
164#define EPH_TX_DEFR 0x0080
165#define EPH_LAT_COL 0x0200
166#define EPH_LOST_CAR 0x0400
167#define EPH_EXC_DEF 0x0800
168#define EPH_CTR_ROL 0x1000
169#define EPH_RX_OVRN 0x2000
170#define EPH_LINK_OK 0x4000
171#define EPH_TX_UNRN 0x8000
172#define MEMINFO 8 /* Memory Information Register */
173#define MEMCFG 10 /* Memory Configuration Register */
174
175/* Bank 1 registers. */
176#define CONFIG 0
177#define CFG_MII_SELECT 0x8000 /* 91C100 only */
178#define CFG_NO_WAIT 0x1000
179#define CFG_FULL_STEP 0x0400
180#define CFG_SET_SQLCH 0x0200
181#define CFG_AUI_SELECT 0x0100
182#define CFG_16BIT 0x0080
183#define CFG_DIS_LINK 0x0040
184#define CFG_STATIC 0x0030
185#define CFG_IRQ_SEL_1 0x0004
186#define CFG_IRQ_SEL_0 0x0002
187#define BASE_ADDR 2
188#define ADDR0 4
189#define GENERAL 10
190#define CONTROL 12
191#define CTL_STORE 0x0001
192#define CTL_RELOAD 0x0002
193#define CTL_EE_SELECT 0x0004
194#define CTL_TE_ENABLE 0x0020
195#define CTL_CR_ENABLE 0x0040
196#define CTL_LE_ENABLE 0x0080
197#define CTL_AUTO_RELEASE 0x0800
198#define CTL_POWERDOWN 0x2000
199
200/* Bank 2 registers. */
201#define MMU_CMD 0
202#define MC_ALLOC 0x20 /* or with number of 256 byte packets */
203#define MC_RESET 0x40
204#define MC_RELEASE 0x80 /* remove and release the current rx packet */
205#define MC_FREEPKT 0xA0 /* Release packet in PNR register */
206#define MC_ENQUEUE 0xC0 /* Enqueue the packet for transmit */
207#define PNR_ARR 2
208#define FIFO_PORTS 4
209#define FP_RXEMPTY 0x8000
210#define POINTER 6
211#define PTR_AUTO_INC 0x0040
212#define PTR_READ 0x2000
213#define PTR_AUTOINC 0x4000
214#define PTR_RCV 0x8000
215#define DATA_1 8
216#define INTERRUPT 12
217#define IM_RCV_INT 0x1
218#define IM_TX_INT 0x2
219#define IM_TX_EMPTY_INT 0x4
220#define IM_ALLOC_INT 0x8
221#define IM_RX_OVRN_INT 0x10
222#define IM_EPH_INT 0x20
223
224#define RCR 4
225enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002,
226 RxEnable = 0x0100, RxStripCRC = 0x0200};
227#define RCR_SOFTRESET 0x8000 /* resets the chip */
228#define RCR_STRIP_CRC 0x200 /* strips CRC */
229#define RCR_ENABLE 0x100 /* IFF this is set, we can receive packets */
230#define RCR_ALMUL 0x4 /* receive all multicast packets */
231#define RCR_PROMISC 0x2 /* enable promiscuous mode */
232
233/* the normal settings for the RCR register : */
234#define RCR_NORMAL (RCR_STRIP_CRC | RCR_ENABLE)
235#define RCR_CLEAR 0x0 /* set it to a base state */
236#define COUNTER 6
237
238/* BANK 3 -- not the same values as in smc9194! */
239#define MULTICAST0 0
240#define MULTICAST2 2
241#define MULTICAST4 4
242#define MULTICAST6 6
243#define MGMT 8
244#define REVISION 0x0a
245
246/* Transmit status bits. */
247#define TS_SUCCESS 0x0001
248#define TS_16COL 0x0010
249#define TS_LATCOL 0x0200
250#define TS_LOSTCAR 0x0400
251
252/* Receive status bits. */
253#define RS_ALGNERR 0x8000
254#define RS_BADCRC 0x2000
255#define RS_ODDFRAME 0x1000
256#define RS_TOOLONG 0x0800
257#define RS_TOOSHORT 0x0400
258#define RS_MULTICAST 0x0001
259#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
260
261#define set_bits(v, p) outw(inw(p)|(v), (p))
262#define mask_bits(v, p) outw(inw(p)&(v), (p))
263
264/*====================================================================*/
265
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100266static void smc91c92_detach(struct pcmcia_device *p_dev);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200267static int smc91c92_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200268static void smc91c92_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
270static int smc_open(struct net_device *dev);
271static int smc_close(struct net_device *dev);
272static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
273static void smc_tx_timeout(struct net_device *dev);
Stephen Hemmingerdbf02fa2009-08-31 19:50:49 +0000274static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
275 struct net_device *dev);
David Howells7d12e782006-10-05 14:55:46 +0100276static irqreturn_t smc_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277static void smc_rx(struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278static void set_rx_mode(struct net_device *dev);
279static int s9k_config(struct net_device *dev, struct ifmap *map);
280static void smc_set_xcvr(struct net_device *dev, int if_port);
281static void smc_reset(struct net_device *dev);
282static void media_check(u_long arg);
Olof Johansson906da802008-02-04 22:27:35 -0800283static void mdio_sync(unsigned int addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284static int mdio_read(struct net_device *dev, int phy_id, int loc);
285static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
286static int smc_link_ok(struct net_device *dev);
Jeff Garzik7282d492006-09-13 14:30:00 -0400287static const struct ethtool_ops ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Stephen Hemminger9b31b692009-03-20 19:36:10 +0000289static const struct net_device_ops smc_netdev_ops = {
290 .ndo_open = smc_open,
291 .ndo_stop = smc_close,
292 .ndo_start_xmit = smc_start_xmit,
293 .ndo_tx_timeout = smc_tx_timeout,
294 .ndo_set_config = s9k_config,
295 .ndo_set_multicast_list = set_rx_mode,
296 .ndo_do_ioctl = &smc_ioctl,
297 .ndo_change_mtu = eth_change_mtu,
298 .ndo_set_mac_address = eth_mac_addr,
299 .ndo_validate_addr = eth_validate_addr,
300};
301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302/*======================================================================
303
304 smc91c92_attach() creates an "instance" of the driver, allocating
305 local data structures for one device. The device is registered
306 with Card Services.
307
308======================================================================*/
309
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200310static int smc91c92_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 struct smc_private *smc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200315 dev_dbg(&link->dev, "smc91c92_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317 /* Create new ethernet device */
318 dev = alloc_etherdev(sizeof(struct smc_private));
319 if (!dev)
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100320 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 smc = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200322 smc->p_dev = link;
Dominik Brodowski44b496f2010-06-11 04:44:55 +0000323 link->priv = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 spin_lock_init(&smc->lock);
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200326 link->resource[0]->end = 16;
327 link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200328 link->config_flags |= CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 /* The SMC91c92-specific entries in the device structure. */
Stephen Hemminger9b31b692009-03-20 19:36:10 +0000331 dev->netdev_ops = &smc_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 SET_ETHTOOL_OPS(dev, &ethtool_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 dev->watchdog_timeo = TX_TIMEOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
335 smc->mii_if.dev = dev;
336 smc->mii_if.mdio_read = mdio_read;
337 smc->mii_if.mdio_write = mdio_write;
338 smc->mii_if.phy_id_mask = 0x1f;
339 smc->mii_if.reg_num_mask = 0x1f;
340
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200341 return smc91c92_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342} /* smc91c92_attach */
343
344/*======================================================================
345
346 This deletes a driver "instance". The device is de-registered
347 with Card Services. If it has been released, all local data
348 structures are freed. Otherwise, the structures will be freed
349 when the device is released.
350
351======================================================================*/
352
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200353static void smc91c92_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
355 struct net_device *dev = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200357 dev_dbg(&link->dev, "smc91c92_detach\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100359 unregister_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100361 smc91c92_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 free_netdev(dev);
364} /* smc91c92_detach */
365
366/*====================================================================*/
367
368static int cvt_ascii_address(struct net_device *dev, char *s)
369{
370 int i, j, da, c;
371
372 if (strlen(s) != 12)
373 return -1;
374 for (i = 0; i < 6; i++) {
375 da = 0;
376 for (j = 0; j < 2; j++) {
377 c = *s++;
378 da <<= 4;
379 da += ((c >= '0') && (c <= '9')) ?
380 (c - '0') : ((c & 0x0f) + 9);
381 }
382 dev->dev_addr[i] = da;
383 }
384 return 0;
385}
386
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200387/*====================================================================
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
389 Configuration stuff for Megahertz cards
390
391 mhz_3288_power() is used to power up a 3288's ethernet chip.
392 mhz_mfc_config() handles socket setup for multifunction (1144
393 and 3288) cards. mhz_setup() gets a card's hardware ethernet
394 address.
395
396======================================================================*/
397
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200398static int mhz_3288_power(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399{
400 struct net_device *dev = link->priv;
401 struct smc_private *smc = netdev_priv(dev);
402 u_char tmp;
403
404 /* Read the ISR twice... */
405 readb(smc->base+MEGAHERTZ_ISR);
406 udelay(5);
407 readb(smc->base+MEGAHERTZ_ISR);
408
409 /* Pause 200ms... */
410 mdelay(200);
411
412 /* Now read and write the COR... */
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200413 tmp = readb(smc->base + link->config_base + CISREG_COR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 udelay(5);
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200415 writeb(tmp, smc->base + link->config_base + CISREG_COR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
417 return 0;
418}
419
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200420static int mhz_mfc_config_check(struct pcmcia_device *p_dev,
421 cistpl_cftable_entry_t *cf,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200422 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200423 unsigned int vcc,
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200424 void *priv_data)
425{
426 int k;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200427 p_dev->resource[1]->start = cf->io.win[0].base;
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200428 for (k = 0; k < 0x400; k += 0x10) {
429 if (k & 0x80)
430 continue;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200431 p_dev->resource[0]->start = k ^ 0x300;
432 p_dev->io_lines = 16;
433 if (!pcmcia_request_io(p_dev))
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200434 return 0;
435 }
436 return -ENODEV;
437}
438
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200439static int mhz_mfc_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
441 struct net_device *dev = link->priv;
442 struct smc_private *smc = netdev_priv(dev);
Dominik Brodowskib5cb2592010-07-24 18:46:42 +0200443 unsigned int offset;
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200444 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200446 link->config_flags |= CONF_ENABLE_SPKR;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200447 link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
448 link->resource[1]->end = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 /* The Megahertz combo cards have modem-like CIS entries, so
451 we have to explicitly try a bunch of port combinations. */
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200452 if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL))
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200453 return -ENODEV;
454
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200455 dev->base_addr = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
457 /* Allocate a memory window, for accessing the ISR */
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200458 link->resource[2]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
459 link->resource[2]->start = link->resource[2]->end = 0;
460 i = pcmcia_request_window(link, link->resource[2], 0);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200461 if (i != 0)
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200462 return -ENODEV;
463
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200464 smc->base = ioremap(link->resource[2]->start,
465 resource_size(link->resource[2]));
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200466 offset = (smc->manfid == MANFID_MOTOROLA) ? link->config_base : 0;
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200467 i = pcmcia_map_mem_page(link, link->resource[2], offset);
Joe Perches8e95a202009-12-03 07:58:21 +0000468 if ((i == 0) &&
469 (smc->manfid == MANFID_MEGAHERTZ) &&
470 (smc->cardid == PRODID_MEGAHERTZ_EM3288))
471 mhz_3288_power(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200473 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474}
475
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200476static int pcmcia_get_versmac(struct pcmcia_device *p_dev,
477 tuple_t *tuple,
478 void *priv)
479{
480 struct net_device *dev = priv;
481 cisparse_t parse;
Ken Kawasakifb9e2d82010-04-03 15:07:10 -0700482 u8 *buf;
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200483
484 if (pcmcia_parse_tuple(tuple, &parse))
485 return -EINVAL;
486
Ken Kawasakifb9e2d82010-04-03 15:07:10 -0700487 buf = parse.version_1.str + parse.version_1.ofs[3];
488
489 if ((parse.version_1.ns > 3) && (cvt_ascii_address(dev, buf) == 0))
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200490 return 0;
491
492 return -EINVAL;
493};
494
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200495static int mhz_setup(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 struct net_device *dev = link->priv;
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200498 size_t len;
499 u8 *buf;
Yum Rayan4638aef42005-05-05 15:14:10 -0700500 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 /* Read the station address from the CIS. It is stored as the last
503 (fourth) string in the Version 1 Version/ID tuple. */
Dominik Brodowski7d2e8d02009-10-18 18:22:32 +0200504 if ((link->prod_id[3]) &&
505 (cvt_ascii_address(dev, link->prod_id[3]) == 0))
506 return 0;
507
508 /* Workarounds for broken cards start here. */
Chuck Ebberta1a98b72008-02-13 19:47:11 -0500509 /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200510 if (!pcmcia_loop_tuple(link, CISTPL_VERS_1, pcmcia_get_versmac, dev))
511 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 /* Another possibility: for the EM3288, in a special tuple */
Yum Rayan4638aef42005-05-05 15:14:10 -0700514 rc = -1;
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200515 len = pcmcia_get_tuple(link, 0x81, &buf);
516 if (buf && len >= 13) {
517 buf[12] = '\0';
Ken Kawasakifb9e2d82010-04-03 15:07:10 -0700518 if (cvt_ascii_address(dev, buf) == 0)
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200519 rc = 0;
520 }
521 kfree(buf);
522
523 return rc;
524};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
526/*======================================================================
527
528 Configuration stuff for the Motorola Mariner
529
530 mot_config() writes directly to the Mariner configuration
531 registers because the CIS is just bogus.
532
533======================================================================*/
534
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200535static void mot_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
537 struct net_device *dev = link->priv;
538 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800539 unsigned int ioaddr = dev->base_addr;
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200540 unsigned int iouart = link->resource[1]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
542 /* Set UART base address and force map with COR bit 1 */
543 writeb(iouart & 0xff, smc->base + MOT_UART + CISREG_IOBASE_0);
544 writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1);
545 writeb(MOT_NORMAL, smc->base + MOT_UART + CISREG_COR);
546
547 /* Set SMC base address and force map with COR bit 1 */
548 writeb(ioaddr & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_0);
549 writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1);
550 writeb(MOT_NORMAL, smc->base + MOT_LAN + CISREG_COR);
551
552 /* Wait for things to settle down */
553 mdelay(100);
554}
555
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200556static int mot_setup(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557{
558 struct net_device *dev = link->priv;
Olof Johansson906da802008-02-04 22:27:35 -0800559 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 int i, wait, loop;
561 u_int addr;
562
563 /* Read Ethernet address from Serial EEPROM */
564
565 for (i = 0; i < 3; i++) {
566 SMC_SELECT_BANK(2);
567 outw(MOT_EEPROM + i, ioaddr + POINTER);
568 SMC_SELECT_BANK(1);
569 outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL);
570
571 for (loop = wait = 0; loop < 200; loop++) {
572 udelay(10);
573 wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL));
574 if (wait == 0) break;
575 }
576
577 if (wait)
578 return -1;
579
580 addr = inw(ioaddr + GENERAL);
581 dev->dev_addr[2*i] = addr & 0xff;
582 dev->dev_addr[2*i+1] = (addr >> 8) & 0xff;
583 }
584
585 return 0;
586}
587
588/*====================================================================*/
589
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200590static int smc_configcheck(struct pcmcia_device *p_dev,
591 cistpl_cftable_entry_t *cf,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200592 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200593 unsigned int vcc,
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200594 void *priv_data)
595{
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200596 p_dev->resource[0]->start = cf->io.win[0].base;
597 p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
598 return pcmcia_request_io(p_dev);
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200599}
600
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200601static int smc_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602{
603 struct net_device *dev = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 int i;
605
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200606 link->resource[0]->end = 16;
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200607 i = pcmcia_loop_config(link, smc_configcheck, NULL);
608 if (!i)
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200609 dev->base_addr = link->resource[0]->start;
Yum Rayan4638aef42005-05-05 15:14:10 -0700610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 return i;
612}
613
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200614
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200615static int smc_setup(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 struct net_device *dev = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 /* Check for a LAN function extension tuple */
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200620 if (!pcmcia_get_mac_from_cis(link, dev))
621 return 0;
622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 /* Try the third string in the Version 1 Version/ID tuple. */
Dominik Brodowskia9606fd2006-06-04 18:06:13 +0200624 if (link->prod_id[2]) {
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200625 if (cvt_ascii_address(dev, link->prod_id[2]) == 0)
626 return 0;
Yum Rayan4638aef42005-05-05 15:14:10 -0700627 }
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200628 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629}
630
631/*====================================================================*/
632
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200633static int osi_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
635 struct net_device *dev = link->priv;
Olof Johansson906da802008-02-04 22:27:35 -0800636 static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 int i, j;
638
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200639 link->config_flags |= CONF_ENABLE_SPKR;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200640 link->resource[0]->end = 64;
641 link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
642 link->resource[1]->end = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
644 /* Enable Hard Decode, LAN, Modem */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200645 link->io_lines = 16;
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200646 link->config_index = 0x23;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 for (i = j = 0; j < 4; j++) {
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200649 link->resource[1]->start = com[j];
650 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200651 if (i == 0)
652 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200654 if (i != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 /* Fallback: turn off hard decode */
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200656 link->config_index = 0x03;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200657 link->resource[1]->end = 0;
658 i = pcmcia_request_io(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200660 dev->base_addr = link->resource[0]->start + 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 return i;
662}
663
Jaswinder Singh Rajput75bf7582009-03-30 20:19:54 +0530664static int osi_load_firmware(struct pcmcia_device *link)
665{
666 const struct firmware *fw;
667 int i, err;
668
669 err = request_firmware(&fw, FIRMWARE_NAME, &link->dev);
670 if (err) {
671 pr_err("Failed to load firmware \"%s\"\n", FIRMWARE_NAME);
672 return err;
673 }
674
675 /* Download the Seven of Diamonds firmware */
676 for (i = 0; i < fw->size; i++) {
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200677 outb(fw->data[i], link->resource[0]->start + 2);
Jaswinder Singh Rajput75bf7582009-03-30 20:19:54 +0530678 udelay(50);
679 }
680 release_firmware(fw);
681 return err;
682}
683
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200684static int pcmcia_osi_mac(struct pcmcia_device *p_dev,
685 tuple_t *tuple,
686 void *priv)
687{
688 struct net_device *dev = priv;
689 int i;
690
691 if (tuple->TupleDataLen < 8)
692 return -EINVAL;
693 if (tuple->TupleData[0] != 0x04)
694 return -EINVAL;
695 for (i = 0; i < 6; i++)
696 dev->dev_addr[i] = tuple->TupleData[i+2];
697 return 0;
698};
699
700
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200701static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 struct net_device *dev = link->priv;
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200704 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706 /* Read the station address from tuple 0x90, subtuple 0x04 */
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200707 if (pcmcia_loop_tuple(link, 0x90, pcmcia_osi_mac, dev))
708 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 if (((manfid == MANFID_OSITECH) &&
711 (cardid == PRODID_OSITECH_SEVEN)) ||
712 ((manfid == MANFID_PSION) &&
713 (cardid == PRODID_PSION_NET100))) {
Jaswinder Singh Rajput75bf7582009-03-30 20:19:54 +0530714 rc = osi_load_firmware(link);
715 if (rc)
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200716 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 } else if (manfid == MANFID_OSITECH) {
718 /* Make sure both functions are powered up */
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200719 set_bits(0x300, link->resource[0]->start + OSITECH_AUI_PWR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 /* Now, turn on the interrupt for both card functions */
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200721 set_bits(0x300, link->resource[0]->start + OSITECH_RESET_ISR);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200722 dev_dbg(&link->dev, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n",
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200723 inw(link->resource[0]->start + OSITECH_AUI_PWR),
724 inw(link->resource[0]->start + OSITECH_RESET_ISR));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 }
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200726 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727}
728
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200729static int smc91c92_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100730{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100731 struct net_device *dev = link->priv;
732
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100733 if (link->open)
Dominik Brodowski4bbed522006-01-15 11:18:12 +0100734 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100735
736 return 0;
737}
738
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200739static int smc91c92_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100740{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100741 struct net_device *dev = link->priv;
742 struct smc_private *smc = netdev_priv(dev);
743 int i;
744
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100745 if ((smc->manfid == MANFID_MEGAHERTZ) &&
746 (smc->cardid == PRODID_MEGAHERTZ_EM3288))
747 mhz_3288_power(link);
748 if (smc->manfid == MANFID_MOTOROLA)
749 mot_config(link);
750 if ((smc->manfid == MANFID_OSITECH) &&
751 (smc->cardid != PRODID_OSITECH_SEVEN)) {
752 /* Power up the card and enable interrupts */
753 set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
754 set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
755 }
756 if (((smc->manfid == MANFID_OSITECH) &&
757 (smc->cardid == PRODID_OSITECH_SEVEN)) ||
758 ((smc->manfid == MANFID_PSION) &&
759 (smc->cardid == PRODID_PSION_NET100))) {
Jaswinder Singh Rajput75bf7582009-03-30 20:19:54 +0530760 i = osi_load_firmware(link);
761 if (i) {
762 pr_err("smc91c92_cs: Failed to load firmware\n");
763 return i;
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100764 }
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100765 }
766 if (link->open) {
767 smc_reset(dev);
768 netif_device_attach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100769 }
770
771 return 0;
772}
773
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775/*======================================================================
776
777 This verifies that the chip is some SMC91cXX variant, and returns
778 the revision code if successful. Otherwise, it returns -ENODEV.
779
780======================================================================*/
781
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200782static int check_sig(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783{
784 struct net_device *dev = link->priv;
Olof Johansson906da802008-02-04 22:27:35 -0800785 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 int width;
787 u_short s;
788
789 SMC_SELECT_BANK(1);
790 if (inw(ioaddr + BANK_SELECT) >> 8 != 0x33) {
791 /* Try powering up the chip */
792 outw(0, ioaddr + CONTROL);
793 mdelay(55);
794 }
795
796 /* Try setting bus width */
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200797 width = (link->resource[0]->flags == IO_DATA_PATH_WIDTH_AUTO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 s = inb(ioaddr + CONFIG);
799 if (width)
800 s |= CFG_16BIT;
801 else
802 s &= ~CFG_16BIT;
803 outb(s, ioaddr + CONFIG);
804
805 /* Check Base Address Register to make sure bus width is OK */
806 s = inw(ioaddr + BASE_ADDR);
807 if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) &&
808 ((s >> 8) != (s & 0xff))) {
809 SMC_SELECT_BANK(3);
810 s = inw(ioaddr + REVISION);
811 return (s & 0xff);
812 }
813
814 if (width) {
Dominik Brodowski4bbed522006-01-15 11:18:12 +0100815 printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n");
Dominik Brodowski50db3fd2006-01-15 10:05:19 +0100816
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200817 smc91c92_suspend(link);
Dominik Brodowskifb49fa52010-07-29 14:06:42 +0200818 pcmcia_fixup_iowidth(link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200819 smc91c92_resume(link);
Dominik Brodowski4bbed522006-01-15 11:18:12 +0100820 return check_sig(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 }
822 return -ENODEV;
823}
824
825/*======================================================================
826
827 smc91c92_config() is scheduled to run after a CARD_INSERTION event
828 is received, to configure the PCMCIA socket, and to make the
829 ethernet device available to the system.
830
831======================================================================*/
832
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200833static int smc91c92_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 struct net_device *dev = link->priv;
836 struct smc_private *smc = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 char *name;
838 int i, j, rev;
Olof Johansson906da802008-02-04 22:27:35 -0800839 unsigned int ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 u_long mir;
841
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200842 dev_dbg(&link->dev, "smc91c92_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
Dominik Brodowskiefd50582006-10-25 21:28:53 -0400844 smc->manfid = link->manf_id;
845 smc->cardid = link->card_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if ((smc->manfid == MANFID_OSITECH) &&
848 (smc->cardid != PRODID_OSITECH_SEVEN)) {
849 i = osi_config(link);
850 } else if ((smc->manfid == MANFID_MOTOROLA) ||
851 ((smc->manfid == MANFID_MEGAHERTZ) &&
852 ((smc->cardid == PRODID_MEGAHERTZ_VARIOUS) ||
853 (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) {
854 i = mhz_mfc_config(link);
855 } else {
856 i = smc_config(link);
857 }
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200858 if (i)
859 goto config_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
Dominik Brodowskieb141202010-03-07 12:21:16 +0100861 i = pcmcia_request_irq(link, smc_interrupt);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200862 if (i)
863 goto config_failed;
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200864 i = pcmcia_enable_device(link);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200865 if (i)
866 goto config_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
868 if (smc->manfid == MANFID_MOTOROLA)
869 mot_config(link);
870
Dominik Brodowskieb141202010-03-07 12:21:16 +0100871 dev->irq = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
873 if ((if_port >= 0) && (if_port <= 2))
874 dev->if_port = if_port;
875 else
876 printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
877
878 switch (smc->manfid) {
879 case MANFID_OSITECH:
880 case MANFID_PSION:
881 i = osi_setup(link, smc->manfid, smc->cardid); break;
882 case MANFID_SMC:
883 case MANFID_NEW_MEDIA:
884 i = smc_setup(link); break;
885 case 0x128: /* For broken Megahertz cards */
886 case MANFID_MEGAHERTZ:
887 i = mhz_setup(link); break;
888 case MANFID_MOTOROLA:
889 default: /* get the hw address from EEPROM */
890 i = mot_setup(link); break;
891 }
892
893 if (i != 0) {
894 printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n");
Ken Kawasakifb9e2d82010-04-03 15:07:10 -0700895 goto config_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 }
897
898 smc->duplex = 0;
899 smc->rx_ovrn = 0;
900
901 rev = check_sig(link);
902 name = "???";
903 if (rev > 0)
904 switch (rev >> 4) {
905 case 3: name = "92"; break;
906 case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break;
907 case 5: name = "95"; break;
908 case 7: name = "100"; break;
909 case 8: name = "100-FD"; break;
910 case 9: name = "110"; break;
911 }
912
913 ioaddr = dev->base_addr;
914 if (rev > 0) {
915 u_long mcr;
916 SMC_SELECT_BANK(0);
917 mir = inw(ioaddr + MEMINFO) & 0xff;
918 if (mir == 0xff) mir++;
919 /* Get scale factor for memory size */
920 mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200;
921 mir *= 128 * (1<<((mcr >> 9) & 7));
922 SMC_SELECT_BANK(1);
923 smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT;
924 smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC;
925 if (smc->manfid == MANFID_OSITECH)
926 smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0;
927 if ((rev >> 4) >= 7)
928 smc->cfg |= CFG_MII_SELECT;
929 } else
930 mir = 0;
931
932 if (smc->cfg & CFG_MII_SELECT) {
933 SMC_SELECT_BANK(3);
934
935 for (i = 0; i < 32; i++) {
936 j = mdio_read(dev, i, 1);
937 if ((j != 0) && (j != 0xffff)) break;
938 }
939 smc->mii_if.phy_id = (i < 32) ? i : -1;
940
941 SMC_SELECT_BANK(0);
942 }
943
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100944 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 if (register_netdev(dev) != 0) {
947 printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 goto config_undo;
949 }
950
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
Johannes Berge1749612008-10-27 15:59:26 -0700952 "hw_addr %pM\n",
Joe Perches0795af52007-10-03 17:59:30 -0700953 dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq,
Johannes Berge1749612008-10-27 15:59:26 -0700954 dev->dev_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
956 if (rev > 0) {
957 if (mir & 0x3ff)
958 printk(KERN_INFO " %lu byte", mir);
959 else
960 printk(KERN_INFO " %lu kb", mir>>10);
961 printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ?
962 "MII" : if_names[dev->if_port]);
963 }
964
965 if (smc->cfg & CFG_MII_SELECT) {
966 if (smc->mii_if.phy_id != -1) {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200967 dev_dbg(&link->dev, " MII transceiver at index %d, status %x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 smc->mii_if.phy_id, j);
969 } else {
970 printk(KERN_NOTICE " No MII transceivers found!\n");
971 }
972 }
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200973 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975config_undo:
976 unregister_netdev(dev);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200977config_failed:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 smc91c92_release(link);
Ken Kawasakifb9e2d82010-04-03 15:07:10 -0700979 free_netdev(dev);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200980 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981} /* smc91c92_config */
982
983/*======================================================================
984
985 After a card is removed, smc91c92_release() will unregister the net
986 device, and release the PCMCIA configuration. If the device is
987 still open, this will be postponed until it is closed.
988
989======================================================================*/
990
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200991static void smc91c92_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992{
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200993 dev_dbg(&link->dev, "smc91c92_release\n");
Dominik Brodowskicdb13802010-07-28 10:59:06 +0200994 if (link->resource[2]->end) {
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100995 struct net_device *dev = link->priv;
996 struct smc_private *smc = netdev_priv(dev);
997 iounmap(smc->base);
998 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200999 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000}
1001
1002/*======================================================================
1003
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 MII interface support for SMC91cXX based cards
1005======================================================================*/
1006
1007#define MDIO_SHIFT_CLK 0x04
1008#define MDIO_DATA_OUT 0x01
1009#define MDIO_DIR_WRITE 0x08
1010#define MDIO_DATA_WRITE0 (MDIO_DIR_WRITE)
1011#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT)
1012#define MDIO_DATA_READ 0x02
1013
Olof Johansson906da802008-02-04 22:27:35 -08001014static void mdio_sync(unsigned int addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015{
1016 int bits;
1017 for (bits = 0; bits < 32; bits++) {
1018 outb(MDIO_DATA_WRITE1, addr);
1019 outb(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
1020 }
1021}
1022
1023static int mdio_read(struct net_device *dev, int phy_id, int loc)
1024{
Olof Johansson906da802008-02-04 22:27:35 -08001025 unsigned int addr = dev->base_addr + MGMT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
1027 int i, retval = 0;
1028
1029 mdio_sync(addr);
1030 for (i = 13; i >= 0; i--) {
1031 int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
1032 outb(dat, addr);
1033 outb(dat | MDIO_SHIFT_CLK, addr);
1034 }
1035 for (i = 19; i > 0; i--) {
1036 outb(0, addr);
1037 retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
1038 outb(MDIO_SHIFT_CLK, addr);
1039 }
1040 return (retval>>1) & 0xffff;
1041}
1042
1043static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
1044{
Olof Johansson906da802008-02-04 22:27:35 -08001045 unsigned int addr = dev->base_addr + MGMT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
1047 int i;
1048
1049 mdio_sync(addr);
1050 for (i = 31; i >= 0; i--) {
1051 int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
1052 outb(dat, addr);
1053 outb(dat | MDIO_SHIFT_CLK, addr);
1054 }
1055 for (i = 1; i >= 0; i--) {
1056 outb(0, addr);
1057 outb(MDIO_SHIFT_CLK, addr);
1058 }
1059}
1060
1061/*======================================================================
1062
1063 The driver core code, most of which should be common with a
1064 non-PCMCIA implementation.
1065
1066======================================================================*/
1067
1068#ifdef PCMCIA_DEBUG
1069static void smc_dump(struct net_device *dev)
1070{
Olof Johansson906da802008-02-04 22:27:35 -08001071 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 u_short i, w, save;
1073 save = inw(ioaddr + BANK_SELECT);
1074 for (w = 0; w < 4; w++) {
1075 SMC_SELECT_BANK(w);
1076 printk(KERN_DEBUG "bank %d: ", w);
1077 for (i = 0; i < 14; i += 2)
1078 printk(" %04x", inw(ioaddr + i));
1079 printk("\n");
1080 }
1081 outw(save, ioaddr + BANK_SELECT);
1082}
1083#endif
1084
1085static int smc_open(struct net_device *dev)
1086{
1087 struct smc_private *smc = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001088 struct pcmcia_device *link = smc->p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001090 dev_dbg(&link->dev, "%s: smc_open(%p), ID/Window %4.4x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 dev->name, dev, inw(dev->base_addr + BANK_SELECT));
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001092#ifdef PCMCIA_DEBUG
1093 smc_dump(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094#endif
1095
1096 /* Check that the PCMCIA card is still here. */
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001097 if (!pcmcia_dev_present(link))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 return -ENODEV;
1099 /* Physical device present signature. */
1100 if (check_sig(link) < 0) {
1101 printk("smc91c92_cs: Yikes! Bad chip signature!\n");
1102 return -ENODEV;
1103 }
1104 link->open++;
1105
1106 netif_start_queue(dev);
1107 smc->saved_skb = NULL;
1108 smc->packets_waiting = 0;
1109
1110 smc_reset(dev);
1111 init_timer(&smc->media);
1112 smc->media.function = &media_check;
1113 smc->media.data = (u_long) dev;
1114 smc->media.expires = jiffies + HZ;
1115 add_timer(&smc->media);
1116
1117 return 0;
1118} /* smc_open */
1119
1120/*====================================================================*/
1121
1122static int smc_close(struct net_device *dev)
1123{
1124 struct smc_private *smc = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001125 struct pcmcia_device *link = smc->p_dev;
Olof Johansson906da802008-02-04 22:27:35 -08001126 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001128 dev_dbg(&link->dev, "%s: smc_close(), status %4.4x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 dev->name, inw(ioaddr + BANK_SELECT));
1130
1131 netif_stop_queue(dev);
1132
1133 /* Shut off all interrupts, and turn off the Tx and Rx sections.
1134 Don't bother to check for chip present. */
1135 SMC_SELECT_BANK(2); /* Nominally paranoia, but do no assume... */
1136 outw(0, ioaddr + INTERRUPT);
1137 SMC_SELECT_BANK(0);
1138 mask_bits(0xff00, ioaddr + RCR);
1139 mask_bits(0xff00, ioaddr + TCR);
1140
1141 /* Put the chip into power-down mode. */
1142 SMC_SELECT_BANK(1);
1143 outw(CTL_POWERDOWN, ioaddr + CONTROL );
1144
1145 link->open--;
1146 del_timer_sync(&smc->media);
1147
1148 return 0;
1149} /* smc_close */
1150
1151/*======================================================================
1152
1153 Transfer a packet to the hardware and trigger the packet send.
1154 This may be called at either from either the Tx queue code
1155 or the interrupt handler.
1156
1157======================================================================*/
1158
1159static void smc_hardware_send_packet(struct net_device * dev)
1160{
1161 struct smc_private *smc = netdev_priv(dev);
1162 struct sk_buff *skb = smc->saved_skb;
Olof Johansson906da802008-02-04 22:27:35 -08001163 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 u_char packet_no;
1165
1166 if (!skb) {
1167 printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name);
1168 return;
1169 }
1170
1171 /* There should be a packet slot waiting. */
1172 packet_no = inw(ioaddr + PNR_ARR) >> 8;
1173 if (packet_no & 0x80) {
1174 /* If not, there is a hardware problem! Likely an ejected card. */
1175 printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation"
1176 " failed, status %#2.2x.\n", dev->name, packet_no);
1177 dev_kfree_skb_irq(skb);
1178 smc->saved_skb = NULL;
1179 netif_start_queue(dev);
1180 return;
1181 }
1182
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001183 dev->stats.tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 /* The card should use the just-allocated buffer. */
1185 outw(packet_no, ioaddr + PNR_ARR);
1186 /* point to the beginning of the packet */
1187 outw(PTR_AUTOINC , ioaddr + POINTER);
1188
1189 /* Send the packet length (+6 for status, length and ctl byte)
1190 and the status word (set to zeros). */
1191 {
1192 u_char *buf = skb->data;
1193 u_int length = skb->len; /* The chip will pad to ethernet min. */
1194
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001195 pr_debug("%s: Trying to xmit packet of length %d.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 dev->name, length);
1197
1198 /* send the packet length: +6 for status word, length, and ctl */
1199 outw(0, ioaddr + DATA_1);
1200 outw(length + 6, ioaddr + DATA_1);
1201 outsw(ioaddr + DATA_1, buf, length >> 1);
1202
1203 /* The odd last byte, if there is one, goes in the control word. */
1204 outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);
1205 }
1206
1207 /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */
1208 outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |
1209 (inw(ioaddr + INTERRUPT) & 0xff00),
1210 ioaddr + INTERRUPT);
1211
1212 /* The chip does the rest of the work. */
1213 outw(MC_ENQUEUE , ioaddr + MMU_CMD);
1214
1215 smc->saved_skb = NULL;
1216 dev_kfree_skb_irq(skb);
1217 dev->trans_start = jiffies;
1218 netif_start_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219}
1220
1221/*====================================================================*/
1222
1223static void smc_tx_timeout(struct net_device *dev)
1224{
1225 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001226 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
1228 printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
1229 "Tx_status %2.2x status %4.4x.\n",
1230 dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001231 dev->stats.tx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 smc_reset(dev);
Eric Dumazet1ae5dc32010-05-10 05:01:31 -07001233 dev->trans_start = jiffies; /* prevent tx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 smc->saved_skb = NULL;
1235 netif_wake_queue(dev);
1236}
1237
Stephen Hemmingerdbf02fa2009-08-31 19:50:49 +00001238static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
1239 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240{
1241 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001242 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 u_short num_pages;
1244 short time_out, ir;
Komuro85e27832007-07-23 21:36:06 +09001245 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247 netif_stop_queue(dev);
1248
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001249 pr_debug("%s: smc_start_xmit(length = %d) called,"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
1251
1252 if (smc->saved_skb) {
1253 /* THIS SHOULD NEVER HAPPEN. */
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001254 dev->stats.tx_aborted_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",
1256 dev->name);
Patrick McHardy5b548142009-06-12 06:22:29 +00001257 return NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 }
1259 smc->saved_skb = skb;
1260
1261 num_pages = skb->len >> 8;
1262
1263 if (num_pages > 7) {
1264 printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
1265 dev_kfree_skb (skb);
1266 smc->saved_skb = NULL;
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001267 dev->stats.tx_dropped++;
Patrick McHardy6ed10652009-06-23 06:03:08 +00001268 return NETDEV_TX_OK; /* Do not re-queue this packet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 }
1270 /* A packet is now waiting. */
1271 smc->packets_waiting++;
1272
Komuro85e27832007-07-23 21:36:06 +09001273 spin_lock_irqsave(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 SMC_SELECT_BANK(2); /* Paranoia, we should always be in window 2 */
1275
1276 /* need MC_RESET to keep the memory consistent. errata? */
1277 if (smc->rx_ovrn) {
1278 outw(MC_RESET, ioaddr + MMU_CMD);
1279 smc->rx_ovrn = 0;
1280 }
1281
1282 /* Allocate the memory; send the packet now if we win. */
1283 outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);
1284 for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {
1285 ir = inw(ioaddr+INTERRUPT);
1286 if (ir & IM_ALLOC_INT) {
1287 /* Acknowledge the interrupt, send the packet. */
1288 outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
1289 smc_hardware_send_packet(dev); /* Send the packet now.. */
Komuro85e27832007-07-23 21:36:06 +09001290 spin_unlock_irqrestore(&smc->lock, flags);
Patrick McHardy6ed10652009-06-23 06:03:08 +00001291 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 }
1293 }
1294
1295 /* Otherwise defer until the Tx-space-allocated interrupt. */
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001296 pr_debug("%s: memory allocation deferred.\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
Komuro85e27832007-07-23 21:36:06 +09001298 spin_unlock_irqrestore(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Patrick McHardy6ed10652009-06-23 06:03:08 +00001300 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301}
1302
1303/*======================================================================
1304
1305 Handle a Tx anomolous event. Entered while in Window 2.
1306
1307======================================================================*/
1308
1309static void smc_tx_err(struct net_device * dev)
1310{
1311 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001312 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
1314 int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
1315 int tx_status;
1316
1317 /* select this as the packet to read from */
1318 outw(packet_no, ioaddr + PNR_ARR);
1319
1320 /* read the first word from this packet */
1321 outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);
1322
1323 tx_status = inw(ioaddr + DATA_1);
1324
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001325 dev->stats.tx_errors++;
1326 if (tx_status & TS_LOSTCAR) dev->stats.tx_carrier_errors++;
1327 if (tx_status & TS_LATCOL) dev->stats.tx_window_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 if (tx_status & TS_16COL) {
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001329 dev->stats.tx_aborted_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 smc->tx_err++;
1331 }
1332
1333 if (tx_status & TS_SUCCESS) {
1334 printk(KERN_NOTICE "%s: Successful packet caused error "
1335 "interrupt?\n", dev->name);
1336 }
1337 /* re-enable transmit */
1338 SMC_SELECT_BANK(0);
1339 outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
1340 SMC_SELECT_BANK(2);
1341
1342 outw(MC_FREEPKT, ioaddr + MMU_CMD); /* Free the packet memory. */
1343
1344 /* one less packet waiting for me */
1345 smc->packets_waiting--;
1346
1347 outw(saved_packet, ioaddr + PNR_ARR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348}
1349
1350/*====================================================================*/
1351
1352static void smc_eph_irq(struct net_device *dev)
1353{
1354 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001355 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 u_short card_stats, ephs;
1357
1358 SMC_SELECT_BANK(0);
1359 ephs = inw(ioaddr + EPH);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001360 pr_debug("%s: Ethernet protocol handler interrupt, status"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 " %4.4x.\n", dev->name, ephs);
1362 /* Could be a counter roll-over warning: update stats. */
1363 card_stats = inw(ioaddr + COUNTER);
1364 /* single collisions */
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001365 dev->stats.collisions += card_stats & 0xF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 card_stats >>= 4;
1367 /* multiple collisions */
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001368 dev->stats.collisions += card_stats & 0xF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369#if 0 /* These are for when linux supports these statistics */
1370 card_stats >>= 4; /* deferred */
1371 card_stats >>= 4; /* excess deferred */
1372#endif
1373 /* If we had a transmit error we must re-enable the transmitter. */
1374 outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
1375
1376 /* Clear a link error interrupt. */
1377 SMC_SELECT_BANK(1);
1378 outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL);
1379 outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
1380 ioaddr + CONTROL);
1381 SMC_SELECT_BANK(2);
1382}
1383
1384/*====================================================================*/
1385
David Howells7d12e782006-10-05 14:55:46 +01001386static irqreturn_t smc_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387{
1388 struct net_device *dev = dev_id;
1389 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001390 unsigned int ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 u_short saved_bank, saved_pointer, mask, status;
1392 unsigned int handled = 1;
1393 char bogus_cnt = INTR_WORK; /* Work we are willing to do. */
1394
1395 if (!netif_device_present(dev))
1396 return IRQ_NONE;
1397
1398 ioaddr = dev->base_addr;
1399
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001400 pr_debug("%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 irq, ioaddr);
1402
Komuro85e27832007-07-23 21:36:06 +09001403 spin_lock(&smc->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 smc->watchdog = 0;
1405 saved_bank = inw(ioaddr + BANK_SELECT);
1406 if ((saved_bank & 0xff00) != 0x3300) {
1407 /* The device does not exist -- the card could be off-line, or
1408 maybe it has been ejected. */
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001409 pr_debug("%s: SMC91c92 interrupt %d for non-existent"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 "/ejected device.\n", dev->name, irq);
1411 handled = 0;
1412 goto irq_done;
1413 }
1414
1415 SMC_SELECT_BANK(2);
1416 saved_pointer = inw(ioaddr + POINTER);
1417 mask = inw(ioaddr + INTERRUPT) >> 8;
1418 /* clear all interrupts */
1419 outw(0, ioaddr + INTERRUPT);
1420
1421 do { /* read the status flag, and mask it */
1422 status = inw(ioaddr + INTERRUPT) & 0xff;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001423 pr_debug("%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 status, mask);
1425 if ((status & mask) == 0) {
1426 if (bogus_cnt == INTR_WORK)
1427 handled = 0;
1428 break;
1429 }
1430 if (status & IM_RCV_INT) {
1431 /* Got a packet(s). */
1432 smc_rx(dev);
1433 }
1434 if (status & IM_TX_INT) {
1435 smc_tx_err(dev);
1436 outw(IM_TX_INT, ioaddr + INTERRUPT);
1437 }
1438 status &= mask;
1439 if (status & IM_TX_EMPTY_INT) {
1440 outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT);
1441 mask &= ~IM_TX_EMPTY_INT;
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001442 dev->stats.tx_packets += smc->packets_waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 smc->packets_waiting = 0;
1444 }
1445 if (status & IM_ALLOC_INT) {
1446 /* Clear this interrupt so it doesn't happen again */
1447 mask &= ~IM_ALLOC_INT;
1448
1449 smc_hardware_send_packet(dev);
1450
1451 /* enable xmit interrupts based on this */
1452 mask |= (IM_TX_EMPTY_INT | IM_TX_INT);
1453
1454 /* and let the card send more packets to me */
1455 netif_wake_queue(dev);
1456 }
1457 if (status & IM_RX_OVRN_INT) {
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001458 dev->stats.rx_errors++;
1459 dev->stats.rx_fifo_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 if (smc->duplex)
1461 smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */
1462 outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
1463 }
1464 if (status & IM_EPH_INT)
1465 smc_eph_irq(dev);
1466 } while (--bogus_cnt);
1467
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001468 pr_debug(" Restoring saved registers mask %2.2x bank %4.4x"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 " pointer %4.4x.\n", mask, saved_bank, saved_pointer);
1470
1471 /* restore state register */
1472 outw((mask<<8), ioaddr + INTERRUPT);
1473 outw(saved_pointer, ioaddr + POINTER);
1474 SMC_SELECT_BANK(saved_bank);
1475
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001476 pr_debug("%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
1478irq_done:
1479
1480 if ((smc->manfid == MANFID_OSITECH) &&
1481 (smc->cardid != PRODID_OSITECH_SEVEN)) {
1482 /* Retrigger interrupt if needed */
1483 mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR);
1484 set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR);
1485 }
1486 if (smc->manfid == MANFID_MOTOROLA) {
1487 u_char cor;
1488 cor = readb(smc->base + MOT_UART + CISREG_COR);
1489 writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR);
1490 writeb(cor, smc->base + MOT_UART + CISREG_COR);
1491 cor = readb(smc->base + MOT_LAN + CISREG_COR);
1492 writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR);
1493 writeb(cor, smc->base + MOT_LAN + CISREG_COR);
1494 }
Ken Kawasaki9735b7e2010-06-19 15:24:27 +00001495
1496 if ((smc->base != NULL) && /* Megahertz MFC's */
1497 (smc->manfid == MANFID_MEGAHERTZ) &&
1498 (smc->cardid == PRODID_MEGAHERTZ_EM3288)) {
1499
1500 u_char tmp;
1501 tmp = readb(smc->base+MEGAHERTZ_ISR);
1502 tmp = readb(smc->base+MEGAHERTZ_ISR);
1503
1504 /* Retrigger interrupt if needed */
1505 writeb(tmp, smc->base + MEGAHERTZ_ISR);
1506 writeb(tmp, smc->base + MEGAHERTZ_ISR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 }
Ken Kawasaki9735b7e2010-06-19 15:24:27 +00001508
Komuro85e27832007-07-23 21:36:06 +09001509 spin_unlock(&smc->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 return IRQ_RETVAL(handled);
1511}
1512
1513/*====================================================================*/
1514
1515static void smc_rx(struct net_device *dev)
1516{
Olof Johansson906da802008-02-04 22:27:35 -08001517 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 int rx_status;
1519 int packet_length; /* Caution: not frame length, rather words
1520 to transfer from the chip. */
1521
1522 /* Assertion: we are in Window 2. */
1523
1524 if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
1525 printk(KERN_ERR "%s: smc_rx() with nothing on Rx FIFO.\n",
1526 dev->name);
1527 return;
1528 }
1529
1530 /* Reset the read pointer, and read the status and packet length. */
1531 outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER);
1532 rx_status = inw(ioaddr + DATA_1);
1533 packet_length = inw(ioaddr + DATA_1) & 0x07ff;
1534
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001535 pr_debug("%s: Receive status %4.4x length %d.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 dev->name, rx_status, packet_length);
1537
1538 if (!(rx_status & RS_ERRORS)) {
1539 /* do stuff to make a new packet */
1540 struct sk_buff *skb;
1541
1542 /* Note: packet_length adds 5 or 6 extra bytes here! */
1543 skb = dev_alloc_skb(packet_length+2);
1544
1545 if (skb == NULL) {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001546 pr_debug("%s: Low memory, packet dropped.\n", dev->name);
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001547 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 outw(MC_RELEASE, ioaddr + MMU_CMD);
1549 return;
1550 }
1551
1552 packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6);
1553 skb_reserve(skb, 2);
1554 insw(ioaddr+DATA_1, skb_put(skb, packet_length),
1555 (packet_length+1)>>1);
1556 skb->protocol = eth_type_trans(skb, dev);
1557
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 netif_rx(skb);
1559 dev->last_rx = jiffies;
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001560 dev->stats.rx_packets++;
1561 dev->stats.rx_bytes += packet_length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 if (rx_status & RS_MULTICAST)
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001563 dev->stats.multicast++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 } else {
1565 /* error ... */
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001566 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001568 if (rx_status & RS_ALGNERR) dev->stats.rx_frame_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 if (rx_status & (RS_TOOSHORT | RS_TOOLONG))
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001570 dev->stats.rx_length_errors++;
1571 if (rx_status & RS_BADCRC) dev->stats.rx_crc_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 }
1573 /* Let the MMU free the memory of this packet. */
1574 outw(MC_RELEASE, ioaddr + MMU_CMD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575}
1576
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577/*======================================================================
1578
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 Set the receive mode.
1580
1581 This routine is used by both the protocol level to notify us of
1582 promiscuous/multicast mode changes, and by the open/reset code to
1583 initialize the Rx registers. We always set the multicast list and
1584 leave the receiver running.
1585
1586======================================================================*/
1587
1588static void set_rx_mode(struct net_device *dev)
1589{
Olof Johansson906da802008-02-04 22:27:35 -08001590 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 struct smc_private *smc = netdev_priv(dev);
Ken Kawasakia6d37022010-04-10 12:50:14 +00001592 unsigned char multicast_table[8];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 unsigned long flags;
1594 u_short rx_cfg_setting;
Ken Kawasakia6d37022010-04-10 12:50:14 +00001595 int i;
1596
1597 memset(multicast_table, 0, sizeof(multicast_table));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598
1599 if (dev->flags & IFF_PROMISC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
1601 } else if (dev->flags & IFF_ALLMULTI)
1602 rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
1603 else {
Jiri Pirko4cd24ea2010-02-08 04:30:35 +00001604 if (!netdev_mc_empty(dev)) {
Jiri Pirko22bedad32010-04-01 21:22:57 +00001605 struct netdev_hw_addr *ha;
Jiri Pirko91fea582010-02-19 08:48:47 +00001606
Jiri Pirko22bedad32010-04-01 21:22:57 +00001607 netdev_for_each_mc_addr(ha, dev) {
1608 u_int position = ether_crc(6, ha->addr);
Jiri Pirko91fea582010-02-19 08:48:47 +00001609 multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
1610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 }
1612 rx_cfg_setting = RxStripCRC | RxEnable;
1613 }
1614
1615 /* Load MC table and Rx setting into the chip without interrupts. */
1616 spin_lock_irqsave(&smc->lock, flags);
1617 SMC_SELECT_BANK(3);
Ken Kawasakia6d37022010-04-10 12:50:14 +00001618 for (i = 0; i < 8; i++)
1619 outb(multicast_table[i], ioaddr + MULTICAST0 + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 SMC_SELECT_BANK(0);
1621 outw(rx_cfg_setting, ioaddr + RCR);
1622 SMC_SELECT_BANK(2);
1623 spin_unlock_irqrestore(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624}
1625
1626/*======================================================================
1627
1628 Senses when a card's config changes. Here, it's coax or TP.
1629
1630======================================================================*/
1631
1632static int s9k_config(struct net_device *dev, struct ifmap *map)
1633{
1634 struct smc_private *smc = netdev_priv(dev);
1635 if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
1636 if (smc->cfg & CFG_MII_SELECT)
1637 return -EOPNOTSUPP;
1638 else if (map->port > 2)
1639 return -EINVAL;
1640 dev->if_port = map->port;
1641 printk(KERN_INFO "%s: switched to %s port\n",
1642 dev->name, if_names[dev->if_port]);
1643 smc_reset(dev);
1644 }
1645 return 0;
1646}
1647
1648/*======================================================================
1649
1650 Reset the chip, reloading every register that might be corrupted.
1651
1652======================================================================*/
1653
1654/*
1655 Set transceiver type, perhaps to something other than what the user
1656 specified in dev->if_port.
1657*/
1658static void smc_set_xcvr(struct net_device *dev, int if_port)
1659{
1660 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001661 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 u_short saved_bank;
1663
1664 saved_bank = inw(ioaddr + BANK_SELECT);
1665 SMC_SELECT_BANK(1);
1666 if (if_port == 2) {
1667 outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG);
1668 if ((smc->manfid == MANFID_OSITECH) &&
1669 (smc->cardid != PRODID_OSITECH_SEVEN))
1670 set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
1671 smc->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002);
1672 } else {
1673 outw(smc->cfg, ioaddr + CONFIG);
1674 if ((smc->manfid == MANFID_OSITECH) &&
1675 (smc->cardid != PRODID_OSITECH_SEVEN))
1676 mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
1677 smc->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001);
1678 }
1679 SMC_SELECT_BANK(saved_bank);
1680}
1681
1682static void smc_reset(struct net_device *dev)
1683{
Olof Johansson906da802008-02-04 22:27:35 -08001684 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 struct smc_private *smc = netdev_priv(dev);
1686 int i;
1687
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001688 pr_debug("%s: smc91c92 reset called.\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
1690 /* The first interaction must be a write to bring the chip out
1691 of sleep mode. */
1692 SMC_SELECT_BANK(0);
1693 /* Reset the chip. */
1694 outw(RCR_SOFTRESET, ioaddr + RCR);
1695 udelay(10);
1696
1697 /* Clear the transmit and receive configuration registers. */
1698 outw(RCR_CLEAR, ioaddr + RCR);
1699 outw(TCR_CLEAR, ioaddr + TCR);
1700
1701 /* Set the Window 1 control, configuration and station addr registers.
1702 No point in writing the I/O base register ;-> */
1703 SMC_SELECT_BANK(1);
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001704 /* Automatically release successfully transmitted packets,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 Accept link errors, counter and Tx error interrupts. */
1706 outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
1707 ioaddr + CONTROL);
1708 smc_set_xcvr(dev, dev->if_port);
1709 if ((smc->manfid == MANFID_OSITECH) &&
1710 (smc->cardid != PRODID_OSITECH_SEVEN))
1711 outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |
1712 (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),
1713 ioaddr - 0x10 + OSITECH_AUI_PWR);
1714
1715 /* Fill in the physical address. The databook is wrong about the order! */
1716 for (i = 0; i < 6; i += 2)
1717 outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i],
1718 ioaddr + ADDR0 + i);
1719
1720 /* Reset the MMU */
1721 SMC_SELECT_BANK(2);
1722 outw(MC_RESET, ioaddr + MMU_CMD);
1723 outw(0, ioaddr + INTERRUPT);
1724
1725 /* Re-enable the chip. */
1726 SMC_SELECT_BANK(0);
1727 outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
1728 TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR);
1729 set_rx_mode(dev);
1730
1731 if (smc->cfg & CFG_MII_SELECT) {
1732 SMC_SELECT_BANK(3);
1733
1734 /* Reset MII */
1735 mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
1736
1737 /* Advertise 100F, 100H, 10F, 10H */
1738 mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1);
1739
1740 /* Restart MII autonegotiation */
1741 mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
1742 mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
1743 }
1744
1745 /* Enable interrupts. */
1746 SMC_SELECT_BANK(2);
1747 outw((IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8,
1748 ioaddr + INTERRUPT);
1749}
1750
1751/*======================================================================
1752
1753 Media selection timer routine
1754
1755======================================================================*/
1756
1757static void media_check(u_long arg)
1758{
1759 struct net_device *dev = (struct net_device *) arg;
1760 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001761 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 u_short i, media, saved_bank;
1763 u_short link;
Komuro85e27832007-07-23 21:36:06 +09001764 unsigned long flags;
1765
1766 spin_lock_irqsave(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
1768 saved_bank = inw(ioaddr + BANK_SELECT);
1769
1770 if (!netif_device_present(dev))
1771 goto reschedule;
1772
1773 SMC_SELECT_BANK(2);
1774
1775 /* need MC_RESET to keep the memory consistent. errata? */
1776 if (smc->rx_ovrn) {
1777 outw(MC_RESET, ioaddr + MMU_CMD);
1778 smc->rx_ovrn = 0;
1779 }
1780 i = inw(ioaddr + INTERRUPT);
1781 SMC_SELECT_BANK(0);
1782 media = inw(ioaddr + EPH) & EPH_LINK_OK;
1783 SMC_SELECT_BANK(1);
1784 media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;
1785
Ken Kawasaki2a915152010-04-24 10:37:09 +00001786 SMC_SELECT_BANK(saved_bank);
1787 spin_unlock_irqrestore(&smc->lock, flags);
1788
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 /* Check for pending interrupt with watchdog flag set: with
1790 this, we can limp along even if the interrupt is blocked */
1791 if (smc->watchdog++ && ((i>>8) & i)) {
1792 if (!smc->fast_poll)
1793 printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
Ken Kawasaki2a915152010-04-24 10:37:09 +00001794 local_irq_save(flags);
Komuroe363d132007-02-10 11:57:35 +09001795 smc_interrupt(dev->irq, dev);
Ken Kawasaki2a915152010-04-24 10:37:09 +00001796 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 smc->fast_poll = HZ;
1798 }
1799 if (smc->fast_poll) {
1800 smc->fast_poll--;
1801 smc->media.expires = jiffies + HZ/100;
1802 add_timer(&smc->media);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 return;
1804 }
1805
Ken Kawasaki2a915152010-04-24 10:37:09 +00001806 spin_lock_irqsave(&smc->lock, flags);
1807
1808 saved_bank = inw(ioaddr + BANK_SELECT);
1809
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 if (smc->cfg & CFG_MII_SELECT) {
1811 if (smc->mii_if.phy_id < 0)
1812 goto reschedule;
1813
1814 SMC_SELECT_BANK(3);
1815 link = mdio_read(dev, smc->mii_if.phy_id, 1);
1816 if (!link || (link == 0xffff)) {
1817 printk(KERN_INFO "%s: MII is missing!\n", dev->name);
1818 smc->mii_if.phy_id = -1;
1819 goto reschedule;
1820 }
1821
1822 link &= 0x0004;
1823 if (link != smc->link_status) {
1824 u_short p = mdio_read(dev, smc->mii_if.phy_id, 5);
1825 printk(KERN_INFO "%s: %s link beat\n", dev->name,
1826 (link) ? "found" : "lost");
1827 smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40))
1828 ? TCR_FDUPLX : 0);
1829 if (link) {
1830 printk(KERN_INFO "%s: autonegotiation complete: "
1831 "%sbaseT-%cD selected\n", dev->name,
1832 ((p & 0x0180) ? "100" : "10"),
1833 (smc->duplex ? 'F' : 'H'));
1834 }
1835 SMC_SELECT_BANK(0);
1836 outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR);
1837 smc->link_status = link;
1838 }
1839 goto reschedule;
1840 }
1841
1842 /* Ignore collisions unless we've had no rx's recently */
Marcelo Feitoza Parisi4851d3a2005-07-15 10:00:41 -07001843 if (time_after(jiffies, dev->last_rx + HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 if (smc->tx_err || (smc->media_status & EPH_16COL))
1845 media |= EPH_16COL;
1846 }
1847 smc->tx_err = 0;
1848
1849 if (media != smc->media_status) {
1850 if ((media & smc->media_status & 1) &&
1851 ((smc->media_status ^ media) & EPH_LINK_OK))
1852 printk(KERN_INFO "%s: %s link beat\n", dev->name,
1853 (smc->media_status & EPH_LINK_OK ? "lost" : "found"));
1854 else if ((media & smc->media_status & 2) &&
1855 ((smc->media_status ^ media) & EPH_16COL))
1856 printk(KERN_INFO "%s: coax cable %s\n", dev->name,
1857 (media & EPH_16COL ? "problem" : "ok"));
1858 if (dev->if_port == 0) {
1859 if (media & 1) {
1860 if (media & EPH_LINK_OK)
1861 printk(KERN_INFO "%s: flipped to 10baseT\n",
1862 dev->name);
1863 else
1864 smc_set_xcvr(dev, 2);
1865 } else {
1866 if (media & EPH_16COL)
1867 smc_set_xcvr(dev, 1);
1868 else
1869 printk(KERN_INFO "%s: flipped to 10base2\n",
1870 dev->name);
1871 }
1872 }
1873 smc->media_status = media;
1874 }
1875
1876reschedule:
1877 smc->media.expires = jiffies + HZ;
1878 add_timer(&smc->media);
1879 SMC_SELECT_BANK(saved_bank);
Komuro85e27832007-07-23 21:36:06 +09001880 spin_unlock_irqrestore(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881}
1882
1883static int smc_link_ok(struct net_device *dev)
1884{
Olof Johansson906da802008-02-04 22:27:35 -08001885 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 struct smc_private *smc = netdev_priv(dev);
1887
1888 if (smc->cfg & CFG_MII_SELECT) {
1889 return mii_link_ok(&smc->mii_if);
1890 } else {
1891 SMC_SELECT_BANK(0);
1892 return inw(ioaddr + EPH) & EPH_LINK_OK;
1893 }
1894}
1895
1896static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
1897{
1898 u16 tmp;
Olof Johansson906da802008-02-04 22:27:35 -08001899 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
1901 ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |
1902 SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
1903
1904 SMC_SELECT_BANK(1);
1905 tmp = inw(ioaddr + CONFIG);
1906 ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP;
1907 ecmd->transceiver = XCVR_INTERNAL;
1908 ecmd->speed = SPEED_10;
1909 ecmd->phy_address = ioaddr + MGMT;
1910
1911 SMC_SELECT_BANK(0);
1912 tmp = inw(ioaddr + TCR);
1913 ecmd->duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF;
1914
1915 return 0;
1916}
1917
1918static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
1919{
1920 u16 tmp;
Olof Johansson906da802008-02-04 22:27:35 -08001921 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
1923 if (ecmd->speed != SPEED_10)
1924 return -EINVAL;
1925 if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
1926 return -EINVAL;
1927 if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI)
1928 return -EINVAL;
1929 if (ecmd->transceiver != XCVR_INTERNAL)
1930 return -EINVAL;
1931
1932 if (ecmd->port == PORT_AUI)
1933 smc_set_xcvr(dev, 1);
1934 else
1935 smc_set_xcvr(dev, 0);
1936
1937 SMC_SELECT_BANK(0);
1938 tmp = inw(ioaddr + TCR);
1939 if (ecmd->duplex == DUPLEX_FULL)
1940 tmp |= TCR_FDUPLX;
1941 else
1942 tmp &= ~TCR_FDUPLX;
1943 outw(tmp, ioaddr + TCR);
1944
1945 return 0;
1946}
1947
1948static int check_if_running(struct net_device *dev)
1949{
1950 if (!netif_running(dev))
1951 return -EINVAL;
1952 return 0;
1953}
1954
1955static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
1956{
1957 strcpy(info->driver, DRV_NAME);
1958 strcpy(info->version, DRV_VERSION);
1959}
1960
1961static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
1962{
1963 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001964 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 u16 saved_bank = inw(ioaddr + BANK_SELECT);
1966 int ret;
Ken Kawasaki2a915152010-04-24 10:37:09 +00001967 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968
Ken Kawasaki2a915152010-04-24 10:37:09 +00001969 spin_lock_irqsave(&smc->lock, flags);
Komuro85e27832007-07-23 21:36:06 +09001970 SMC_SELECT_BANK(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 if (smc->cfg & CFG_MII_SELECT)
1972 ret = mii_ethtool_gset(&smc->mii_if, ecmd);
1973 else
1974 ret = smc_netdev_get_ecmd(dev, ecmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 SMC_SELECT_BANK(saved_bank);
Ken Kawasaki2a915152010-04-24 10:37:09 +00001976 spin_unlock_irqrestore(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 return ret;
1978}
1979
1980static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
1981{
1982 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001983 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 u16 saved_bank = inw(ioaddr + BANK_SELECT);
1985 int ret;
Ken Kawasaki2a915152010-04-24 10:37:09 +00001986 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
Ken Kawasaki2a915152010-04-24 10:37:09 +00001988 spin_lock_irqsave(&smc->lock, flags);
Komuro85e27832007-07-23 21:36:06 +09001989 SMC_SELECT_BANK(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 if (smc->cfg & CFG_MII_SELECT)
1991 ret = mii_ethtool_sset(&smc->mii_if, ecmd);
1992 else
1993 ret = smc_netdev_set_ecmd(dev, ecmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 SMC_SELECT_BANK(saved_bank);
Ken Kawasaki2a915152010-04-24 10:37:09 +00001995 spin_unlock_irqrestore(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 return ret;
1997}
1998
1999static u32 smc_get_link(struct net_device *dev)
2000{
2001 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08002002 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 u16 saved_bank = inw(ioaddr + BANK_SELECT);
2004 u32 ret;
Ken Kawasaki2a915152010-04-24 10:37:09 +00002005 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006
Ken Kawasaki2a915152010-04-24 10:37:09 +00002007 spin_lock_irqsave(&smc->lock, flags);
Komuro85e27832007-07-23 21:36:06 +09002008 SMC_SELECT_BANK(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 ret = smc_link_ok(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 SMC_SELECT_BANK(saved_bank);
Ken Kawasaki2a915152010-04-24 10:37:09 +00002011 spin_unlock_irqrestore(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 return ret;
2013}
2014
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015static int smc_nway_reset(struct net_device *dev)
2016{
2017 struct smc_private *smc = netdev_priv(dev);
2018 if (smc->cfg & CFG_MII_SELECT) {
Olof Johansson906da802008-02-04 22:27:35 -08002019 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 u16 saved_bank = inw(ioaddr + BANK_SELECT);
2021 int res;
2022
2023 SMC_SELECT_BANK(3);
2024 res = mii_nway_restart(&smc->mii_if);
2025 SMC_SELECT_BANK(saved_bank);
2026
2027 return res;
2028 } else
2029 return -EOPNOTSUPP;
2030}
2031
Jeff Garzik7282d492006-09-13 14:30:00 -04002032static const struct ethtool_ops ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 .begin = check_if_running,
2034 .get_drvinfo = smc_get_drvinfo,
2035 .get_settings = smc_get_settings,
2036 .set_settings = smc_set_settings,
2037 .get_link = smc_get_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 .nway_reset = smc_nway_reset,
2039};
2040
2041static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
2042{
2043 struct smc_private *smc = netdev_priv(dev);
2044 struct mii_ioctl_data *mii = if_mii(rq);
2045 int rc = 0;
2046 u16 saved_bank;
Olof Johansson906da802008-02-04 22:27:35 -08002047 unsigned int ioaddr = dev->base_addr;
Ken Kawasaki2a915152010-04-24 10:37:09 +00002048 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
2050 if (!netif_running(dev))
2051 return -EINVAL;
2052
Ken Kawasaki2a915152010-04-24 10:37:09 +00002053 spin_lock_irqsave(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 saved_bank = inw(ioaddr + BANK_SELECT);
2055 SMC_SELECT_BANK(3);
2056 rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
2057 SMC_SELECT_BANK(saved_bank);
Ken Kawasaki2a915152010-04-24 10:37:09 +00002058 spin_unlock_irqrestore(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 return rc;
2060}
2061
Dominik Brodowski5c672222005-06-27 16:28:27 -07002062static struct pcmcia_device_id smc91c92_ids[] = {
2063 PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
2064 PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
2065 PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
2066 PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
2067 PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
2068 PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
2069 PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
2070 PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
Komurod277ad02005-07-28 01:07:24 -07002071 PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
2072 PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
Dominik Brodowski5c672222005-06-27 16:28:27 -07002073 PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020),
2074 PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023),
2075 PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb),
2076 PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc),
2077 PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1),
2078 PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5),
2079 PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9),
2080 PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953),
2081 PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a),
Komurod277ad02005-07-28 01:07:24 -07002082 PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Four of Diamonds Ethernet", 0xc2f80cd, 0xb3466314),
2083 PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Seven of Diamonds Ethernet", 0xc2f80cd, 0x194b650a),
Dominik Brodowski5c672222005-06-27 16:28:27 -07002084 PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc),
2085 PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9),
2086 PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d),
2087 /* These conflict with other cards! */
2088 /* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */
2089 /* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */
2090 PCMCIA_DEVICE_NULL,
2091};
2092MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids);
2093
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094static struct pcmcia_driver smc91c92_cs_driver = {
2095 .owner = THIS_MODULE,
2096 .drv = {
2097 .name = "smc91c92_cs",
2098 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02002099 .probe = smc91c92_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +01002100 .remove = smc91c92_detach,
Dominik Brodowski5c672222005-06-27 16:28:27 -07002101 .id_table = smc91c92_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +01002102 .suspend = smc91c92_suspend,
2103 .resume = smc91c92_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104};
2105
2106static int __init init_smc91c92_cs(void)
2107{
2108 return pcmcia_register_driver(&smc91c92_cs_driver);
2109}
2110
2111static void __exit exit_smc91c92_cs(void)
2112{
2113 pcmcia_unregister_driver(&smc91c92_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114}
2115
2116module_init(init_smc91c92_cs);
2117module_exit(exit_smc91c92_cs);