blob: af03759d186dd618fbf14feb0722a5c632e723b2 [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/cs_types.h>
48#include <pcmcia/cs.h>
49#include <pcmcia/cistpl.h>
50#include <pcmcia/cisreg.h>
51#include <pcmcia/ciscode.h>
52#include <pcmcia/ds.h>
Dominik Brodowski50db3fd2006-01-15 10:05:19 +010053#include <pcmcia/ss.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55#include <asm/io.h>
56#include <asm/system.h>
57#include <asm/uaccess.h>
58
Linus Torvalds1da177e2005-04-16 15:20:36 -070059/*====================================================================*/
60
Arjan van de Venf71e1302006-03-03 21:33:57 -050061static const char *if_names[] = { "auto", "10baseT", "10base2"};
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Jaswinder Singh Rajput75bf7582009-03-30 20:19:54 +053063/* Firmware name */
64#define FIRMWARE_NAME "ositech/Xilinx7OD.bin"
65
Linus Torvalds1da177e2005-04-16 15:20:36 -070066/* Module parameters */
67
68MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver");
69MODULE_LICENSE("GPL");
Jaswinder Singh Rajput75bf7582009-03-30 20:19:54 +053070MODULE_FIRMWARE(FIRMWARE_NAME);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
72#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
73
74/*
75 Transceiver/media type.
76 0 = auto
77 1 = 10baseT (and autoselect if #define AUTOSELECT),
78 2 = AUI/10base2,
79*/
80INT_MODULE_PARM(if_port, 0);
81
82#ifdef PCMCIA_DEBUG
83INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
84static const char *version =
Andy Gospodarekd5b20692006-09-11 17:39:18 -040085"smc91c92_cs.c 1.123 2006/11/09 Donald Becker, becker@scyld.com.\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -070086#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
87#else
88#define DEBUG(n, args...)
89#endif
90
91#define DRV_NAME "smc91c92_cs"
Andy Gospodarekd5b20692006-09-11 17:39:18 -040092#define DRV_VERSION "1.123"
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
94/*====================================================================*/
95
96/* Operational parameter that usually are not changed. */
97
98/* Time in jiffies before concluding Tx hung */
99#define TX_TIMEOUT ((400*HZ)/1000)
100
101/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
102#define INTR_WORK 4
103
104/* Times to check the check the chip before concluding that it doesn't
105 currently have room for another Tx packet. */
106#define MEMORY_WAIT_TIME 8
107
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108struct smc_private {
Dominik Brodowskifd238232006-03-05 10:45:09 +0100109 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 spinlock_t lock;
111 u_short manfid;
112 u_short cardid;
Stephen Hemminger6fb72982009-03-20 19:36:09 +0000113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 dev_node_t node;
115 struct sk_buff *saved_skb;
116 int packets_waiting;
117 void __iomem *base;
118 u_short cfg;
119 struct timer_list media;
120 int watchdog, tx_err;
121 u_short media_status;
122 u_short fast_poll;
123 u_short link_status;
124 struct mii_if_info mii_if;
125 int duplex;
126 int rx_ovrn;
127};
128
Yum Rayan4638aef42005-05-05 15:14:10 -0700129struct smc_cfg_mem {
130 tuple_t tuple;
131 cisparse_t parse;
132 u_char buf[255];
133};
134
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135/* Special definitions for Megahertz multifunction cards */
136#define MEGAHERTZ_ISR 0x0380
137
138/* Special function registers for Motorola Mariner */
139#define MOT_LAN 0x0000
140#define MOT_UART 0x0020
141#define MOT_EEPROM 0x20
142
143#define MOT_NORMAL \
144(COR_LEVEL_REQ | COR_FUNC_ENA | COR_ADDR_DECODE | COR_IREQ_ENA)
145
146/* Special function registers for Ositech cards */
147#define OSITECH_AUI_CTL 0x0c
148#define OSITECH_PWRDOWN 0x0d
149#define OSITECH_RESET 0x0e
150#define OSITECH_ISR 0x0f
151#define OSITECH_AUI_PWR 0x0c
152#define OSITECH_RESET_ISR 0x0e
153
154#define OSI_AUI_PWR 0x40
155#define OSI_LAN_PWRDOWN 0x02
156#define OSI_MODEM_PWRDOWN 0x01
157#define OSI_LAN_RESET 0x02
158#define OSI_MODEM_RESET 0x01
159
160/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */
161#define BANK_SELECT 14 /* Window select register. */
162#define SMC_SELECT_BANK(x) { outw(x, ioaddr + BANK_SELECT); }
163
164/* Bank 0 registers. */
165#define TCR 0 /* transmit control register */
166#define TCR_CLEAR 0 /* do NOTHING */
167#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */
168#define TCR_PAD_EN 0x0080 /* pads short packets to 64 bytes */
169#define TCR_MONCSN 0x0400 /* Monitor Carrier. */
170#define TCR_FDUPLX 0x0800 /* Full duplex mode. */
171#define TCR_NORMAL TCR_ENABLE | TCR_PAD_EN
172
173#define EPH 2 /* Ethernet Protocol Handler report. */
174#define EPH_TX_SUC 0x0001
175#define EPH_SNGLCOL 0x0002
176#define EPH_MULCOL 0x0004
177#define EPH_LTX_MULT 0x0008
178#define EPH_16COL 0x0010
179#define EPH_SQET 0x0020
180#define EPH_LTX_BRD 0x0040
181#define EPH_TX_DEFR 0x0080
182#define EPH_LAT_COL 0x0200
183#define EPH_LOST_CAR 0x0400
184#define EPH_EXC_DEF 0x0800
185#define EPH_CTR_ROL 0x1000
186#define EPH_RX_OVRN 0x2000
187#define EPH_LINK_OK 0x4000
188#define EPH_TX_UNRN 0x8000
189#define MEMINFO 8 /* Memory Information Register */
190#define MEMCFG 10 /* Memory Configuration Register */
191
192/* Bank 1 registers. */
193#define CONFIG 0
194#define CFG_MII_SELECT 0x8000 /* 91C100 only */
195#define CFG_NO_WAIT 0x1000
196#define CFG_FULL_STEP 0x0400
197#define CFG_SET_SQLCH 0x0200
198#define CFG_AUI_SELECT 0x0100
199#define CFG_16BIT 0x0080
200#define CFG_DIS_LINK 0x0040
201#define CFG_STATIC 0x0030
202#define CFG_IRQ_SEL_1 0x0004
203#define CFG_IRQ_SEL_0 0x0002
204#define BASE_ADDR 2
205#define ADDR0 4
206#define GENERAL 10
207#define CONTROL 12
208#define CTL_STORE 0x0001
209#define CTL_RELOAD 0x0002
210#define CTL_EE_SELECT 0x0004
211#define CTL_TE_ENABLE 0x0020
212#define CTL_CR_ENABLE 0x0040
213#define CTL_LE_ENABLE 0x0080
214#define CTL_AUTO_RELEASE 0x0800
215#define CTL_POWERDOWN 0x2000
216
217/* Bank 2 registers. */
218#define MMU_CMD 0
219#define MC_ALLOC 0x20 /* or with number of 256 byte packets */
220#define MC_RESET 0x40
221#define MC_RELEASE 0x80 /* remove and release the current rx packet */
222#define MC_FREEPKT 0xA0 /* Release packet in PNR register */
223#define MC_ENQUEUE 0xC0 /* Enqueue the packet for transmit */
224#define PNR_ARR 2
225#define FIFO_PORTS 4
226#define FP_RXEMPTY 0x8000
227#define POINTER 6
228#define PTR_AUTO_INC 0x0040
229#define PTR_READ 0x2000
230#define PTR_AUTOINC 0x4000
231#define PTR_RCV 0x8000
232#define DATA_1 8
233#define INTERRUPT 12
234#define IM_RCV_INT 0x1
235#define IM_TX_INT 0x2
236#define IM_TX_EMPTY_INT 0x4
237#define IM_ALLOC_INT 0x8
238#define IM_RX_OVRN_INT 0x10
239#define IM_EPH_INT 0x20
240
241#define RCR 4
242enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002,
243 RxEnable = 0x0100, RxStripCRC = 0x0200};
244#define RCR_SOFTRESET 0x8000 /* resets the chip */
245#define RCR_STRIP_CRC 0x200 /* strips CRC */
246#define RCR_ENABLE 0x100 /* IFF this is set, we can receive packets */
247#define RCR_ALMUL 0x4 /* receive all multicast packets */
248#define RCR_PROMISC 0x2 /* enable promiscuous mode */
249
250/* the normal settings for the RCR register : */
251#define RCR_NORMAL (RCR_STRIP_CRC | RCR_ENABLE)
252#define RCR_CLEAR 0x0 /* set it to a base state */
253#define COUNTER 6
254
255/* BANK 3 -- not the same values as in smc9194! */
256#define MULTICAST0 0
257#define MULTICAST2 2
258#define MULTICAST4 4
259#define MULTICAST6 6
260#define MGMT 8
261#define REVISION 0x0a
262
263/* Transmit status bits. */
264#define TS_SUCCESS 0x0001
265#define TS_16COL 0x0010
266#define TS_LATCOL 0x0200
267#define TS_LOSTCAR 0x0400
268
269/* Receive status bits. */
270#define RS_ALGNERR 0x8000
271#define RS_BADCRC 0x2000
272#define RS_ODDFRAME 0x1000
273#define RS_TOOLONG 0x0800
274#define RS_TOOSHORT 0x0400
275#define RS_MULTICAST 0x0001
276#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
277
278#define set_bits(v, p) outw(inw(p)|(v), (p))
279#define mask_bits(v, p) outw(inw(p)&(v), (p))
280
281/*====================================================================*/
282
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100283static void smc91c92_detach(struct pcmcia_device *p_dev);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200284static int smc91c92_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200285static void smc91c92_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287static int smc_open(struct net_device *dev);
288static int smc_close(struct net_device *dev);
289static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
290static void smc_tx_timeout(struct net_device *dev);
Stephen Hemmingerdbf02fa2009-08-31 19:50:49 +0000291static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
292 struct net_device *dev);
David Howells7d12e782006-10-05 14:55:46 +0100293static irqreturn_t smc_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294static void smc_rx(struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295static void set_rx_mode(struct net_device *dev);
296static int s9k_config(struct net_device *dev, struct ifmap *map);
297static void smc_set_xcvr(struct net_device *dev, int if_port);
298static void smc_reset(struct net_device *dev);
299static void media_check(u_long arg);
Olof Johansson906da802008-02-04 22:27:35 -0800300static void mdio_sync(unsigned int addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301static int mdio_read(struct net_device *dev, int phy_id, int loc);
302static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
303static int smc_link_ok(struct net_device *dev);
Jeff Garzik7282d492006-09-13 14:30:00 -0400304static const struct ethtool_ops ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Stephen Hemminger9b31b692009-03-20 19:36:10 +0000306static const struct net_device_ops smc_netdev_ops = {
307 .ndo_open = smc_open,
308 .ndo_stop = smc_close,
309 .ndo_start_xmit = smc_start_xmit,
310 .ndo_tx_timeout = smc_tx_timeout,
311 .ndo_set_config = s9k_config,
312 .ndo_set_multicast_list = set_rx_mode,
313 .ndo_do_ioctl = &smc_ioctl,
314 .ndo_change_mtu = eth_change_mtu,
315 .ndo_set_mac_address = eth_mac_addr,
316 .ndo_validate_addr = eth_validate_addr,
317};
318
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319/*======================================================================
320
321 smc91c92_attach() creates an "instance" of the driver, allocating
322 local data structures for one device. The device is registered
323 with Card Services.
324
325======================================================================*/
326
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200327static int smc91c92_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 struct smc_private *smc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 DEBUG(0, "smc91c92_attach()\n");
333
334 /* Create new ethernet device */
335 dev = alloc_etherdev(sizeof(struct smc_private));
336 if (!dev)
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100337 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 smc = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200339 smc->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 link->priv = dev;
341
342 spin_lock_init(&smc->lock);
343 link->io.NumPorts1 = 16;
344 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
345 link->io.IOAddrLines = 4;
Komuro5e7bf8c2007-10-28 11:26:17 +0900346 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_HANDLE_PRESENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
348 link->irq.Handler = &smc_interrupt;
349 link->irq.Instance = dev;
350 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 link->conf.IntType = INT_MEMORY_AND_IO;
352
353 /* The SMC91c92-specific entries in the device structure. */
Stephen Hemminger9b31b692009-03-20 19:36:10 +0000354 dev->netdev_ops = &smc_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 SET_ETHTOOL_OPS(dev, &ethtool_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 dev->watchdog_timeo = TX_TIMEOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
358 smc->mii_if.dev = dev;
359 smc->mii_if.mdio_read = mdio_read;
360 smc->mii_if.mdio_write = mdio_write;
361 smc->mii_if.phy_id_mask = 0x1f;
362 smc->mii_if.reg_num_mask = 0x1f;
363
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200364 return smc91c92_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365} /* smc91c92_attach */
366
367/*======================================================================
368
369 This deletes a driver "instance". The device is de-registered
370 with Card Services. If it has been released, all local data
371 structures are freed. Otherwise, the structures will be freed
372 when the device is released.
373
374======================================================================*/
375
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200376static void smc91c92_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
378 struct net_device *dev = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 DEBUG(0, "smc91c92_detach(0x%p)\n", link);
381
Dominik Brodowskifd238232006-03-05 10:45:09 +0100382 if (link->dev_node)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 unregister_netdev(dev);
384
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100385 smc91c92_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 free_netdev(dev);
388} /* smc91c92_detach */
389
390/*====================================================================*/
391
392static int cvt_ascii_address(struct net_device *dev, char *s)
393{
394 int i, j, da, c;
395
396 if (strlen(s) != 12)
397 return -1;
398 for (i = 0; i < 6; i++) {
399 da = 0;
400 for (j = 0; j < 2; j++) {
401 c = *s++;
402 da <<= 4;
403 da += ((c >= '0') && (c <= '9')) ?
404 (c - '0') : ((c & 0x0f) + 9);
405 }
406 dev->dev_addr[i] = da;
407 }
408 return 0;
409}
410
411/*====================================================================*/
412
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200413static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 cisparse_t *parse)
415{
416 int i;
417
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200418 i = pcmcia_get_first_tuple(handle, tuple);
419 if (i != 0)
420 return i;
421 i = pcmcia_get_tuple_data(handle, tuple);
422 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 return i;
Dominik Brodowski2f3061e2008-08-31 15:50:33 +0200424 return pcmcia_parse_tuple(tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425}
426
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200427static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 cisparse_t *parse)
429{
430 int i;
431
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200432 if ((i = pcmcia_get_next_tuple(handle, tuple)) != 0 ||
433 (i = pcmcia_get_tuple_data(handle, tuple)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 return i;
Dominik Brodowski2f3061e2008-08-31 15:50:33 +0200435 return pcmcia_parse_tuple(tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436}
437
438/*======================================================================
439
440 Configuration stuff for Megahertz cards
441
442 mhz_3288_power() is used to power up a 3288's ethernet chip.
443 mhz_mfc_config() handles socket setup for multifunction (1144
444 and 3288) cards. mhz_setup() gets a card's hardware ethernet
445 address.
446
447======================================================================*/
448
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200449static int mhz_3288_power(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
451 struct net_device *dev = link->priv;
452 struct smc_private *smc = netdev_priv(dev);
453 u_char tmp;
454
455 /* Read the ISR twice... */
456 readb(smc->base+MEGAHERTZ_ISR);
457 udelay(5);
458 readb(smc->base+MEGAHERTZ_ISR);
459
460 /* Pause 200ms... */
461 mdelay(200);
462
463 /* Now read and write the COR... */
464 tmp = readb(smc->base + link->conf.ConfigBase + CISREG_COR);
465 udelay(5);
466 writeb(tmp, smc->base + link->conf.ConfigBase + CISREG_COR);
467
468 return 0;
469}
470
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200471static int mhz_mfc_config_check(struct pcmcia_device *p_dev,
472 cistpl_cftable_entry_t *cf,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200473 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200474 unsigned int vcc,
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200475 void *priv_data)
476{
477 int k;
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200478 p_dev->io.BasePort2 = cf->io.win[0].base;
479 for (k = 0; k < 0x400; k += 0x10) {
480 if (k & 0x80)
481 continue;
482 p_dev->io.BasePort1 = k ^ 0x300;
483 if (!pcmcia_request_io(p_dev, &p_dev->io))
484 return 0;
485 }
486 return -ENODEV;
487}
488
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200489static int mhz_mfc_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490{
491 struct net_device *dev = link->priv;
492 struct smc_private *smc = netdev_priv(dev);
Yum Rayan4638aef42005-05-05 15:14:10 -0700493 struct smc_cfg_mem *cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 win_req_t req;
495 memreq_t mem;
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200496 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
Yum Rayan4638aef42005-05-05 15:14:10 -0700498 cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
499 if (!cfg_mem)
Dominik Brodowski11683862008-08-03 10:22:47 +0200500 return -ENOMEM;
Yum Rayan4638aef42005-05-05 15:14:10 -0700501
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 link->conf.Attributes |= CONF_ENABLE_SPKR;
503 link->conf.Status = CCSR_AUDIO_ENA;
504 link->irq.Attributes =
505 IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
506 link->io.IOAddrLines = 16;
507 link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
508 link->io.NumPorts2 = 8;
509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 /* The Megahertz combo cards have modem-like CIS entries, so
511 we have to explicitly try a bunch of port combinations. */
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200512 if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL))
Yum Rayan4638aef42005-05-05 15:14:10 -0700513 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 dev->base_addr = link->io.BasePort1;
515
516 /* Allocate a memory window, for accessing the ISR */
517 req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
518 req.Base = req.Size = 0;
519 req.AccessSpeed = 0;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200520 i = pcmcia_request_window(&link, &req, &link->win);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200521 if (i != 0)
Yum Rayan4638aef42005-05-05 15:14:10 -0700522 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 smc->base = ioremap(req.Base, req.Size);
524 mem.CardOffset = mem.Page = 0;
525 if (smc->manfid == MANFID_MOTOROLA)
526 mem.CardOffset = link->conf.ConfigBase;
527 i = pcmcia_map_mem_page(link->win, &mem);
528
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200529 if ((i == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 && (smc->manfid == MANFID_MEGAHERTZ)
531 && (smc->cardid == PRODID_MEGAHERTZ_EM3288))
532 mhz_3288_power(link);
533
Yum Rayan4638aef42005-05-05 15:14:10 -0700534free_cfg_mem:
535 kfree(cfg_mem);
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200536 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537}
538
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200539static int mhz_setup(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 struct net_device *dev = link->priv;
Yum Rayan4638aef42005-05-05 15:14:10 -0700542 struct smc_cfg_mem *cfg_mem;
543 tuple_t *tuple;
544 cisparse_t *parse;
545 u_char *buf, *station_addr;
546 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Dominik Brodowski7d2e8d02009-10-18 18:22:32 +0200548 /* Read the station address from the CIS. It is stored as the last
549 (fourth) string in the Version 1 Version/ID tuple. */
550 if ((link->prod_id[3]) &&
551 (cvt_ascii_address(dev, link->prod_id[3]) == 0))
552 return 0;
553
554 /* Workarounds for broken cards start here. */
555
Yum Rayan4638aef42005-05-05 15:14:10 -0700556 cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
557 if (!cfg_mem)
558 return -1;
559
560 tuple = &cfg_mem->tuple;
561 parse = &cfg_mem->parse;
562 buf = cfg_mem->buf;
563
564 tuple->Attributes = tuple->TupleOffset = 0;
565 tuple->TupleData = (cisdata_t *)buf;
566 tuple->TupleDataMax = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Dominik Brodowski7d2e8d02009-10-18 18:22:32 +0200568 /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
Chuck Ebberta1a98b72008-02-13 19:47:11 -0500569 tuple->DesiredTuple = CISTPL_VERS_1;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200570 if (first_tuple(link, tuple, parse) != 0) {
Chuck Ebberta1a98b72008-02-13 19:47:11 -0500571 rc = -1;
572 goto free_cfg_mem;
573 }
574 /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200575 if (next_tuple(link, tuple, parse) != 0)
Chuck Ebberta1a98b72008-02-13 19:47:11 -0500576 first_tuple(link, tuple, parse);
577 if (parse->version_1.ns > 3) {
578 station_addr = parse->version_1.str + parse->version_1.ofs[3];
Yum Rayan4638aef42005-05-05 15:14:10 -0700579 if (cvt_ascii_address(dev, station_addr) == 0) {
580 rc = 0;
581 goto free_cfg_mem;
582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 }
584
585 /* Another possibility: for the EM3288, in a special tuple */
Yum Rayan4638aef42005-05-05 15:14:10 -0700586 tuple->DesiredTuple = 0x81;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200587 if (pcmcia_get_first_tuple(link, tuple) != 0) {
Yum Rayan4638aef42005-05-05 15:14:10 -0700588 rc = -1;
589 goto free_cfg_mem;
590 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200591 if (pcmcia_get_tuple_data(link, tuple) != 0) {
Yum Rayan4638aef42005-05-05 15:14:10 -0700592 rc = -1;
593 goto free_cfg_mem;
594 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 buf[12] = '\0';
Yum Rayan4638aef42005-05-05 15:14:10 -0700596 if (cvt_ascii_address(dev, buf) == 0) {
597 rc = 0;
598 goto free_cfg_mem;
599 }
600 rc = -1;
601free_cfg_mem:
602 kfree(cfg_mem);
603 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604}
605
606/*======================================================================
607
608 Configuration stuff for the Motorola Mariner
609
610 mot_config() writes directly to the Mariner configuration
611 registers because the CIS is just bogus.
612
613======================================================================*/
614
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200615static void mot_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616{
617 struct net_device *dev = link->priv;
618 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800619 unsigned int ioaddr = dev->base_addr;
620 unsigned int iouart = link->io.BasePort2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622 /* Set UART base address and force map with COR bit 1 */
623 writeb(iouart & 0xff, smc->base + MOT_UART + CISREG_IOBASE_0);
624 writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1);
625 writeb(MOT_NORMAL, smc->base + MOT_UART + CISREG_COR);
626
627 /* Set SMC base address and force map with COR bit 1 */
628 writeb(ioaddr & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_0);
629 writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1);
630 writeb(MOT_NORMAL, smc->base + MOT_LAN + CISREG_COR);
631
632 /* Wait for things to settle down */
633 mdelay(100);
634}
635
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200636static int mot_setup(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637{
638 struct net_device *dev = link->priv;
Olof Johansson906da802008-02-04 22:27:35 -0800639 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 int i, wait, loop;
641 u_int addr;
642
643 /* Read Ethernet address from Serial EEPROM */
644
645 for (i = 0; i < 3; i++) {
646 SMC_SELECT_BANK(2);
647 outw(MOT_EEPROM + i, ioaddr + POINTER);
648 SMC_SELECT_BANK(1);
649 outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL);
650
651 for (loop = wait = 0; loop < 200; loop++) {
652 udelay(10);
653 wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL));
654 if (wait == 0) break;
655 }
656
657 if (wait)
658 return -1;
659
660 addr = inw(ioaddr + GENERAL);
661 dev->dev_addr[2*i] = addr & 0xff;
662 dev->dev_addr[2*i+1] = (addr >> 8) & 0xff;
663 }
664
665 return 0;
666}
667
668/*====================================================================*/
669
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200670static int smc_configcheck(struct pcmcia_device *p_dev,
671 cistpl_cftable_entry_t *cf,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200672 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200673 unsigned int vcc,
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200674 void *priv_data)
675{
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200676 p_dev->io.BasePort1 = cf->io.win[0].base;
677 p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
678 return pcmcia_request_io(p_dev, &p_dev->io);
679}
680
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200681static int smc_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
683 struct net_device *dev = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 int i;
685
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 link->io.NumPorts1 = 16;
Dominik Brodowskib54bf942008-08-02 14:28:43 +0200687 i = pcmcia_loop_config(link, smc_configcheck, NULL);
688 if (!i)
689 dev->base_addr = link->io.BasePort1;
Yum Rayan4638aef42005-05-05 15:14:10 -0700690
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 return i;
692}
693
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200694static int smc_setup(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 struct net_device *dev = link->priv;
Yum Rayan4638aef42005-05-05 15:14:10 -0700697 struct smc_cfg_mem *cfg_mem;
698 tuple_t *tuple;
699 cisparse_t *parse;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 cistpl_lan_node_id_t *node_id;
Yum Rayan4638aef42005-05-05 15:14:10 -0700701 u_char *buf, *station_addr;
702 int i, rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Yum Rayan4638aef42005-05-05 15:14:10 -0700704 cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
705 if (!cfg_mem)
Dominik Brodowski11683862008-08-03 10:22:47 +0200706 return -ENOMEM;
Yum Rayan4638aef42005-05-05 15:14:10 -0700707
708 tuple = &cfg_mem->tuple;
709 parse = &cfg_mem->parse;
710 buf = cfg_mem->buf;
711
712 tuple->Attributes = tuple->TupleOffset = 0;
713 tuple->TupleData = (cisdata_t *)buf;
714 tuple->TupleDataMax = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
716 /* Check for a LAN function extension tuple */
Yum Rayan4638aef42005-05-05 15:14:10 -0700717 tuple->DesiredTuple = CISTPL_FUNCE;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200718 i = first_tuple(link, tuple, parse);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200719 while (i == 0) {
Yum Rayan4638aef42005-05-05 15:14:10 -0700720 if (parse->funce.type == CISTPL_FUNCE_LAN_NODE_ID)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 break;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200722 i = next_tuple(link, tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200724 if (i == 0) {
Yum Rayan4638aef42005-05-05 15:14:10 -0700725 node_id = (cistpl_lan_node_id_t *)parse->funce.data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 if (node_id->nb == 6) {
727 for (i = 0; i < 6; i++)
728 dev->dev_addr[i] = node_id->id[i];
Yum Rayan4638aef42005-05-05 15:14:10 -0700729 rc = 0;
730 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 }
732 }
733 /* Try the third string in the Version 1 Version/ID tuple. */
Dominik Brodowskia9606fd2006-06-04 18:06:13 +0200734 if (link->prod_id[2]) {
735 station_addr = link->prod_id[2];
736 if (cvt_ascii_address(dev, station_addr) == 0) {
737 rc = 0;
738 goto free_cfg_mem;
739 }
Yum Rayan4638aef42005-05-05 15:14:10 -0700740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Yum Rayan4638aef42005-05-05 15:14:10 -0700742 rc = -1;
743free_cfg_mem:
744 kfree(cfg_mem);
745 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746}
747
748/*====================================================================*/
749
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200750static int osi_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
752 struct net_device *dev = link->priv;
Olof Johansson906da802008-02-04 22:27:35 -0800753 static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 int i, j;
755
756 link->conf.Attributes |= CONF_ENABLE_SPKR;
757 link->conf.Status = CCSR_AUDIO_ENA;
758 link->irq.Attributes =
759 IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
760 link->io.NumPorts1 = 64;
761 link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
762 link->io.NumPorts2 = 8;
763 link->io.IOAddrLines = 16;
764
765 /* Enable Hard Decode, LAN, Modem */
766 link->conf.ConfigIndex = 0x23;
767
768 for (i = j = 0; j < 4; j++) {
769 link->io.BasePort2 = com[j];
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200770 i = pcmcia_request_io(link, &link->io);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200771 if (i == 0)
772 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200774 if (i != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 /* Fallback: turn off hard decode */
776 link->conf.ConfigIndex = 0x03;
777 link->io.NumPorts2 = 0;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200778 i = pcmcia_request_io(link, &link->io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
780 dev->base_addr = link->io.BasePort1 + 0x10;
781 return i;
782}
783
Jaswinder Singh Rajput75bf7582009-03-30 20:19:54 +0530784static int osi_load_firmware(struct pcmcia_device *link)
785{
786 const struct firmware *fw;
787 int i, err;
788
789 err = request_firmware(&fw, FIRMWARE_NAME, &link->dev);
790 if (err) {
791 pr_err("Failed to load firmware \"%s\"\n", FIRMWARE_NAME);
792 return err;
793 }
794
795 /* Download the Seven of Diamonds firmware */
796 for (i = 0; i < fw->size; i++) {
797 outb(fw->data[i], link->io.BasePort1 + 2);
798 udelay(50);
799 }
800 release_firmware(fw);
801 return err;
802}
803
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200804static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 struct net_device *dev = link->priv;
Yum Rayan4638aef42005-05-05 15:14:10 -0700807 struct smc_cfg_mem *cfg_mem;
808 tuple_t *tuple;
809 u_char *buf;
810 int i, rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Yum Rayan4638aef42005-05-05 15:14:10 -0700812 cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
813 if (!cfg_mem)
814 return -1;
815
816 tuple = &cfg_mem->tuple;
817 buf = cfg_mem->buf;
818
819 tuple->Attributes = TUPLE_RETURN_COMMON;
820 tuple->TupleData = (cisdata_t *)buf;
821 tuple->TupleDataMax = 255;
822 tuple->TupleOffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 /* Read the station address from tuple 0x90, subtuple 0x04 */
Yum Rayan4638aef42005-05-05 15:14:10 -0700825 tuple->DesiredTuple = 0x90;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200826 i = pcmcia_get_first_tuple(link, tuple);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200827 while (i == 0) {
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200828 i = pcmcia_get_tuple_data(link, tuple);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200829 if ((i != 0) || (buf[0] == 0x04))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 break;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200831 i = pcmcia_get_next_tuple(link, tuple);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200833 if (i != 0) {
Yum Rayan4638aef42005-05-05 15:14:10 -0700834 rc = -1;
835 goto free_cfg_mem;
836 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 for (i = 0; i < 6; i++)
838 dev->dev_addr[i] = buf[i+2];
839
840 if (((manfid == MANFID_OSITECH) &&
841 (cardid == PRODID_OSITECH_SEVEN)) ||
842 ((manfid == MANFID_PSION) &&
843 (cardid == PRODID_PSION_NET100))) {
Jaswinder Singh Rajput75bf7582009-03-30 20:19:54 +0530844 rc = osi_load_firmware(link);
845 if (rc)
846 goto free_cfg_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 } else if (manfid == MANFID_OSITECH) {
848 /* Make sure both functions are powered up */
849 set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR);
850 /* Now, turn on the interrupt for both card functions */
851 set_bits(0x300, link->io.BasePort1 + OSITECH_RESET_ISR);
852 DEBUG(2, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n",
853 inw(link->io.BasePort1 + OSITECH_AUI_PWR),
854 inw(link->io.BasePort1 + OSITECH_RESET_ISR));
855 }
Yum Rayan4638aef42005-05-05 15:14:10 -0700856 rc = 0;
857free_cfg_mem:
858 kfree(cfg_mem);
859 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200862static int smc91c92_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100863{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100864 struct net_device *dev = link->priv;
865
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100866 if (link->open)
Dominik Brodowski4bbed522006-01-15 11:18:12 +0100867 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100868
869 return 0;
870}
871
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200872static int smc91c92_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100873{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100874 struct net_device *dev = link->priv;
875 struct smc_private *smc = netdev_priv(dev);
876 int i;
877
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100878 if ((smc->manfid == MANFID_MEGAHERTZ) &&
879 (smc->cardid == PRODID_MEGAHERTZ_EM3288))
880 mhz_3288_power(link);
881 if (smc->manfid == MANFID_MOTOROLA)
882 mot_config(link);
883 if ((smc->manfid == MANFID_OSITECH) &&
884 (smc->cardid != PRODID_OSITECH_SEVEN)) {
885 /* Power up the card and enable interrupts */
886 set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
887 set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
888 }
889 if (((smc->manfid == MANFID_OSITECH) &&
890 (smc->cardid == PRODID_OSITECH_SEVEN)) ||
891 ((smc->manfid == MANFID_PSION) &&
892 (smc->cardid == PRODID_PSION_NET100))) {
Jaswinder Singh Rajput75bf7582009-03-30 20:19:54 +0530893 i = osi_load_firmware(link);
894 if (i) {
895 pr_err("smc91c92_cs: Failed to load firmware\n");
896 return i;
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100897 }
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100898 }
899 if (link->open) {
900 smc_reset(dev);
901 netif_device_attach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100902 }
903
904 return 0;
905}
906
907
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908/*======================================================================
909
910 This verifies that the chip is some SMC91cXX variant, and returns
911 the revision code if successful. Otherwise, it returns -ENODEV.
912
913======================================================================*/
914
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200915static int check_sig(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916{
917 struct net_device *dev = link->priv;
Olof Johansson906da802008-02-04 22:27:35 -0800918 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 int width;
920 u_short s;
921
922 SMC_SELECT_BANK(1);
923 if (inw(ioaddr + BANK_SELECT) >> 8 != 0x33) {
924 /* Try powering up the chip */
925 outw(0, ioaddr + CONTROL);
926 mdelay(55);
927 }
928
929 /* Try setting bus width */
930 width = (link->io.Attributes1 == IO_DATA_PATH_WIDTH_AUTO);
931 s = inb(ioaddr + CONFIG);
932 if (width)
933 s |= CFG_16BIT;
934 else
935 s &= ~CFG_16BIT;
936 outb(s, ioaddr + CONFIG);
937
938 /* Check Base Address Register to make sure bus width is OK */
939 s = inw(ioaddr + BASE_ADDR);
940 if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) &&
941 ((s >> 8) != (s & 0xff))) {
942 SMC_SELECT_BANK(3);
943 s = inw(ioaddr + REVISION);
944 return (s & 0xff);
945 }
946
947 if (width) {
Dominik Brodowski4bbed522006-01-15 11:18:12 +0100948 modconf_t mod = {
949 .Attributes = CONF_IO_CHANGE_WIDTH,
950 };
951 printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n");
Dominik Brodowski50db3fd2006-01-15 10:05:19 +0100952
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200953 smc91c92_suspend(link);
954 pcmcia_modify_configuration(link, &mod);
955 smc91c92_resume(link);
Dominik Brodowski4bbed522006-01-15 11:18:12 +0100956 return check_sig(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 }
958 return -ENODEV;
959}
960
961/*======================================================================
962
963 smc91c92_config() is scheduled to run after a CARD_INSERTION event
964 is received, to configure the PCMCIA socket, and to make the
965 ethernet device available to the system.
966
967======================================================================*/
968
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200969#define CS_EXIT_TEST(ret, svc, label) \
970if (ret != 0) { \
971 cs_error(link, svc, ret); \
972 goto label; \
973}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200975static int smc91c92_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 struct net_device *dev = link->priv;
978 struct smc_private *smc = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 char *name;
980 int i, j, rev;
Olof Johansson906da802008-02-04 22:27:35 -0800981 unsigned int ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 u_long mir;
983
984 DEBUG(0, "smc91c92_config(0x%p)\n", link);
985
Dominik Brodowskiefd50582006-10-25 21:28:53 -0400986 smc->manfid = link->manf_id;
987 smc->cardid = link->card_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 if ((smc->manfid == MANFID_OSITECH) &&
990 (smc->cardid != PRODID_OSITECH_SEVEN)) {
991 i = osi_config(link);
992 } else if ((smc->manfid == MANFID_MOTOROLA) ||
993 ((smc->manfid == MANFID_MEGAHERTZ) &&
994 ((smc->cardid == PRODID_MEGAHERTZ_VARIOUS) ||
995 (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) {
996 i = mhz_mfc_config(link);
997 } else {
998 i = smc_config(link);
999 }
1000 CS_EXIT_TEST(i, RequestIO, config_failed);
1001
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001002 i = pcmcia_request_irq(link, &link->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 CS_EXIT_TEST(i, RequestIRQ, config_failed);
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001004 i = pcmcia_request_configuration(link, &link->conf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 CS_EXIT_TEST(i, RequestConfiguration, config_failed);
1006
1007 if (smc->manfid == MANFID_MOTOROLA)
1008 mot_config(link);
1009
1010 dev->irq = link->irq.AssignedIRQ;
1011
1012 if ((if_port >= 0) && (if_port <= 2))
1013 dev->if_port = if_port;
1014 else
1015 printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
1016
1017 switch (smc->manfid) {
1018 case MANFID_OSITECH:
1019 case MANFID_PSION:
1020 i = osi_setup(link, smc->manfid, smc->cardid); break;
1021 case MANFID_SMC:
1022 case MANFID_NEW_MEDIA:
1023 i = smc_setup(link); break;
1024 case 0x128: /* For broken Megahertz cards */
1025 case MANFID_MEGAHERTZ:
1026 i = mhz_setup(link); break;
1027 case MANFID_MOTOROLA:
1028 default: /* get the hw address from EEPROM */
1029 i = mot_setup(link); break;
1030 }
1031
1032 if (i != 0) {
1033 printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n");
1034 goto config_undo;
1035 }
1036
1037 smc->duplex = 0;
1038 smc->rx_ovrn = 0;
1039
1040 rev = check_sig(link);
1041 name = "???";
1042 if (rev > 0)
1043 switch (rev >> 4) {
1044 case 3: name = "92"; break;
1045 case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break;
1046 case 5: name = "95"; break;
1047 case 7: name = "100"; break;
1048 case 8: name = "100-FD"; break;
1049 case 9: name = "110"; break;
1050 }
1051
1052 ioaddr = dev->base_addr;
1053 if (rev > 0) {
1054 u_long mcr;
1055 SMC_SELECT_BANK(0);
1056 mir = inw(ioaddr + MEMINFO) & 0xff;
1057 if (mir == 0xff) mir++;
1058 /* Get scale factor for memory size */
1059 mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200;
1060 mir *= 128 * (1<<((mcr >> 9) & 7));
1061 SMC_SELECT_BANK(1);
1062 smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT;
1063 smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC;
1064 if (smc->manfid == MANFID_OSITECH)
1065 smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0;
1066 if ((rev >> 4) >= 7)
1067 smc->cfg |= CFG_MII_SELECT;
1068 } else
1069 mir = 0;
1070
1071 if (smc->cfg & CFG_MII_SELECT) {
1072 SMC_SELECT_BANK(3);
1073
1074 for (i = 0; i < 32; i++) {
1075 j = mdio_read(dev, i, 1);
1076 if ((j != 0) && (j != 0xffff)) break;
1077 }
1078 smc->mii_if.phy_id = (i < 32) ? i : -1;
1079
1080 SMC_SELECT_BANK(0);
1081 }
1082
Dominik Brodowskifd238232006-03-05 10:45:09 +01001083 link->dev_node = &smc->node;
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001084 SET_NETDEV_DEV(dev, &handle_to_dev(link));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
1086 if (register_netdev(dev) != 0) {
1087 printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
Dominik Brodowskifd238232006-03-05 10:45:09 +01001088 link->dev_node = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 goto config_undo;
1090 }
1091
1092 strcpy(smc->node.dev_name, dev->name);
1093
1094 printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
Johannes Berge1749612008-10-27 15:59:26 -07001095 "hw_addr %pM\n",
Joe Perches0795af52007-10-03 17:59:30 -07001096 dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq,
Johannes Berge1749612008-10-27 15:59:26 -07001097 dev->dev_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099 if (rev > 0) {
1100 if (mir & 0x3ff)
1101 printk(KERN_INFO " %lu byte", mir);
1102 else
1103 printk(KERN_INFO " %lu kb", mir>>10);
1104 printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ?
1105 "MII" : if_names[dev->if_port]);
1106 }
1107
1108 if (smc->cfg & CFG_MII_SELECT) {
1109 if (smc->mii_if.phy_id != -1) {
1110 DEBUG(0, " MII transceiver at index %d, status %x.\n",
1111 smc->mii_if.phy_id, j);
1112 } else {
1113 printk(KERN_NOTICE " No MII transceivers found!\n");
1114 }
1115 }
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001116 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
1118config_undo:
1119 unregister_netdev(dev);
1120config_failed: /* CS_EXIT_TEST() calls jump to here... */
1121 smc91c92_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001122 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123} /* smc91c92_config */
1124
1125/*======================================================================
1126
1127 After a card is removed, smc91c92_release() will unregister the net
1128 device, and release the PCMCIA configuration. If the device is
1129 still open, this will be postponed until it is closed.
1130
1131======================================================================*/
1132
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001133static void smc91c92_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134{
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +01001135 DEBUG(0, "smc91c92_release(0x%p)\n", link);
1136 if (link->win) {
1137 struct net_device *dev = link->priv;
1138 struct smc_private *smc = netdev_priv(dev);
1139 iounmap(smc->base);
1140 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001141 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142}
1143
1144/*======================================================================
1145
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 MII interface support for SMC91cXX based cards
1147======================================================================*/
1148
1149#define MDIO_SHIFT_CLK 0x04
1150#define MDIO_DATA_OUT 0x01
1151#define MDIO_DIR_WRITE 0x08
1152#define MDIO_DATA_WRITE0 (MDIO_DIR_WRITE)
1153#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT)
1154#define MDIO_DATA_READ 0x02
1155
Olof Johansson906da802008-02-04 22:27:35 -08001156static void mdio_sync(unsigned int addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157{
1158 int bits;
1159 for (bits = 0; bits < 32; bits++) {
1160 outb(MDIO_DATA_WRITE1, addr);
1161 outb(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
1162 }
1163}
1164
1165static int mdio_read(struct net_device *dev, int phy_id, int loc)
1166{
Olof Johansson906da802008-02-04 22:27:35 -08001167 unsigned int addr = dev->base_addr + MGMT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
1169 int i, retval = 0;
1170
1171 mdio_sync(addr);
1172 for (i = 13; i >= 0; i--) {
1173 int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
1174 outb(dat, addr);
1175 outb(dat | MDIO_SHIFT_CLK, addr);
1176 }
1177 for (i = 19; i > 0; i--) {
1178 outb(0, addr);
1179 retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
1180 outb(MDIO_SHIFT_CLK, addr);
1181 }
1182 return (retval>>1) & 0xffff;
1183}
1184
1185static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
1186{
Olof Johansson906da802008-02-04 22:27:35 -08001187 unsigned int addr = dev->base_addr + MGMT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
1189 int i;
1190
1191 mdio_sync(addr);
1192 for (i = 31; i >= 0; i--) {
1193 int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
1194 outb(dat, addr);
1195 outb(dat | MDIO_SHIFT_CLK, addr);
1196 }
1197 for (i = 1; i >= 0; i--) {
1198 outb(0, addr);
1199 outb(MDIO_SHIFT_CLK, addr);
1200 }
1201}
1202
1203/*======================================================================
1204
1205 The driver core code, most of which should be common with a
1206 non-PCMCIA implementation.
1207
1208======================================================================*/
1209
1210#ifdef PCMCIA_DEBUG
1211static void smc_dump(struct net_device *dev)
1212{
Olof Johansson906da802008-02-04 22:27:35 -08001213 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 u_short i, w, save;
1215 save = inw(ioaddr + BANK_SELECT);
1216 for (w = 0; w < 4; w++) {
1217 SMC_SELECT_BANK(w);
1218 printk(KERN_DEBUG "bank %d: ", w);
1219 for (i = 0; i < 14; i += 2)
1220 printk(" %04x", inw(ioaddr + i));
1221 printk("\n");
1222 }
1223 outw(save, ioaddr + BANK_SELECT);
1224}
1225#endif
1226
1227static int smc_open(struct net_device *dev)
1228{
1229 struct smc_private *smc = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001230 struct pcmcia_device *link = smc->p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
1232#ifdef PCMCIA_DEBUG
1233 DEBUG(0, "%s: smc_open(%p), ID/Window %4.4x.\n",
1234 dev->name, dev, inw(dev->base_addr + BANK_SELECT));
1235 if (pc_debug > 1) smc_dump(dev);
1236#endif
1237
1238 /* Check that the PCMCIA card is still here. */
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001239 if (!pcmcia_dev_present(link))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 return -ENODEV;
1241 /* Physical device present signature. */
1242 if (check_sig(link) < 0) {
1243 printk("smc91c92_cs: Yikes! Bad chip signature!\n");
1244 return -ENODEV;
1245 }
1246 link->open++;
1247
1248 netif_start_queue(dev);
1249 smc->saved_skb = NULL;
1250 smc->packets_waiting = 0;
1251
1252 smc_reset(dev);
1253 init_timer(&smc->media);
1254 smc->media.function = &media_check;
1255 smc->media.data = (u_long) dev;
1256 smc->media.expires = jiffies + HZ;
1257 add_timer(&smc->media);
1258
1259 return 0;
1260} /* smc_open */
1261
1262/*====================================================================*/
1263
1264static int smc_close(struct net_device *dev)
1265{
1266 struct smc_private *smc = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001267 struct pcmcia_device *link = smc->p_dev;
Olof Johansson906da802008-02-04 22:27:35 -08001268 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 DEBUG(0, "%s: smc_close(), status %4.4x.\n",
1271 dev->name, inw(ioaddr + BANK_SELECT));
1272
1273 netif_stop_queue(dev);
1274
1275 /* Shut off all interrupts, and turn off the Tx and Rx sections.
1276 Don't bother to check for chip present. */
1277 SMC_SELECT_BANK(2); /* Nominally paranoia, but do no assume... */
1278 outw(0, ioaddr + INTERRUPT);
1279 SMC_SELECT_BANK(0);
1280 mask_bits(0xff00, ioaddr + RCR);
1281 mask_bits(0xff00, ioaddr + TCR);
1282
1283 /* Put the chip into power-down mode. */
1284 SMC_SELECT_BANK(1);
1285 outw(CTL_POWERDOWN, ioaddr + CONTROL );
1286
1287 link->open--;
1288 del_timer_sync(&smc->media);
1289
1290 return 0;
1291} /* smc_close */
1292
1293/*======================================================================
1294
1295 Transfer a packet to the hardware and trigger the packet send.
1296 This may be called at either from either the Tx queue code
1297 or the interrupt handler.
1298
1299======================================================================*/
1300
1301static void smc_hardware_send_packet(struct net_device * dev)
1302{
1303 struct smc_private *smc = netdev_priv(dev);
1304 struct sk_buff *skb = smc->saved_skb;
Olof Johansson906da802008-02-04 22:27:35 -08001305 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 u_char packet_no;
1307
1308 if (!skb) {
1309 printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name);
1310 return;
1311 }
1312
1313 /* There should be a packet slot waiting. */
1314 packet_no = inw(ioaddr + PNR_ARR) >> 8;
1315 if (packet_no & 0x80) {
1316 /* If not, there is a hardware problem! Likely an ejected card. */
1317 printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation"
1318 " failed, status %#2.2x.\n", dev->name, packet_no);
1319 dev_kfree_skb_irq(skb);
1320 smc->saved_skb = NULL;
1321 netif_start_queue(dev);
1322 return;
1323 }
1324
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001325 dev->stats.tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 /* The card should use the just-allocated buffer. */
1327 outw(packet_no, ioaddr + PNR_ARR);
1328 /* point to the beginning of the packet */
1329 outw(PTR_AUTOINC , ioaddr + POINTER);
1330
1331 /* Send the packet length (+6 for status, length and ctl byte)
1332 and the status word (set to zeros). */
1333 {
1334 u_char *buf = skb->data;
1335 u_int length = skb->len; /* The chip will pad to ethernet min. */
1336
1337 DEBUG(2, "%s: Trying to xmit packet of length %d.\n",
1338 dev->name, length);
1339
1340 /* send the packet length: +6 for status word, length, and ctl */
1341 outw(0, ioaddr + DATA_1);
1342 outw(length + 6, ioaddr + DATA_1);
1343 outsw(ioaddr + DATA_1, buf, length >> 1);
1344
1345 /* The odd last byte, if there is one, goes in the control word. */
1346 outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);
1347 }
1348
1349 /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */
1350 outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |
1351 (inw(ioaddr + INTERRUPT) & 0xff00),
1352 ioaddr + INTERRUPT);
1353
1354 /* The chip does the rest of the work. */
1355 outw(MC_ENQUEUE , ioaddr + MMU_CMD);
1356
1357 smc->saved_skb = NULL;
1358 dev_kfree_skb_irq(skb);
1359 dev->trans_start = jiffies;
1360 netif_start_queue(dev);
1361 return;
1362}
1363
1364/*====================================================================*/
1365
1366static void smc_tx_timeout(struct net_device *dev)
1367{
1368 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001369 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
1371 printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
1372 "Tx_status %2.2x status %4.4x.\n",
1373 dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001374 dev->stats.tx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 smc_reset(dev);
1376 dev->trans_start = jiffies;
1377 smc->saved_skb = NULL;
1378 netif_wake_queue(dev);
1379}
1380
Stephen Hemmingerdbf02fa2009-08-31 19:50:49 +00001381static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
1382 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383{
1384 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001385 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 u_short num_pages;
1387 short time_out, ir;
Komuro85e27832007-07-23 21:36:06 +09001388 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
1390 netif_stop_queue(dev);
1391
1392 DEBUG(2, "%s: smc_start_xmit(length = %d) called,"
1393 " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
1394
1395 if (smc->saved_skb) {
1396 /* THIS SHOULD NEVER HAPPEN. */
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001397 dev->stats.tx_aborted_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",
1399 dev->name);
Patrick McHardy5b548142009-06-12 06:22:29 +00001400 return NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 }
1402 smc->saved_skb = skb;
1403
1404 num_pages = skb->len >> 8;
1405
1406 if (num_pages > 7) {
1407 printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
1408 dev_kfree_skb (skb);
1409 smc->saved_skb = NULL;
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001410 dev->stats.tx_dropped++;
Patrick McHardy6ed10652009-06-23 06:03:08 +00001411 return NETDEV_TX_OK; /* Do not re-queue this packet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 }
1413 /* A packet is now waiting. */
1414 smc->packets_waiting++;
1415
Komuro85e27832007-07-23 21:36:06 +09001416 spin_lock_irqsave(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 SMC_SELECT_BANK(2); /* Paranoia, we should always be in window 2 */
1418
1419 /* need MC_RESET to keep the memory consistent. errata? */
1420 if (smc->rx_ovrn) {
1421 outw(MC_RESET, ioaddr + MMU_CMD);
1422 smc->rx_ovrn = 0;
1423 }
1424
1425 /* Allocate the memory; send the packet now if we win. */
1426 outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);
1427 for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {
1428 ir = inw(ioaddr+INTERRUPT);
1429 if (ir & IM_ALLOC_INT) {
1430 /* Acknowledge the interrupt, send the packet. */
1431 outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
1432 smc_hardware_send_packet(dev); /* Send the packet now.. */
Komuro85e27832007-07-23 21:36:06 +09001433 spin_unlock_irqrestore(&smc->lock, flags);
Patrick McHardy6ed10652009-06-23 06:03:08 +00001434 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 }
1436 }
1437
1438 /* Otherwise defer until the Tx-space-allocated interrupt. */
1439 DEBUG(2, "%s: memory allocation deferred.\n", dev->name);
1440 outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
Komuro85e27832007-07-23 21:36:06 +09001441 spin_unlock_irqrestore(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
Patrick McHardy6ed10652009-06-23 06:03:08 +00001443 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444}
1445
1446/*======================================================================
1447
1448 Handle a Tx anomolous event. Entered while in Window 2.
1449
1450======================================================================*/
1451
1452static void smc_tx_err(struct net_device * dev)
1453{
1454 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001455 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
1457 int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
1458 int tx_status;
1459
1460 /* select this as the packet to read from */
1461 outw(packet_no, ioaddr + PNR_ARR);
1462
1463 /* read the first word from this packet */
1464 outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);
1465
1466 tx_status = inw(ioaddr + DATA_1);
1467
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001468 dev->stats.tx_errors++;
1469 if (tx_status & TS_LOSTCAR) dev->stats.tx_carrier_errors++;
1470 if (tx_status & TS_LATCOL) dev->stats.tx_window_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 if (tx_status & TS_16COL) {
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001472 dev->stats.tx_aborted_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 smc->tx_err++;
1474 }
1475
1476 if (tx_status & TS_SUCCESS) {
1477 printk(KERN_NOTICE "%s: Successful packet caused error "
1478 "interrupt?\n", dev->name);
1479 }
1480 /* re-enable transmit */
1481 SMC_SELECT_BANK(0);
1482 outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
1483 SMC_SELECT_BANK(2);
1484
1485 outw(MC_FREEPKT, ioaddr + MMU_CMD); /* Free the packet memory. */
1486
1487 /* one less packet waiting for me */
1488 smc->packets_waiting--;
1489
1490 outw(saved_packet, ioaddr + PNR_ARR);
1491 return;
1492}
1493
1494/*====================================================================*/
1495
1496static void smc_eph_irq(struct net_device *dev)
1497{
1498 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001499 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 u_short card_stats, ephs;
1501
1502 SMC_SELECT_BANK(0);
1503 ephs = inw(ioaddr + EPH);
1504 DEBUG(2, "%s: Ethernet protocol handler interrupt, status"
1505 " %4.4x.\n", dev->name, ephs);
1506 /* Could be a counter roll-over warning: update stats. */
1507 card_stats = inw(ioaddr + COUNTER);
1508 /* single collisions */
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001509 dev->stats.collisions += card_stats & 0xF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 card_stats >>= 4;
1511 /* multiple collisions */
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001512 dev->stats.collisions += card_stats & 0xF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513#if 0 /* These are for when linux supports these statistics */
1514 card_stats >>= 4; /* deferred */
1515 card_stats >>= 4; /* excess deferred */
1516#endif
1517 /* If we had a transmit error we must re-enable the transmitter. */
1518 outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
1519
1520 /* Clear a link error interrupt. */
1521 SMC_SELECT_BANK(1);
1522 outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL);
1523 outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
1524 ioaddr + CONTROL);
1525 SMC_SELECT_BANK(2);
1526}
1527
1528/*====================================================================*/
1529
David Howells7d12e782006-10-05 14:55:46 +01001530static irqreturn_t smc_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531{
1532 struct net_device *dev = dev_id;
1533 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001534 unsigned int ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 u_short saved_bank, saved_pointer, mask, status;
1536 unsigned int handled = 1;
1537 char bogus_cnt = INTR_WORK; /* Work we are willing to do. */
1538
1539 if (!netif_device_present(dev))
1540 return IRQ_NONE;
1541
1542 ioaddr = dev->base_addr;
1543
1544 DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
1545 irq, ioaddr);
1546
Komuro85e27832007-07-23 21:36:06 +09001547 spin_lock(&smc->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 smc->watchdog = 0;
1549 saved_bank = inw(ioaddr + BANK_SELECT);
1550 if ((saved_bank & 0xff00) != 0x3300) {
1551 /* The device does not exist -- the card could be off-line, or
1552 maybe it has been ejected. */
1553 DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent"
1554 "/ejected device.\n", dev->name, irq);
1555 handled = 0;
1556 goto irq_done;
1557 }
1558
1559 SMC_SELECT_BANK(2);
1560 saved_pointer = inw(ioaddr + POINTER);
1561 mask = inw(ioaddr + INTERRUPT) >> 8;
1562 /* clear all interrupts */
1563 outw(0, ioaddr + INTERRUPT);
1564
1565 do { /* read the status flag, and mask it */
1566 status = inw(ioaddr + INTERRUPT) & 0xff;
1567 DEBUG(3, "%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
1568 status, mask);
1569 if ((status & mask) == 0) {
1570 if (bogus_cnt == INTR_WORK)
1571 handled = 0;
1572 break;
1573 }
1574 if (status & IM_RCV_INT) {
1575 /* Got a packet(s). */
1576 smc_rx(dev);
1577 }
1578 if (status & IM_TX_INT) {
1579 smc_tx_err(dev);
1580 outw(IM_TX_INT, ioaddr + INTERRUPT);
1581 }
1582 status &= mask;
1583 if (status & IM_TX_EMPTY_INT) {
1584 outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT);
1585 mask &= ~IM_TX_EMPTY_INT;
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001586 dev->stats.tx_packets += smc->packets_waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 smc->packets_waiting = 0;
1588 }
1589 if (status & IM_ALLOC_INT) {
1590 /* Clear this interrupt so it doesn't happen again */
1591 mask &= ~IM_ALLOC_INT;
1592
1593 smc_hardware_send_packet(dev);
1594
1595 /* enable xmit interrupts based on this */
1596 mask |= (IM_TX_EMPTY_INT | IM_TX_INT);
1597
1598 /* and let the card send more packets to me */
1599 netif_wake_queue(dev);
1600 }
1601 if (status & IM_RX_OVRN_INT) {
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001602 dev->stats.rx_errors++;
1603 dev->stats.rx_fifo_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 if (smc->duplex)
1605 smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */
1606 outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
1607 }
1608 if (status & IM_EPH_INT)
1609 smc_eph_irq(dev);
1610 } while (--bogus_cnt);
1611
1612 DEBUG(3, " Restoring saved registers mask %2.2x bank %4.4x"
1613 " pointer %4.4x.\n", mask, saved_bank, saved_pointer);
1614
1615 /* restore state register */
1616 outw((mask<<8), ioaddr + INTERRUPT);
1617 outw(saved_pointer, ioaddr + POINTER);
1618 SMC_SELECT_BANK(saved_bank);
1619
1620 DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
1621
1622irq_done:
1623
1624 if ((smc->manfid == MANFID_OSITECH) &&
1625 (smc->cardid != PRODID_OSITECH_SEVEN)) {
1626 /* Retrigger interrupt if needed */
1627 mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR);
1628 set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR);
1629 }
1630 if (smc->manfid == MANFID_MOTOROLA) {
1631 u_char cor;
1632 cor = readb(smc->base + MOT_UART + CISREG_COR);
1633 writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR);
1634 writeb(cor, smc->base + MOT_UART + CISREG_COR);
1635 cor = readb(smc->base + MOT_LAN + CISREG_COR);
1636 writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR);
1637 writeb(cor, smc->base + MOT_LAN + CISREG_COR);
1638 }
1639#ifdef DOES_NOT_WORK
1640 if (smc->base != NULL) { /* Megahertz MFC's */
1641 readb(smc->base+MEGAHERTZ_ISR);
1642 readb(smc->base+MEGAHERTZ_ISR);
1643 }
1644#endif
Komuro85e27832007-07-23 21:36:06 +09001645 spin_unlock(&smc->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 return IRQ_RETVAL(handled);
1647}
1648
1649/*====================================================================*/
1650
1651static void smc_rx(struct net_device *dev)
1652{
Olof Johansson906da802008-02-04 22:27:35 -08001653 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 int rx_status;
1655 int packet_length; /* Caution: not frame length, rather words
1656 to transfer from the chip. */
1657
1658 /* Assertion: we are in Window 2. */
1659
1660 if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
1661 printk(KERN_ERR "%s: smc_rx() with nothing on Rx FIFO.\n",
1662 dev->name);
1663 return;
1664 }
1665
1666 /* Reset the read pointer, and read the status and packet length. */
1667 outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER);
1668 rx_status = inw(ioaddr + DATA_1);
1669 packet_length = inw(ioaddr + DATA_1) & 0x07ff;
1670
1671 DEBUG(2, "%s: Receive status %4.4x length %d.\n",
1672 dev->name, rx_status, packet_length);
1673
1674 if (!(rx_status & RS_ERRORS)) {
1675 /* do stuff to make a new packet */
1676 struct sk_buff *skb;
1677
1678 /* Note: packet_length adds 5 or 6 extra bytes here! */
1679 skb = dev_alloc_skb(packet_length+2);
1680
1681 if (skb == NULL) {
1682 DEBUG(1, "%s: Low memory, packet dropped.\n", dev->name);
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001683 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 outw(MC_RELEASE, ioaddr + MMU_CMD);
1685 return;
1686 }
1687
1688 packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6);
1689 skb_reserve(skb, 2);
1690 insw(ioaddr+DATA_1, skb_put(skb, packet_length),
1691 (packet_length+1)>>1);
1692 skb->protocol = eth_type_trans(skb, dev);
1693
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 netif_rx(skb);
1695 dev->last_rx = jiffies;
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001696 dev->stats.rx_packets++;
1697 dev->stats.rx_bytes += packet_length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 if (rx_status & RS_MULTICAST)
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001699 dev->stats.multicast++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 } else {
1701 /* error ... */
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001702 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001704 if (rx_status & RS_ALGNERR) dev->stats.rx_frame_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 if (rx_status & (RS_TOOSHORT | RS_TOOLONG))
Stephen Hemminger6fb72982009-03-20 19:36:09 +00001706 dev->stats.rx_length_errors++;
1707 if (rx_status & RS_BADCRC) dev->stats.rx_crc_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 }
1709 /* Let the MMU free the memory of this packet. */
1710 outw(MC_RELEASE, ioaddr + MMU_CMD);
1711
1712 return;
1713}
1714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715/*======================================================================
1716
1717 Calculate values for the hardware multicast filter hash table.
1718
1719======================================================================*/
1720
1721static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
1722 u_char *multicast_table)
1723{
1724 struct dev_mc_list *mc_addr;
1725
Komurobb53d6d2005-10-03 22:03:28 -04001726 for (mc_addr = addrs; mc_addr && count-- > 0; mc_addr = mc_addr->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 u_int position = ether_crc(6, mc_addr->dmi_addr);
1728#ifndef final_version /* Verify multicast address. */
1729 if ((mc_addr->dmi_addr[0] & 1) == 0)
1730 continue;
1731#endif
1732 multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
1733 }
1734}
1735
1736/*======================================================================
1737
1738 Set the receive mode.
1739
1740 This routine is used by both the protocol level to notify us of
1741 promiscuous/multicast mode changes, and by the open/reset code to
1742 initialize the Rx registers. We always set the multicast list and
1743 leave the receiver running.
1744
1745======================================================================*/
1746
1747static void set_rx_mode(struct net_device *dev)
1748{
Olof Johansson906da802008-02-04 22:27:35 -08001749 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 struct smc_private *smc = netdev_priv(dev);
1751 u_int multicast_table[ 2 ] = { 0, };
1752 unsigned long flags;
1753 u_short rx_cfg_setting;
1754
1755 if (dev->flags & IFF_PROMISC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
1757 } else if (dev->flags & IFF_ALLMULTI)
1758 rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
1759 else {
1760 if (dev->mc_count) {
1761 fill_multicast_tbl(dev->mc_count, dev->mc_list,
1762 (u_char *)multicast_table);
1763 }
1764 rx_cfg_setting = RxStripCRC | RxEnable;
1765 }
1766
1767 /* Load MC table and Rx setting into the chip without interrupts. */
1768 spin_lock_irqsave(&smc->lock, flags);
1769 SMC_SELECT_BANK(3);
1770 outl(multicast_table[0], ioaddr + MULTICAST0);
1771 outl(multicast_table[1], ioaddr + MULTICAST4);
1772 SMC_SELECT_BANK(0);
1773 outw(rx_cfg_setting, ioaddr + RCR);
1774 SMC_SELECT_BANK(2);
1775 spin_unlock_irqrestore(&smc->lock, flags);
1776
1777 return;
1778}
1779
1780/*======================================================================
1781
1782 Senses when a card's config changes. Here, it's coax or TP.
1783
1784======================================================================*/
1785
1786static int s9k_config(struct net_device *dev, struct ifmap *map)
1787{
1788 struct smc_private *smc = netdev_priv(dev);
1789 if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
1790 if (smc->cfg & CFG_MII_SELECT)
1791 return -EOPNOTSUPP;
1792 else if (map->port > 2)
1793 return -EINVAL;
1794 dev->if_port = map->port;
1795 printk(KERN_INFO "%s: switched to %s port\n",
1796 dev->name, if_names[dev->if_port]);
1797 smc_reset(dev);
1798 }
1799 return 0;
1800}
1801
1802/*======================================================================
1803
1804 Reset the chip, reloading every register that might be corrupted.
1805
1806======================================================================*/
1807
1808/*
1809 Set transceiver type, perhaps to something other than what the user
1810 specified in dev->if_port.
1811*/
1812static void smc_set_xcvr(struct net_device *dev, int if_port)
1813{
1814 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001815 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 u_short saved_bank;
1817
1818 saved_bank = inw(ioaddr + BANK_SELECT);
1819 SMC_SELECT_BANK(1);
1820 if (if_port == 2) {
1821 outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG);
1822 if ((smc->manfid == MANFID_OSITECH) &&
1823 (smc->cardid != PRODID_OSITECH_SEVEN))
1824 set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
1825 smc->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002);
1826 } else {
1827 outw(smc->cfg, ioaddr + CONFIG);
1828 if ((smc->manfid == MANFID_OSITECH) &&
1829 (smc->cardid != PRODID_OSITECH_SEVEN))
1830 mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
1831 smc->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001);
1832 }
1833 SMC_SELECT_BANK(saved_bank);
1834}
1835
1836static void smc_reset(struct net_device *dev)
1837{
Olof Johansson906da802008-02-04 22:27:35 -08001838 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 struct smc_private *smc = netdev_priv(dev);
1840 int i;
1841
1842 DEBUG(0, "%s: smc91c92 reset called.\n", dev->name);
1843
1844 /* The first interaction must be a write to bring the chip out
1845 of sleep mode. */
1846 SMC_SELECT_BANK(0);
1847 /* Reset the chip. */
1848 outw(RCR_SOFTRESET, ioaddr + RCR);
1849 udelay(10);
1850
1851 /* Clear the transmit and receive configuration registers. */
1852 outw(RCR_CLEAR, ioaddr + RCR);
1853 outw(TCR_CLEAR, ioaddr + TCR);
1854
1855 /* Set the Window 1 control, configuration and station addr registers.
1856 No point in writing the I/O base register ;-> */
1857 SMC_SELECT_BANK(1);
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001858 /* Automatically release successfully transmitted packets,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 Accept link errors, counter and Tx error interrupts. */
1860 outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
1861 ioaddr + CONTROL);
1862 smc_set_xcvr(dev, dev->if_port);
1863 if ((smc->manfid == MANFID_OSITECH) &&
1864 (smc->cardid != PRODID_OSITECH_SEVEN))
1865 outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |
1866 (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),
1867 ioaddr - 0x10 + OSITECH_AUI_PWR);
1868
1869 /* Fill in the physical address. The databook is wrong about the order! */
1870 for (i = 0; i < 6; i += 2)
1871 outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i],
1872 ioaddr + ADDR0 + i);
1873
1874 /* Reset the MMU */
1875 SMC_SELECT_BANK(2);
1876 outw(MC_RESET, ioaddr + MMU_CMD);
1877 outw(0, ioaddr + INTERRUPT);
1878
1879 /* Re-enable the chip. */
1880 SMC_SELECT_BANK(0);
1881 outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
1882 TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR);
1883 set_rx_mode(dev);
1884
1885 if (smc->cfg & CFG_MII_SELECT) {
1886 SMC_SELECT_BANK(3);
1887
1888 /* Reset MII */
1889 mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
1890
1891 /* Advertise 100F, 100H, 10F, 10H */
1892 mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1);
1893
1894 /* Restart MII autonegotiation */
1895 mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
1896 mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
1897 }
1898
1899 /* Enable interrupts. */
1900 SMC_SELECT_BANK(2);
1901 outw((IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8,
1902 ioaddr + INTERRUPT);
1903}
1904
1905/*======================================================================
1906
1907 Media selection timer routine
1908
1909======================================================================*/
1910
1911static void media_check(u_long arg)
1912{
1913 struct net_device *dev = (struct net_device *) arg;
1914 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001915 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 u_short i, media, saved_bank;
1917 u_short link;
Komuro85e27832007-07-23 21:36:06 +09001918 unsigned long flags;
1919
1920 spin_lock_irqsave(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
1922 saved_bank = inw(ioaddr + BANK_SELECT);
1923
1924 if (!netif_device_present(dev))
1925 goto reschedule;
1926
1927 SMC_SELECT_BANK(2);
1928
1929 /* need MC_RESET to keep the memory consistent. errata? */
1930 if (smc->rx_ovrn) {
1931 outw(MC_RESET, ioaddr + MMU_CMD);
1932 smc->rx_ovrn = 0;
1933 }
1934 i = inw(ioaddr + INTERRUPT);
1935 SMC_SELECT_BANK(0);
1936 media = inw(ioaddr + EPH) & EPH_LINK_OK;
1937 SMC_SELECT_BANK(1);
1938 media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;
1939
1940 /* Check for pending interrupt with watchdog flag set: with
1941 this, we can limp along even if the interrupt is blocked */
1942 if (smc->watchdog++ && ((i>>8) & i)) {
1943 if (!smc->fast_poll)
1944 printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
Komuroe363d132007-02-10 11:57:35 +09001945 smc_interrupt(dev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 smc->fast_poll = HZ;
1947 }
1948 if (smc->fast_poll) {
1949 smc->fast_poll--;
1950 smc->media.expires = jiffies + HZ/100;
1951 add_timer(&smc->media);
1952 SMC_SELECT_BANK(saved_bank);
Komuro85e27832007-07-23 21:36:06 +09001953 spin_unlock_irqrestore(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 return;
1955 }
1956
1957 if (smc->cfg & CFG_MII_SELECT) {
1958 if (smc->mii_if.phy_id < 0)
1959 goto reschedule;
1960
1961 SMC_SELECT_BANK(3);
1962 link = mdio_read(dev, smc->mii_if.phy_id, 1);
1963 if (!link || (link == 0xffff)) {
1964 printk(KERN_INFO "%s: MII is missing!\n", dev->name);
1965 smc->mii_if.phy_id = -1;
1966 goto reschedule;
1967 }
1968
1969 link &= 0x0004;
1970 if (link != smc->link_status) {
1971 u_short p = mdio_read(dev, smc->mii_if.phy_id, 5);
1972 printk(KERN_INFO "%s: %s link beat\n", dev->name,
1973 (link) ? "found" : "lost");
1974 smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40))
1975 ? TCR_FDUPLX : 0);
1976 if (link) {
1977 printk(KERN_INFO "%s: autonegotiation complete: "
1978 "%sbaseT-%cD selected\n", dev->name,
1979 ((p & 0x0180) ? "100" : "10"),
1980 (smc->duplex ? 'F' : 'H'));
1981 }
1982 SMC_SELECT_BANK(0);
1983 outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR);
1984 smc->link_status = link;
1985 }
1986 goto reschedule;
1987 }
1988
1989 /* Ignore collisions unless we've had no rx's recently */
Marcelo Feitoza Parisi4851d3a2005-07-15 10:00:41 -07001990 if (time_after(jiffies, dev->last_rx + HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 if (smc->tx_err || (smc->media_status & EPH_16COL))
1992 media |= EPH_16COL;
1993 }
1994 smc->tx_err = 0;
1995
1996 if (media != smc->media_status) {
1997 if ((media & smc->media_status & 1) &&
1998 ((smc->media_status ^ media) & EPH_LINK_OK))
1999 printk(KERN_INFO "%s: %s link beat\n", dev->name,
2000 (smc->media_status & EPH_LINK_OK ? "lost" : "found"));
2001 else if ((media & smc->media_status & 2) &&
2002 ((smc->media_status ^ media) & EPH_16COL))
2003 printk(KERN_INFO "%s: coax cable %s\n", dev->name,
2004 (media & EPH_16COL ? "problem" : "ok"));
2005 if (dev->if_port == 0) {
2006 if (media & 1) {
2007 if (media & EPH_LINK_OK)
2008 printk(KERN_INFO "%s: flipped to 10baseT\n",
2009 dev->name);
2010 else
2011 smc_set_xcvr(dev, 2);
2012 } else {
2013 if (media & EPH_16COL)
2014 smc_set_xcvr(dev, 1);
2015 else
2016 printk(KERN_INFO "%s: flipped to 10base2\n",
2017 dev->name);
2018 }
2019 }
2020 smc->media_status = media;
2021 }
2022
2023reschedule:
2024 smc->media.expires = jiffies + HZ;
2025 add_timer(&smc->media);
2026 SMC_SELECT_BANK(saved_bank);
Komuro85e27832007-07-23 21:36:06 +09002027 spin_unlock_irqrestore(&smc->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028}
2029
2030static int smc_link_ok(struct net_device *dev)
2031{
Olof Johansson906da802008-02-04 22:27:35 -08002032 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 struct smc_private *smc = netdev_priv(dev);
2034
2035 if (smc->cfg & CFG_MII_SELECT) {
2036 return mii_link_ok(&smc->mii_if);
2037 } else {
2038 SMC_SELECT_BANK(0);
2039 return inw(ioaddr + EPH) & EPH_LINK_OK;
2040 }
2041}
2042
2043static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
2044{
2045 u16 tmp;
Olof Johansson906da802008-02-04 22:27:35 -08002046 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047
2048 ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |
2049 SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
2050
2051 SMC_SELECT_BANK(1);
2052 tmp = inw(ioaddr + CONFIG);
2053 ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP;
2054 ecmd->transceiver = XCVR_INTERNAL;
2055 ecmd->speed = SPEED_10;
2056 ecmd->phy_address = ioaddr + MGMT;
2057
2058 SMC_SELECT_BANK(0);
2059 tmp = inw(ioaddr + TCR);
2060 ecmd->duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF;
2061
2062 return 0;
2063}
2064
2065static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
2066{
2067 u16 tmp;
Olof Johansson906da802008-02-04 22:27:35 -08002068 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
2070 if (ecmd->speed != SPEED_10)
2071 return -EINVAL;
2072 if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
2073 return -EINVAL;
2074 if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI)
2075 return -EINVAL;
2076 if (ecmd->transceiver != XCVR_INTERNAL)
2077 return -EINVAL;
2078
2079 if (ecmd->port == PORT_AUI)
2080 smc_set_xcvr(dev, 1);
2081 else
2082 smc_set_xcvr(dev, 0);
2083
2084 SMC_SELECT_BANK(0);
2085 tmp = inw(ioaddr + TCR);
2086 if (ecmd->duplex == DUPLEX_FULL)
2087 tmp |= TCR_FDUPLX;
2088 else
2089 tmp &= ~TCR_FDUPLX;
2090 outw(tmp, ioaddr + TCR);
2091
2092 return 0;
2093}
2094
2095static int check_if_running(struct net_device *dev)
2096{
2097 if (!netif_running(dev))
2098 return -EINVAL;
2099 return 0;
2100}
2101
2102static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
2103{
2104 strcpy(info->driver, DRV_NAME);
2105 strcpy(info->version, DRV_VERSION);
2106}
2107
2108static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
2109{
2110 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08002111 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 u16 saved_bank = inw(ioaddr + BANK_SELECT);
2113 int ret;
2114
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 spin_lock_irq(&smc->lock);
Komuro85e27832007-07-23 21:36:06 +09002116 SMC_SELECT_BANK(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 if (smc->cfg & CFG_MII_SELECT)
2118 ret = mii_ethtool_gset(&smc->mii_if, ecmd);
2119 else
2120 ret = smc_netdev_get_ecmd(dev, ecmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 SMC_SELECT_BANK(saved_bank);
Komuro85e27832007-07-23 21:36:06 +09002122 spin_unlock_irq(&smc->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 return ret;
2124}
2125
2126static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
2127{
2128 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08002129 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 u16 saved_bank = inw(ioaddr + BANK_SELECT);
2131 int ret;
2132
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 spin_lock_irq(&smc->lock);
Komuro85e27832007-07-23 21:36:06 +09002134 SMC_SELECT_BANK(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 if (smc->cfg & CFG_MII_SELECT)
2136 ret = mii_ethtool_sset(&smc->mii_if, ecmd);
2137 else
2138 ret = smc_netdev_set_ecmd(dev, ecmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 SMC_SELECT_BANK(saved_bank);
Komuro85e27832007-07-23 21:36:06 +09002140 spin_unlock_irq(&smc->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 return ret;
2142}
2143
2144static u32 smc_get_link(struct net_device *dev)
2145{
2146 struct smc_private *smc = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08002147 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 u16 saved_bank = inw(ioaddr + BANK_SELECT);
2149 u32 ret;
2150
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 spin_lock_irq(&smc->lock);
Komuro85e27832007-07-23 21:36:06 +09002152 SMC_SELECT_BANK(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 ret = smc_link_ok(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 SMC_SELECT_BANK(saved_bank);
Komuro85e27832007-07-23 21:36:06 +09002155 spin_unlock_irq(&smc->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 return ret;
2157}
2158
2159#ifdef PCMCIA_DEBUG
2160static u32 smc_get_msglevel(struct net_device *dev)
2161{
2162 return pc_debug;
2163}
2164
2165static void smc_set_msglevel(struct net_device *dev, u32 val)
2166{
2167 pc_debug = val;
2168}
2169#endif
2170
2171static int smc_nway_reset(struct net_device *dev)
2172{
2173 struct smc_private *smc = netdev_priv(dev);
2174 if (smc->cfg & CFG_MII_SELECT) {
Olof Johansson906da802008-02-04 22:27:35 -08002175 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 u16 saved_bank = inw(ioaddr + BANK_SELECT);
2177 int res;
2178
2179 SMC_SELECT_BANK(3);
2180 res = mii_nway_restart(&smc->mii_if);
2181 SMC_SELECT_BANK(saved_bank);
2182
2183 return res;
2184 } else
2185 return -EOPNOTSUPP;
2186}
2187
Jeff Garzik7282d492006-09-13 14:30:00 -04002188static const struct ethtool_ops ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 .begin = check_if_running,
2190 .get_drvinfo = smc_get_drvinfo,
2191 .get_settings = smc_get_settings,
2192 .set_settings = smc_set_settings,
2193 .get_link = smc_get_link,
2194#ifdef PCMCIA_DEBUG
2195 .get_msglevel = smc_get_msglevel,
2196 .set_msglevel = smc_set_msglevel,
2197#endif
2198 .nway_reset = smc_nway_reset,
2199};
2200
2201static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
2202{
2203 struct smc_private *smc = netdev_priv(dev);
2204 struct mii_ioctl_data *mii = if_mii(rq);
2205 int rc = 0;
2206 u16 saved_bank;
Olof Johansson906da802008-02-04 22:27:35 -08002207 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208
2209 if (!netif_running(dev))
2210 return -EINVAL;
2211
2212 spin_lock_irq(&smc->lock);
2213 saved_bank = inw(ioaddr + BANK_SELECT);
2214 SMC_SELECT_BANK(3);
2215 rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
2216 SMC_SELECT_BANK(saved_bank);
2217 spin_unlock_irq(&smc->lock);
2218 return rc;
2219}
2220
Dominik Brodowski5c672222005-06-27 16:28:27 -07002221static struct pcmcia_device_id smc91c92_ids[] = {
2222 PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
2223 PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
2224 PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
2225 PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
2226 PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
2227 PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
2228 PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
2229 PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
Komurod277ad02005-07-28 01:07:24 -07002230 PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
2231 PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
Dominik Brodowski5c672222005-06-27 16:28:27 -07002232 PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020),
2233 PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023),
2234 PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb),
2235 PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc),
2236 PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1),
2237 PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5),
2238 PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9),
2239 PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953),
2240 PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a),
Komurod277ad02005-07-28 01:07:24 -07002241 PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Four of Diamonds Ethernet", 0xc2f80cd, 0xb3466314),
2242 PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Seven of Diamonds Ethernet", 0xc2f80cd, 0x194b650a),
Dominik Brodowski5c672222005-06-27 16:28:27 -07002243 PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc),
2244 PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9),
2245 PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d),
2246 /* These conflict with other cards! */
2247 /* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */
2248 /* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */
2249 PCMCIA_DEVICE_NULL,
2250};
2251MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids);
2252
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253static struct pcmcia_driver smc91c92_cs_driver = {
2254 .owner = THIS_MODULE,
2255 .drv = {
2256 .name = "smc91c92_cs",
2257 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02002258 .probe = smc91c92_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +01002259 .remove = smc91c92_detach,
Dominik Brodowski5c672222005-06-27 16:28:27 -07002260 .id_table = smc91c92_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +01002261 .suspend = smc91c92_suspend,
2262 .resume = smc91c92_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263};
2264
2265static int __init init_smc91c92_cs(void)
2266{
2267 return pcmcia_register_driver(&smc91c92_cs_driver);
2268}
2269
2270static void __exit exit_smc91c92_cs(void)
2271{
2272 pcmcia_unregister_driver(&smc91c92_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273}
2274
2275module_init(init_smc91c92_cs);
2276module_exit(exit_smc91c92_cs);