| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 1 | /** | 
 | 2 |  * drivers/net/ksx884x.c - Micrel KSZ8841/2 PCI Ethernet driver | 
 | 3 |  * | 
 | 4 |  * Copyright (c) 2009-2010 Micrel, Inc. | 
 | 5 |  * 	Tristram Ha <Tristram.Ha@micrel.com> | 
 | 6 |  * | 
 | 7 |  * This program is free software; you can redistribute it and/or modify | 
 | 8 |  * it under the terms of the GNU General Public License version 2 as | 
 | 9 |  * published by the Free Software Foundation. | 
 | 10 |  * | 
 | 11 |  * This program is distributed in the hope that it will be useful, | 
 | 12 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 13 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 14 |  * GNU General Public License for more details. | 
 | 15 |  */ | 
 | 16 |  | 
| Joe Perches | 0dc7d2b | 2010-02-27 14:43:51 +0000 | [diff] [blame] | 17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 
 | 18 |  | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 19 | #include <linux/init.h> | 
| Alexey Dobriyan | a6b7a40 | 2011-06-06 10:43:46 +0000 | [diff] [blame] | 20 | #include <linux/interrupt.h> | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 21 | #include <linux/kernel.h> | 
 | 22 | #include <linux/module.h> | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 23 | #include <linux/ioport.h> | 
 | 24 | #include <linux/pci.h> | 
 | 25 | #include <linux/proc_fs.h> | 
 | 26 | #include <linux/mii.h> | 
 | 27 | #include <linux/platform_device.h> | 
 | 28 | #include <linux/ethtool.h> | 
 | 29 | #include <linux/etherdevice.h> | 
 | 30 | #include <linux/in.h> | 
 | 31 | #include <linux/ip.h> | 
 | 32 | #include <linux/if_vlan.h> | 
 | 33 | #include <linux/crc32.h> | 
 | 34 | #include <linux/sched.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 35 | #include <linux/slab.h> | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 36 |  | 
 | 37 |  | 
 | 38 | /* DMA Registers */ | 
 | 39 |  | 
 | 40 | #define KS_DMA_TX_CTRL			0x0000 | 
 | 41 | #define DMA_TX_ENABLE			0x00000001 | 
 | 42 | #define DMA_TX_CRC_ENABLE		0x00000002 | 
 | 43 | #define DMA_TX_PAD_ENABLE		0x00000004 | 
 | 44 | #define DMA_TX_LOOPBACK			0x00000100 | 
 | 45 | #define DMA_TX_FLOW_ENABLE		0x00000200 | 
 | 46 | #define DMA_TX_CSUM_IP			0x00010000 | 
 | 47 | #define DMA_TX_CSUM_TCP			0x00020000 | 
 | 48 | #define DMA_TX_CSUM_UDP			0x00040000 | 
 | 49 | #define DMA_TX_BURST_SIZE		0x3F000000 | 
 | 50 |  | 
 | 51 | #define KS_DMA_RX_CTRL			0x0004 | 
 | 52 | #define DMA_RX_ENABLE			0x00000001 | 
 | 53 | #define KS884X_DMA_RX_MULTICAST		0x00000002 | 
 | 54 | #define DMA_RX_PROMISCUOUS		0x00000004 | 
 | 55 | #define DMA_RX_ERROR			0x00000008 | 
 | 56 | #define DMA_RX_UNICAST			0x00000010 | 
 | 57 | #define DMA_RX_ALL_MULTICAST		0x00000020 | 
 | 58 | #define DMA_RX_BROADCAST		0x00000040 | 
 | 59 | #define DMA_RX_FLOW_ENABLE		0x00000200 | 
 | 60 | #define DMA_RX_CSUM_IP			0x00010000 | 
 | 61 | #define DMA_RX_CSUM_TCP			0x00020000 | 
 | 62 | #define DMA_RX_CSUM_UDP			0x00040000 | 
 | 63 | #define DMA_RX_BURST_SIZE		0x3F000000 | 
 | 64 |  | 
 | 65 | #define DMA_BURST_SHIFT			24 | 
 | 66 | #define DMA_BURST_DEFAULT		8 | 
 | 67 |  | 
 | 68 | #define KS_DMA_TX_START			0x0008 | 
 | 69 | #define KS_DMA_RX_START			0x000C | 
 | 70 | #define DMA_START			0x00000001 | 
 | 71 |  | 
 | 72 | #define KS_DMA_TX_ADDR			0x0010 | 
 | 73 | #define KS_DMA_RX_ADDR			0x0014 | 
 | 74 |  | 
 | 75 | #define DMA_ADDR_LIST_MASK		0xFFFFFFFC | 
 | 76 | #define DMA_ADDR_LIST_SHIFT		2 | 
 | 77 |  | 
 | 78 | /* MTR0 */ | 
 | 79 | #define KS884X_MULTICAST_0_OFFSET	0x0020 | 
 | 80 | #define KS884X_MULTICAST_1_OFFSET	0x0021 | 
 | 81 | #define KS884X_MULTICAST_2_OFFSET	0x0022 | 
 | 82 | #define KS884x_MULTICAST_3_OFFSET	0x0023 | 
 | 83 | /* MTR1 */ | 
 | 84 | #define KS884X_MULTICAST_4_OFFSET	0x0024 | 
 | 85 | #define KS884X_MULTICAST_5_OFFSET	0x0025 | 
 | 86 | #define KS884X_MULTICAST_6_OFFSET	0x0026 | 
 | 87 | #define KS884X_MULTICAST_7_OFFSET	0x0027 | 
 | 88 |  | 
 | 89 | /* Interrupt Registers */ | 
 | 90 |  | 
 | 91 | /* INTEN */ | 
 | 92 | #define KS884X_INTERRUPTS_ENABLE	0x0028 | 
 | 93 | /* INTST */ | 
 | 94 | #define KS884X_INTERRUPTS_STATUS	0x002C | 
 | 95 |  | 
 | 96 | #define KS884X_INT_RX_STOPPED		0x02000000 | 
 | 97 | #define KS884X_INT_TX_STOPPED		0x04000000 | 
 | 98 | #define KS884X_INT_RX_OVERRUN		0x08000000 | 
 | 99 | #define KS884X_INT_TX_EMPTY		0x10000000 | 
 | 100 | #define KS884X_INT_RX			0x20000000 | 
 | 101 | #define KS884X_INT_TX			0x40000000 | 
 | 102 | #define KS884X_INT_PHY			0x80000000 | 
 | 103 |  | 
 | 104 | #define KS884X_INT_RX_MASK		\ | 
 | 105 | 	(KS884X_INT_RX | KS884X_INT_RX_OVERRUN) | 
 | 106 | #define KS884X_INT_TX_MASK		\ | 
 | 107 | 	(KS884X_INT_TX | KS884X_INT_TX_EMPTY) | 
 | 108 | #define KS884X_INT_MASK	(KS884X_INT_RX | KS884X_INT_TX | KS884X_INT_PHY) | 
 | 109 |  | 
 | 110 | /* MAC Additional Station Address */ | 
 | 111 |  | 
 | 112 | /* MAAL0 */ | 
 | 113 | #define KS_ADD_ADDR_0_LO		0x0080 | 
 | 114 | /* MAAH0 */ | 
 | 115 | #define KS_ADD_ADDR_0_HI		0x0084 | 
 | 116 | /* MAAL1 */ | 
 | 117 | #define KS_ADD_ADDR_1_LO		0x0088 | 
 | 118 | /* MAAH1 */ | 
 | 119 | #define KS_ADD_ADDR_1_HI		0x008C | 
 | 120 | /* MAAL2 */ | 
 | 121 | #define KS_ADD_ADDR_2_LO		0x0090 | 
 | 122 | /* MAAH2 */ | 
 | 123 | #define KS_ADD_ADDR_2_HI		0x0094 | 
 | 124 | /* MAAL3 */ | 
 | 125 | #define KS_ADD_ADDR_3_LO		0x0098 | 
 | 126 | /* MAAH3 */ | 
 | 127 | #define KS_ADD_ADDR_3_HI		0x009C | 
 | 128 | /* MAAL4 */ | 
 | 129 | #define KS_ADD_ADDR_4_LO		0x00A0 | 
 | 130 | /* MAAH4 */ | 
 | 131 | #define KS_ADD_ADDR_4_HI		0x00A4 | 
 | 132 | /* MAAL5 */ | 
 | 133 | #define KS_ADD_ADDR_5_LO		0x00A8 | 
 | 134 | /* MAAH5 */ | 
 | 135 | #define KS_ADD_ADDR_5_HI		0x00AC | 
 | 136 | /* MAAL6 */ | 
 | 137 | #define KS_ADD_ADDR_6_LO		0x00B0 | 
 | 138 | /* MAAH6 */ | 
 | 139 | #define KS_ADD_ADDR_6_HI		0x00B4 | 
 | 140 | /* MAAL7 */ | 
 | 141 | #define KS_ADD_ADDR_7_LO		0x00B8 | 
 | 142 | /* MAAH7 */ | 
 | 143 | #define KS_ADD_ADDR_7_HI		0x00BC | 
 | 144 | /* MAAL8 */ | 
 | 145 | #define KS_ADD_ADDR_8_LO		0x00C0 | 
 | 146 | /* MAAH8 */ | 
 | 147 | #define KS_ADD_ADDR_8_HI		0x00C4 | 
 | 148 | /* MAAL9 */ | 
 | 149 | #define KS_ADD_ADDR_9_LO		0x00C8 | 
 | 150 | /* MAAH9 */ | 
 | 151 | #define KS_ADD_ADDR_9_HI		0x00CC | 
 | 152 | /* MAAL10 */ | 
 | 153 | #define KS_ADD_ADDR_A_LO		0x00D0 | 
 | 154 | /* MAAH10 */ | 
 | 155 | #define KS_ADD_ADDR_A_HI		0x00D4 | 
 | 156 | /* MAAL11 */ | 
 | 157 | #define KS_ADD_ADDR_B_LO		0x00D8 | 
 | 158 | /* MAAH11 */ | 
 | 159 | #define KS_ADD_ADDR_B_HI		0x00DC | 
 | 160 | /* MAAL12 */ | 
 | 161 | #define KS_ADD_ADDR_C_LO		0x00E0 | 
 | 162 | /* MAAH12 */ | 
 | 163 | #define KS_ADD_ADDR_C_HI		0x00E4 | 
 | 164 | /* MAAL13 */ | 
 | 165 | #define KS_ADD_ADDR_D_LO		0x00E8 | 
 | 166 | /* MAAH13 */ | 
 | 167 | #define KS_ADD_ADDR_D_HI		0x00EC | 
 | 168 | /* MAAL14 */ | 
 | 169 | #define KS_ADD_ADDR_E_LO		0x00F0 | 
 | 170 | /* MAAH14 */ | 
 | 171 | #define KS_ADD_ADDR_E_HI		0x00F4 | 
 | 172 | /* MAAL15 */ | 
 | 173 | #define KS_ADD_ADDR_F_LO		0x00F8 | 
 | 174 | /* MAAH15 */ | 
 | 175 | #define KS_ADD_ADDR_F_HI		0x00FC | 
 | 176 |  | 
 | 177 | #define ADD_ADDR_HI_MASK		0x0000FFFF | 
 | 178 | #define ADD_ADDR_ENABLE			0x80000000 | 
 | 179 | #define ADD_ADDR_INCR			8 | 
 | 180 |  | 
 | 181 | /* Miscellaneous Registers */ | 
 | 182 |  | 
 | 183 | /* MARL */ | 
 | 184 | #define KS884X_ADDR_0_OFFSET		0x0200 | 
 | 185 | #define KS884X_ADDR_1_OFFSET		0x0201 | 
 | 186 | /* MARM */ | 
 | 187 | #define KS884X_ADDR_2_OFFSET		0x0202 | 
 | 188 | #define KS884X_ADDR_3_OFFSET		0x0203 | 
 | 189 | /* MARH */ | 
 | 190 | #define KS884X_ADDR_4_OFFSET		0x0204 | 
 | 191 | #define KS884X_ADDR_5_OFFSET		0x0205 | 
 | 192 |  | 
 | 193 | /* OBCR */ | 
 | 194 | #define KS884X_BUS_CTRL_OFFSET		0x0210 | 
 | 195 |  | 
 | 196 | #define BUS_SPEED_125_MHZ		0x0000 | 
 | 197 | #define BUS_SPEED_62_5_MHZ		0x0001 | 
 | 198 | #define BUS_SPEED_41_66_MHZ		0x0002 | 
 | 199 | #define BUS_SPEED_25_MHZ		0x0003 | 
 | 200 |  | 
 | 201 | /* EEPCR */ | 
 | 202 | #define KS884X_EEPROM_CTRL_OFFSET	0x0212 | 
 | 203 |  | 
 | 204 | #define EEPROM_CHIP_SELECT		0x0001 | 
 | 205 | #define EEPROM_SERIAL_CLOCK		0x0002 | 
 | 206 | #define EEPROM_DATA_OUT			0x0004 | 
 | 207 | #define EEPROM_DATA_IN			0x0008 | 
 | 208 | #define EEPROM_ACCESS_ENABLE		0x0010 | 
 | 209 |  | 
 | 210 | /* MBIR */ | 
 | 211 | #define KS884X_MEM_INFO_OFFSET		0x0214 | 
 | 212 |  | 
 | 213 | #define RX_MEM_TEST_FAILED		0x0008 | 
 | 214 | #define RX_MEM_TEST_FINISHED		0x0010 | 
 | 215 | #define TX_MEM_TEST_FAILED		0x0800 | 
 | 216 | #define TX_MEM_TEST_FINISHED		0x1000 | 
 | 217 |  | 
 | 218 | /* GCR */ | 
 | 219 | #define KS884X_GLOBAL_CTRL_OFFSET	0x0216 | 
 | 220 | #define GLOBAL_SOFTWARE_RESET		0x0001 | 
 | 221 |  | 
 | 222 | #define KS8841_POWER_MANAGE_OFFSET	0x0218 | 
 | 223 |  | 
 | 224 | /* WFCR */ | 
 | 225 | #define KS8841_WOL_CTRL_OFFSET		0x021A | 
 | 226 | #define KS8841_WOL_MAGIC_ENABLE		0x0080 | 
 | 227 | #define KS8841_WOL_FRAME3_ENABLE	0x0008 | 
 | 228 | #define KS8841_WOL_FRAME2_ENABLE	0x0004 | 
 | 229 | #define KS8841_WOL_FRAME1_ENABLE	0x0002 | 
 | 230 | #define KS8841_WOL_FRAME0_ENABLE	0x0001 | 
 | 231 |  | 
 | 232 | /* WF0 */ | 
 | 233 | #define KS8841_WOL_FRAME_CRC_OFFSET	0x0220 | 
 | 234 | #define KS8841_WOL_FRAME_BYTE0_OFFSET	0x0224 | 
 | 235 | #define KS8841_WOL_FRAME_BYTE2_OFFSET	0x0228 | 
 | 236 |  | 
 | 237 | /* IACR */ | 
 | 238 | #define KS884X_IACR_P			0x04A0 | 
 | 239 | #define KS884X_IACR_OFFSET		KS884X_IACR_P | 
 | 240 |  | 
 | 241 | /* IADR1 */ | 
 | 242 | #define KS884X_IADR1_P			0x04A2 | 
 | 243 | #define KS884X_IADR2_P			0x04A4 | 
 | 244 | #define KS884X_IADR3_P			0x04A6 | 
 | 245 | #define KS884X_IADR4_P			0x04A8 | 
 | 246 | #define KS884X_IADR5_P			0x04AA | 
 | 247 |  | 
 | 248 | #define KS884X_ACC_CTRL_SEL_OFFSET	KS884X_IACR_P | 
 | 249 | #define KS884X_ACC_CTRL_INDEX_OFFSET	(KS884X_ACC_CTRL_SEL_OFFSET + 1) | 
 | 250 |  | 
 | 251 | #define KS884X_ACC_DATA_0_OFFSET	KS884X_IADR4_P | 
 | 252 | #define KS884X_ACC_DATA_1_OFFSET	(KS884X_ACC_DATA_0_OFFSET + 1) | 
 | 253 | #define KS884X_ACC_DATA_2_OFFSET	KS884X_IADR5_P | 
 | 254 | #define KS884X_ACC_DATA_3_OFFSET	(KS884X_ACC_DATA_2_OFFSET + 1) | 
 | 255 | #define KS884X_ACC_DATA_4_OFFSET	KS884X_IADR2_P | 
 | 256 | #define KS884X_ACC_DATA_5_OFFSET	(KS884X_ACC_DATA_4_OFFSET + 1) | 
 | 257 | #define KS884X_ACC_DATA_6_OFFSET	KS884X_IADR3_P | 
 | 258 | #define KS884X_ACC_DATA_7_OFFSET	(KS884X_ACC_DATA_6_OFFSET + 1) | 
 | 259 | #define KS884X_ACC_DATA_8_OFFSET	KS884X_IADR1_P | 
 | 260 |  | 
 | 261 | /* P1MBCR */ | 
 | 262 | #define KS884X_P1MBCR_P			0x04D0 | 
 | 263 | #define KS884X_P1MBSR_P			0x04D2 | 
 | 264 | #define KS884X_PHY1ILR_P		0x04D4 | 
 | 265 | #define KS884X_PHY1IHR_P		0x04D6 | 
 | 266 | #define KS884X_P1ANAR_P			0x04D8 | 
 | 267 | #define KS884X_P1ANLPR_P		0x04DA | 
 | 268 |  | 
 | 269 | /* P2MBCR */ | 
 | 270 | #define KS884X_P2MBCR_P			0x04E0 | 
 | 271 | #define KS884X_P2MBSR_P			0x04E2 | 
 | 272 | #define KS884X_PHY2ILR_P		0x04E4 | 
 | 273 | #define KS884X_PHY2IHR_P		0x04E6 | 
 | 274 | #define KS884X_P2ANAR_P			0x04E8 | 
 | 275 | #define KS884X_P2ANLPR_P		0x04EA | 
 | 276 |  | 
 | 277 | #define KS884X_PHY_1_CTRL_OFFSET	KS884X_P1MBCR_P | 
 | 278 | #define PHY_CTRL_INTERVAL		(KS884X_P2MBCR_P - KS884X_P1MBCR_P) | 
 | 279 |  | 
 | 280 | #define KS884X_PHY_CTRL_OFFSET		0x00 | 
 | 281 |  | 
 | 282 | /* Mode Control Register */ | 
 | 283 | #define PHY_REG_CTRL			0 | 
 | 284 |  | 
 | 285 | #define PHY_RESET			0x8000 | 
 | 286 | #define PHY_LOOPBACK			0x4000 | 
 | 287 | #define PHY_SPEED_100MBIT		0x2000 | 
 | 288 | #define PHY_AUTO_NEG_ENABLE		0x1000 | 
 | 289 | #define PHY_POWER_DOWN			0x0800 | 
 | 290 | #define PHY_MII_DISABLE			0x0400 | 
 | 291 | #define PHY_AUTO_NEG_RESTART		0x0200 | 
 | 292 | #define PHY_FULL_DUPLEX			0x0100 | 
 | 293 | #define PHY_COLLISION_TEST		0x0080 | 
 | 294 | #define PHY_HP_MDIX			0x0020 | 
 | 295 | #define PHY_FORCE_MDIX			0x0010 | 
 | 296 | #define PHY_AUTO_MDIX_DISABLE		0x0008 | 
 | 297 | #define PHY_REMOTE_FAULT_DISABLE	0x0004 | 
 | 298 | #define PHY_TRANSMIT_DISABLE		0x0002 | 
 | 299 | #define PHY_LED_DISABLE			0x0001 | 
 | 300 |  | 
 | 301 | #define KS884X_PHY_STATUS_OFFSET	0x02 | 
 | 302 |  | 
 | 303 | /* Mode Status Register */ | 
 | 304 | #define PHY_REG_STATUS			1 | 
 | 305 |  | 
 | 306 | #define PHY_100BT4_CAPABLE		0x8000 | 
 | 307 | #define PHY_100BTX_FD_CAPABLE		0x4000 | 
 | 308 | #define PHY_100BTX_CAPABLE		0x2000 | 
 | 309 | #define PHY_10BT_FD_CAPABLE		0x1000 | 
 | 310 | #define PHY_10BT_CAPABLE		0x0800 | 
 | 311 | #define PHY_MII_SUPPRESS_CAPABLE	0x0040 | 
 | 312 | #define PHY_AUTO_NEG_ACKNOWLEDGE	0x0020 | 
 | 313 | #define PHY_REMOTE_FAULT		0x0010 | 
 | 314 | #define PHY_AUTO_NEG_CAPABLE		0x0008 | 
 | 315 | #define PHY_LINK_STATUS			0x0004 | 
 | 316 | #define PHY_JABBER_DETECT		0x0002 | 
 | 317 | #define PHY_EXTENDED_CAPABILITY		0x0001 | 
 | 318 |  | 
 | 319 | #define KS884X_PHY_ID_1_OFFSET		0x04 | 
 | 320 | #define KS884X_PHY_ID_2_OFFSET		0x06 | 
 | 321 |  | 
 | 322 | /* PHY Identifier Registers */ | 
 | 323 | #define PHY_REG_ID_1			2 | 
 | 324 | #define PHY_REG_ID_2			3 | 
 | 325 |  | 
 | 326 | #define KS884X_PHY_AUTO_NEG_OFFSET	0x08 | 
 | 327 |  | 
 | 328 | /* Auto-Negotiation Advertisement Register */ | 
 | 329 | #define PHY_REG_AUTO_NEGOTIATION	4 | 
 | 330 |  | 
 | 331 | #define PHY_AUTO_NEG_NEXT_PAGE		0x8000 | 
 | 332 | #define PHY_AUTO_NEG_REMOTE_FAULT	0x2000 | 
 | 333 | /* Not supported. */ | 
 | 334 | #define PHY_AUTO_NEG_ASYM_PAUSE		0x0800 | 
 | 335 | #define PHY_AUTO_NEG_SYM_PAUSE		0x0400 | 
 | 336 | #define PHY_AUTO_NEG_100BT4		0x0200 | 
 | 337 | #define PHY_AUTO_NEG_100BTX_FD		0x0100 | 
 | 338 | #define PHY_AUTO_NEG_100BTX		0x0080 | 
 | 339 | #define PHY_AUTO_NEG_10BT_FD		0x0040 | 
 | 340 | #define PHY_AUTO_NEG_10BT		0x0020 | 
 | 341 | #define PHY_AUTO_NEG_SELECTOR		0x001F | 
 | 342 | #define PHY_AUTO_NEG_802_3		0x0001 | 
 | 343 |  | 
 | 344 | #define PHY_AUTO_NEG_PAUSE  (PHY_AUTO_NEG_SYM_PAUSE | PHY_AUTO_NEG_ASYM_PAUSE) | 
 | 345 |  | 
 | 346 | #define KS884X_PHY_REMOTE_CAP_OFFSET	0x0A | 
 | 347 |  | 
 | 348 | /* Auto-Negotiation Link Partner Ability Register */ | 
 | 349 | #define PHY_REG_REMOTE_CAPABILITY	5 | 
 | 350 |  | 
 | 351 | #define PHY_REMOTE_NEXT_PAGE		0x8000 | 
 | 352 | #define PHY_REMOTE_ACKNOWLEDGE		0x4000 | 
 | 353 | #define PHY_REMOTE_REMOTE_FAULT		0x2000 | 
 | 354 | #define PHY_REMOTE_SYM_PAUSE		0x0400 | 
 | 355 | #define PHY_REMOTE_100BTX_FD		0x0100 | 
 | 356 | #define PHY_REMOTE_100BTX		0x0080 | 
 | 357 | #define PHY_REMOTE_10BT_FD		0x0040 | 
 | 358 | #define PHY_REMOTE_10BT			0x0020 | 
 | 359 |  | 
 | 360 | /* P1VCT */ | 
 | 361 | #define KS884X_P1VCT_P			0x04F0 | 
 | 362 | #define KS884X_P1PHYCTRL_P		0x04F2 | 
 | 363 |  | 
 | 364 | /* P2VCT */ | 
 | 365 | #define KS884X_P2VCT_P			0x04F4 | 
 | 366 | #define KS884X_P2PHYCTRL_P		0x04F6 | 
 | 367 |  | 
 | 368 | #define KS884X_PHY_SPECIAL_OFFSET	KS884X_P1VCT_P | 
 | 369 | #define PHY_SPECIAL_INTERVAL		(KS884X_P2VCT_P - KS884X_P1VCT_P) | 
 | 370 |  | 
 | 371 | #define KS884X_PHY_LINK_MD_OFFSET	0x00 | 
 | 372 |  | 
 | 373 | #define PHY_START_CABLE_DIAG		0x8000 | 
 | 374 | #define PHY_CABLE_DIAG_RESULT		0x6000 | 
 | 375 | #define PHY_CABLE_STAT_NORMAL		0x0000 | 
 | 376 | #define PHY_CABLE_STAT_OPEN		0x2000 | 
 | 377 | #define PHY_CABLE_STAT_SHORT		0x4000 | 
 | 378 | #define PHY_CABLE_STAT_FAILED		0x6000 | 
 | 379 | #define PHY_CABLE_10M_SHORT		0x1000 | 
 | 380 | #define PHY_CABLE_FAULT_COUNTER		0x01FF | 
 | 381 |  | 
 | 382 | #define KS884X_PHY_PHY_CTRL_OFFSET	0x02 | 
 | 383 |  | 
 | 384 | #define PHY_STAT_REVERSED_POLARITY	0x0020 | 
 | 385 | #define PHY_STAT_MDIX			0x0010 | 
 | 386 | #define PHY_FORCE_LINK			0x0008 | 
 | 387 | #define PHY_POWER_SAVING_DISABLE	0x0004 | 
 | 388 | #define PHY_REMOTE_LOOPBACK		0x0002 | 
 | 389 |  | 
 | 390 | /* SIDER */ | 
 | 391 | #define KS884X_SIDER_P			0x0400 | 
 | 392 | #define KS884X_CHIP_ID_OFFSET		KS884X_SIDER_P | 
 | 393 | #define KS884X_FAMILY_ID_OFFSET		(KS884X_CHIP_ID_OFFSET + 1) | 
 | 394 |  | 
 | 395 | #define REG_FAMILY_ID			0x88 | 
 | 396 |  | 
 | 397 | #define REG_CHIP_ID_41			0x8810 | 
 | 398 | #define REG_CHIP_ID_42			0x8800 | 
 | 399 |  | 
 | 400 | #define KS884X_CHIP_ID_MASK_41		0xFF10 | 
 | 401 | #define KS884X_CHIP_ID_MASK		0xFFF0 | 
 | 402 | #define KS884X_CHIP_ID_SHIFT		4 | 
 | 403 | #define KS884X_REVISION_MASK		0x000E | 
 | 404 | #define KS884X_REVISION_SHIFT		1 | 
 | 405 | #define KS8842_START			0x0001 | 
 | 406 |  | 
 | 407 | #define CHIP_IP_41_M			0x8810 | 
 | 408 | #define CHIP_IP_42_M			0x8800 | 
 | 409 | #define CHIP_IP_61_M			0x8890 | 
 | 410 | #define CHIP_IP_62_M			0x8880 | 
 | 411 |  | 
 | 412 | #define CHIP_IP_41_P			0x8850 | 
 | 413 | #define CHIP_IP_42_P			0x8840 | 
 | 414 | #define CHIP_IP_61_P			0x88D0 | 
 | 415 | #define CHIP_IP_62_P			0x88C0 | 
 | 416 |  | 
 | 417 | /* SGCR1 */ | 
 | 418 | #define KS8842_SGCR1_P			0x0402 | 
 | 419 | #define KS8842_SWITCH_CTRL_1_OFFSET	KS8842_SGCR1_P | 
 | 420 |  | 
 | 421 | #define SWITCH_PASS_ALL			0x8000 | 
 | 422 | #define SWITCH_TX_FLOW_CTRL		0x2000 | 
 | 423 | #define SWITCH_RX_FLOW_CTRL		0x1000 | 
 | 424 | #define SWITCH_CHECK_LENGTH		0x0800 | 
 | 425 | #define SWITCH_AGING_ENABLE		0x0400 | 
 | 426 | #define SWITCH_FAST_AGING		0x0200 | 
 | 427 | #define SWITCH_AGGR_BACKOFF		0x0100 | 
 | 428 | #define SWITCH_PASS_PAUSE		0x0008 | 
 | 429 | #define SWITCH_LINK_AUTO_AGING		0x0001 | 
 | 430 |  | 
 | 431 | /* SGCR2 */ | 
 | 432 | #define KS8842_SGCR2_P			0x0404 | 
 | 433 | #define KS8842_SWITCH_CTRL_2_OFFSET	KS8842_SGCR2_P | 
 | 434 |  | 
 | 435 | #define SWITCH_VLAN_ENABLE		0x8000 | 
 | 436 | #define SWITCH_IGMP_SNOOP		0x4000 | 
 | 437 | #define IPV6_MLD_SNOOP_ENABLE		0x2000 | 
 | 438 | #define IPV6_MLD_SNOOP_OPTION		0x1000 | 
 | 439 | #define PRIORITY_SCHEME_SELECT		0x0800 | 
 | 440 | #define SWITCH_MIRROR_RX_TX		0x0100 | 
 | 441 | #define UNICAST_VLAN_BOUNDARY		0x0080 | 
 | 442 | #define MULTICAST_STORM_DISABLE		0x0040 | 
 | 443 | #define SWITCH_BACK_PRESSURE		0x0020 | 
 | 444 | #define FAIR_FLOW_CTRL			0x0010 | 
 | 445 | #define NO_EXC_COLLISION_DROP		0x0008 | 
 | 446 | #define SWITCH_HUGE_PACKET		0x0004 | 
 | 447 | #define SWITCH_LEGAL_PACKET		0x0002 | 
 | 448 | #define SWITCH_BUF_RESERVE		0x0001 | 
 | 449 |  | 
 | 450 | /* SGCR3 */ | 
 | 451 | #define KS8842_SGCR3_P			0x0406 | 
 | 452 | #define KS8842_SWITCH_CTRL_3_OFFSET	KS8842_SGCR3_P | 
 | 453 |  | 
 | 454 | #define BROADCAST_STORM_RATE_LO		0xFF00 | 
 | 455 | #define SWITCH_REPEATER			0x0080 | 
 | 456 | #define SWITCH_HALF_DUPLEX		0x0040 | 
 | 457 | #define SWITCH_FLOW_CTRL		0x0020 | 
 | 458 | #define SWITCH_10_MBIT			0x0010 | 
 | 459 | #define SWITCH_REPLACE_NULL_VID		0x0008 | 
 | 460 | #define BROADCAST_STORM_RATE_HI		0x0007 | 
 | 461 |  | 
 | 462 | #define BROADCAST_STORM_RATE		0x07FF | 
 | 463 |  | 
 | 464 | /* SGCR4 */ | 
 | 465 | #define KS8842_SGCR4_P			0x0408 | 
 | 466 |  | 
 | 467 | /* SGCR5 */ | 
 | 468 | #define KS8842_SGCR5_P			0x040A | 
 | 469 | #define KS8842_SWITCH_CTRL_5_OFFSET	KS8842_SGCR5_P | 
 | 470 |  | 
 | 471 | #define LED_MODE			0x8200 | 
 | 472 | #define LED_SPEED_DUPLEX_ACT		0x0000 | 
 | 473 | #define LED_SPEED_DUPLEX_LINK_ACT	0x8000 | 
 | 474 | #define LED_DUPLEX_10_100		0x0200 | 
 | 475 |  | 
 | 476 | /* SGCR6 */ | 
 | 477 | #define KS8842_SGCR6_P			0x0410 | 
 | 478 | #define KS8842_SWITCH_CTRL_6_OFFSET	KS8842_SGCR6_P | 
 | 479 |  | 
 | 480 | #define KS8842_PRIORITY_MASK		3 | 
 | 481 | #define KS8842_PRIORITY_SHIFT		2 | 
 | 482 |  | 
 | 483 | /* SGCR7 */ | 
 | 484 | #define KS8842_SGCR7_P			0x0412 | 
 | 485 | #define KS8842_SWITCH_CTRL_7_OFFSET	KS8842_SGCR7_P | 
 | 486 |  | 
 | 487 | #define SWITCH_UNK_DEF_PORT_ENABLE	0x0008 | 
 | 488 | #define SWITCH_UNK_DEF_PORT_3		0x0004 | 
 | 489 | #define SWITCH_UNK_DEF_PORT_2		0x0002 | 
 | 490 | #define SWITCH_UNK_DEF_PORT_1		0x0001 | 
 | 491 |  | 
 | 492 | /* MACAR1 */ | 
 | 493 | #define KS8842_MACAR1_P			0x0470 | 
 | 494 | #define KS8842_MACAR2_P			0x0472 | 
 | 495 | #define KS8842_MACAR3_P			0x0474 | 
 | 496 | #define KS8842_MAC_ADDR_1_OFFSET	KS8842_MACAR1_P | 
 | 497 | #define KS8842_MAC_ADDR_0_OFFSET	(KS8842_MAC_ADDR_1_OFFSET + 1) | 
 | 498 | #define KS8842_MAC_ADDR_3_OFFSET	KS8842_MACAR2_P | 
 | 499 | #define KS8842_MAC_ADDR_2_OFFSET	(KS8842_MAC_ADDR_3_OFFSET + 1) | 
 | 500 | #define KS8842_MAC_ADDR_5_OFFSET	KS8842_MACAR3_P | 
 | 501 | #define KS8842_MAC_ADDR_4_OFFSET	(KS8842_MAC_ADDR_5_OFFSET + 1) | 
 | 502 |  | 
 | 503 | /* TOSR1 */ | 
 | 504 | #define KS8842_TOSR1_P			0x0480 | 
 | 505 | #define KS8842_TOSR2_P			0x0482 | 
 | 506 | #define KS8842_TOSR3_P			0x0484 | 
 | 507 | #define KS8842_TOSR4_P			0x0486 | 
 | 508 | #define KS8842_TOSR5_P			0x0488 | 
 | 509 | #define KS8842_TOSR6_P			0x048A | 
 | 510 | #define KS8842_TOSR7_P			0x0490 | 
 | 511 | #define KS8842_TOSR8_P			0x0492 | 
 | 512 | #define KS8842_TOS_1_OFFSET		KS8842_TOSR1_P | 
 | 513 | #define KS8842_TOS_2_OFFSET		KS8842_TOSR2_P | 
 | 514 | #define KS8842_TOS_3_OFFSET		KS8842_TOSR3_P | 
 | 515 | #define KS8842_TOS_4_OFFSET		KS8842_TOSR4_P | 
 | 516 | #define KS8842_TOS_5_OFFSET		KS8842_TOSR5_P | 
 | 517 | #define KS8842_TOS_6_OFFSET		KS8842_TOSR6_P | 
 | 518 |  | 
 | 519 | #define KS8842_TOS_7_OFFSET		KS8842_TOSR7_P | 
 | 520 | #define KS8842_TOS_8_OFFSET		KS8842_TOSR8_P | 
 | 521 |  | 
 | 522 | /* P1CR1 */ | 
 | 523 | #define KS8842_P1CR1_P			0x0500 | 
 | 524 | #define KS8842_P1CR2_P			0x0502 | 
 | 525 | #define KS8842_P1VIDR_P			0x0504 | 
 | 526 | #define KS8842_P1CR3_P			0x0506 | 
 | 527 | #define KS8842_P1IRCR_P			0x0508 | 
 | 528 | #define KS8842_P1ERCR_P			0x050A | 
 | 529 | #define KS884X_P1SCSLMD_P		0x0510 | 
 | 530 | #define KS884X_P1CR4_P			0x0512 | 
 | 531 | #define KS884X_P1SR_P			0x0514 | 
 | 532 |  | 
 | 533 | /* P2CR1 */ | 
 | 534 | #define KS8842_P2CR1_P			0x0520 | 
 | 535 | #define KS8842_P2CR2_P			0x0522 | 
 | 536 | #define KS8842_P2VIDR_P			0x0524 | 
 | 537 | #define KS8842_P2CR3_P			0x0526 | 
 | 538 | #define KS8842_P2IRCR_P			0x0528 | 
 | 539 | #define KS8842_P2ERCR_P			0x052A | 
 | 540 | #define KS884X_P2SCSLMD_P		0x0530 | 
 | 541 | #define KS884X_P2CR4_P			0x0532 | 
 | 542 | #define KS884X_P2SR_P			0x0534 | 
 | 543 |  | 
 | 544 | /* P3CR1 */ | 
 | 545 | #define KS8842_P3CR1_P			0x0540 | 
 | 546 | #define KS8842_P3CR2_P			0x0542 | 
 | 547 | #define KS8842_P3VIDR_P			0x0544 | 
 | 548 | #define KS8842_P3CR3_P			0x0546 | 
 | 549 | #define KS8842_P3IRCR_P			0x0548 | 
 | 550 | #define KS8842_P3ERCR_P			0x054A | 
 | 551 |  | 
 | 552 | #define KS8842_PORT_1_CTRL_1		KS8842_P1CR1_P | 
 | 553 | #define KS8842_PORT_2_CTRL_1		KS8842_P2CR1_P | 
 | 554 | #define KS8842_PORT_3_CTRL_1		KS8842_P3CR1_P | 
 | 555 |  | 
 | 556 | #define PORT_CTRL_ADDR(port, addr)		\ | 
 | 557 | 	(addr = KS8842_PORT_1_CTRL_1 + (port) *	\ | 
 | 558 | 		(KS8842_PORT_2_CTRL_1 - KS8842_PORT_1_CTRL_1)) | 
 | 559 |  | 
 | 560 | #define KS8842_PORT_CTRL_1_OFFSET	0x00 | 
 | 561 |  | 
 | 562 | #define PORT_BROADCAST_STORM		0x0080 | 
 | 563 | #define PORT_DIFFSERV_ENABLE		0x0040 | 
 | 564 | #define PORT_802_1P_ENABLE		0x0020 | 
 | 565 | #define PORT_BASED_PRIORITY_MASK	0x0018 | 
 | 566 | #define PORT_BASED_PRIORITY_BASE	0x0003 | 
 | 567 | #define PORT_BASED_PRIORITY_SHIFT	3 | 
 | 568 | #define PORT_BASED_PRIORITY_0		0x0000 | 
 | 569 | #define PORT_BASED_PRIORITY_1		0x0008 | 
 | 570 | #define PORT_BASED_PRIORITY_2		0x0010 | 
 | 571 | #define PORT_BASED_PRIORITY_3		0x0018 | 
 | 572 | #define PORT_INSERT_TAG			0x0004 | 
 | 573 | #define PORT_REMOVE_TAG			0x0002 | 
 | 574 | #define PORT_PRIO_QUEUE_ENABLE		0x0001 | 
 | 575 |  | 
 | 576 | #define KS8842_PORT_CTRL_2_OFFSET	0x02 | 
 | 577 |  | 
 | 578 | #define PORT_INGRESS_VLAN_FILTER	0x4000 | 
 | 579 | #define PORT_DISCARD_NON_VID		0x2000 | 
 | 580 | #define PORT_FORCE_FLOW_CTRL		0x1000 | 
 | 581 | #define PORT_BACK_PRESSURE		0x0800 | 
 | 582 | #define PORT_TX_ENABLE			0x0400 | 
 | 583 | #define PORT_RX_ENABLE			0x0200 | 
 | 584 | #define PORT_LEARN_DISABLE		0x0100 | 
 | 585 | #define PORT_MIRROR_SNIFFER		0x0080 | 
 | 586 | #define PORT_MIRROR_RX			0x0040 | 
 | 587 | #define PORT_MIRROR_TX			0x0020 | 
 | 588 | #define PORT_USER_PRIORITY_CEILING	0x0008 | 
 | 589 | #define PORT_VLAN_MEMBERSHIP		0x0007 | 
 | 590 |  | 
 | 591 | #define KS8842_PORT_CTRL_VID_OFFSET	0x04 | 
 | 592 |  | 
 | 593 | #define PORT_DEFAULT_VID		0x0001 | 
 | 594 |  | 
 | 595 | #define KS8842_PORT_CTRL_3_OFFSET	0x06 | 
 | 596 |  | 
 | 597 | #define PORT_INGRESS_LIMIT_MODE		0x000C | 
 | 598 | #define PORT_INGRESS_ALL		0x0000 | 
 | 599 | #define PORT_INGRESS_UNICAST		0x0004 | 
 | 600 | #define PORT_INGRESS_MULTICAST		0x0008 | 
 | 601 | #define PORT_INGRESS_BROADCAST		0x000C | 
 | 602 | #define PORT_COUNT_IFG			0x0002 | 
 | 603 | #define PORT_COUNT_PREAMBLE		0x0001 | 
 | 604 |  | 
 | 605 | #define KS8842_PORT_IN_RATE_OFFSET	0x08 | 
 | 606 | #define KS8842_PORT_OUT_RATE_OFFSET	0x0A | 
 | 607 |  | 
 | 608 | #define PORT_PRIORITY_RATE		0x0F | 
 | 609 | #define PORT_PRIORITY_RATE_SHIFT	4 | 
 | 610 |  | 
 | 611 | #define KS884X_PORT_LINK_MD		0x10 | 
 | 612 |  | 
 | 613 | #define PORT_CABLE_10M_SHORT		0x8000 | 
 | 614 | #define PORT_CABLE_DIAG_RESULT		0x6000 | 
 | 615 | #define PORT_CABLE_STAT_NORMAL		0x0000 | 
 | 616 | #define PORT_CABLE_STAT_OPEN		0x2000 | 
 | 617 | #define PORT_CABLE_STAT_SHORT		0x4000 | 
 | 618 | #define PORT_CABLE_STAT_FAILED		0x6000 | 
 | 619 | #define PORT_START_CABLE_DIAG		0x1000 | 
 | 620 | #define PORT_FORCE_LINK			0x0800 | 
 | 621 | #define PORT_POWER_SAVING_DISABLE	0x0400 | 
 | 622 | #define PORT_PHY_REMOTE_LOOPBACK	0x0200 | 
 | 623 | #define PORT_CABLE_FAULT_COUNTER	0x01FF | 
 | 624 |  | 
 | 625 | #define KS884X_PORT_CTRL_4_OFFSET	0x12 | 
 | 626 |  | 
 | 627 | #define PORT_LED_OFF			0x8000 | 
 | 628 | #define PORT_TX_DISABLE			0x4000 | 
 | 629 | #define PORT_AUTO_NEG_RESTART		0x2000 | 
 | 630 | #define PORT_REMOTE_FAULT_DISABLE	0x1000 | 
 | 631 | #define PORT_POWER_DOWN			0x0800 | 
 | 632 | #define PORT_AUTO_MDIX_DISABLE		0x0400 | 
 | 633 | #define PORT_FORCE_MDIX			0x0200 | 
 | 634 | #define PORT_LOOPBACK			0x0100 | 
 | 635 | #define PORT_AUTO_NEG_ENABLE		0x0080 | 
 | 636 | #define PORT_FORCE_100_MBIT		0x0040 | 
 | 637 | #define PORT_FORCE_FULL_DUPLEX		0x0020 | 
 | 638 | #define PORT_AUTO_NEG_SYM_PAUSE		0x0010 | 
 | 639 | #define PORT_AUTO_NEG_100BTX_FD		0x0008 | 
 | 640 | #define PORT_AUTO_NEG_100BTX		0x0004 | 
 | 641 | #define PORT_AUTO_NEG_10BT_FD		0x0002 | 
 | 642 | #define PORT_AUTO_NEG_10BT		0x0001 | 
 | 643 |  | 
 | 644 | #define KS884X_PORT_STATUS_OFFSET	0x14 | 
 | 645 |  | 
 | 646 | #define PORT_HP_MDIX			0x8000 | 
 | 647 | #define PORT_REVERSED_POLARITY		0x2000 | 
 | 648 | #define PORT_RX_FLOW_CTRL		0x0800 | 
 | 649 | #define PORT_TX_FLOW_CTRL		0x1000 | 
 | 650 | #define PORT_STATUS_SPEED_100MBIT	0x0400 | 
 | 651 | #define PORT_STATUS_FULL_DUPLEX		0x0200 | 
 | 652 | #define PORT_REMOTE_FAULT		0x0100 | 
 | 653 | #define PORT_MDIX_STATUS		0x0080 | 
 | 654 | #define PORT_AUTO_NEG_COMPLETE		0x0040 | 
 | 655 | #define PORT_STATUS_LINK_GOOD		0x0020 | 
 | 656 | #define PORT_REMOTE_SYM_PAUSE		0x0010 | 
 | 657 | #define PORT_REMOTE_100BTX_FD		0x0008 | 
 | 658 | #define PORT_REMOTE_100BTX		0x0004 | 
 | 659 | #define PORT_REMOTE_10BT_FD		0x0002 | 
 | 660 | #define PORT_REMOTE_10BT		0x0001 | 
 | 661 |  | 
 | 662 | /* | 
 | 663 | #define STATIC_MAC_TABLE_ADDR		00-0000FFFF-FFFFFFFF | 
 | 664 | #define STATIC_MAC_TABLE_FWD_PORTS	00-00070000-00000000 | 
 | 665 | #define STATIC_MAC_TABLE_VALID		00-00080000-00000000 | 
 | 666 | #define STATIC_MAC_TABLE_OVERRIDE	00-00100000-00000000 | 
 | 667 | #define STATIC_MAC_TABLE_USE_FID	00-00200000-00000000 | 
 | 668 | #define STATIC_MAC_TABLE_FID		00-03C00000-00000000 | 
 | 669 | */ | 
 | 670 |  | 
 | 671 | #define STATIC_MAC_TABLE_ADDR		0x0000FFFF | 
 | 672 | #define STATIC_MAC_TABLE_FWD_PORTS	0x00070000 | 
 | 673 | #define STATIC_MAC_TABLE_VALID		0x00080000 | 
 | 674 | #define STATIC_MAC_TABLE_OVERRIDE	0x00100000 | 
 | 675 | #define STATIC_MAC_TABLE_USE_FID	0x00200000 | 
 | 676 | #define STATIC_MAC_TABLE_FID		0x03C00000 | 
 | 677 |  | 
 | 678 | #define STATIC_MAC_FWD_PORTS_SHIFT	16 | 
 | 679 | #define STATIC_MAC_FID_SHIFT		22 | 
 | 680 |  | 
 | 681 | /* | 
 | 682 | #define VLAN_TABLE_VID			00-00000000-00000FFF | 
 | 683 | #define VLAN_TABLE_FID			00-00000000-0000F000 | 
 | 684 | #define VLAN_TABLE_MEMBERSHIP		00-00000000-00070000 | 
 | 685 | #define VLAN_TABLE_VALID		00-00000000-00080000 | 
 | 686 | */ | 
 | 687 |  | 
 | 688 | #define VLAN_TABLE_VID			0x00000FFF | 
 | 689 | #define VLAN_TABLE_FID			0x0000F000 | 
 | 690 | #define VLAN_TABLE_MEMBERSHIP		0x00070000 | 
 | 691 | #define VLAN_TABLE_VALID		0x00080000 | 
 | 692 |  | 
 | 693 | #define VLAN_TABLE_FID_SHIFT		12 | 
 | 694 | #define VLAN_TABLE_MEMBERSHIP_SHIFT	16 | 
 | 695 |  | 
 | 696 | /* | 
 | 697 | #define DYNAMIC_MAC_TABLE_ADDR		00-0000FFFF-FFFFFFFF | 
 | 698 | #define DYNAMIC_MAC_TABLE_FID		00-000F0000-00000000 | 
 | 699 | #define DYNAMIC_MAC_TABLE_SRC_PORT	00-00300000-00000000 | 
 | 700 | #define DYNAMIC_MAC_TABLE_TIMESTAMP	00-00C00000-00000000 | 
 | 701 | #define DYNAMIC_MAC_TABLE_ENTRIES	03-FF000000-00000000 | 
 | 702 | #define DYNAMIC_MAC_TABLE_MAC_EMPTY	04-00000000-00000000 | 
 | 703 | #define DYNAMIC_MAC_TABLE_RESERVED	78-00000000-00000000 | 
 | 704 | #define DYNAMIC_MAC_TABLE_NOT_READY	80-00000000-00000000 | 
 | 705 | */ | 
 | 706 |  | 
 | 707 | #define DYNAMIC_MAC_TABLE_ADDR		0x0000FFFF | 
 | 708 | #define DYNAMIC_MAC_TABLE_FID		0x000F0000 | 
 | 709 | #define DYNAMIC_MAC_TABLE_SRC_PORT	0x00300000 | 
 | 710 | #define DYNAMIC_MAC_TABLE_TIMESTAMP	0x00C00000 | 
 | 711 | #define DYNAMIC_MAC_TABLE_ENTRIES	0xFF000000 | 
 | 712 |  | 
 | 713 | #define DYNAMIC_MAC_TABLE_ENTRIES_H	0x03 | 
 | 714 | #define DYNAMIC_MAC_TABLE_MAC_EMPTY	0x04 | 
 | 715 | #define DYNAMIC_MAC_TABLE_RESERVED	0x78 | 
 | 716 | #define DYNAMIC_MAC_TABLE_NOT_READY	0x80 | 
 | 717 |  | 
 | 718 | #define DYNAMIC_MAC_FID_SHIFT		16 | 
 | 719 | #define DYNAMIC_MAC_SRC_PORT_SHIFT	20 | 
 | 720 | #define DYNAMIC_MAC_TIMESTAMP_SHIFT	22 | 
 | 721 | #define DYNAMIC_MAC_ENTRIES_SHIFT	24 | 
 | 722 | #define DYNAMIC_MAC_ENTRIES_H_SHIFT	8 | 
 | 723 |  | 
 | 724 | /* | 
 | 725 | #define MIB_COUNTER_VALUE		00-00000000-3FFFFFFF | 
 | 726 | #define MIB_COUNTER_VALID		00-00000000-40000000 | 
 | 727 | #define MIB_COUNTER_OVERFLOW		00-00000000-80000000 | 
 | 728 | */ | 
 | 729 |  | 
 | 730 | #define MIB_COUNTER_VALUE		0x3FFFFFFF | 
 | 731 | #define MIB_COUNTER_VALID		0x40000000 | 
 | 732 | #define MIB_COUNTER_OVERFLOW		0x80000000 | 
 | 733 |  | 
 | 734 | #define MIB_PACKET_DROPPED		0x0000FFFF | 
 | 735 |  | 
 | 736 | #define KS_MIB_PACKET_DROPPED_TX_0	0x100 | 
 | 737 | #define KS_MIB_PACKET_DROPPED_TX_1	0x101 | 
 | 738 | #define KS_MIB_PACKET_DROPPED_TX	0x102 | 
 | 739 | #define KS_MIB_PACKET_DROPPED_RX_0	0x103 | 
 | 740 | #define KS_MIB_PACKET_DROPPED_RX_1	0x104 | 
 | 741 | #define KS_MIB_PACKET_DROPPED_RX	0x105 | 
 | 742 |  | 
 | 743 | /* Change default LED mode. */ | 
 | 744 | #define SET_DEFAULT_LED			LED_SPEED_DUPLEX_ACT | 
 | 745 |  | 
 | 746 | #define MAC_ADDR_LEN			6 | 
 | 747 | #define MAC_ADDR_ORDER(i)		(MAC_ADDR_LEN - 1 - (i)) | 
 | 748 |  | 
 | 749 | #define MAX_ETHERNET_BODY_SIZE		1500 | 
 | 750 | #define ETHERNET_HEADER_SIZE		14 | 
 | 751 |  | 
 | 752 | #define MAX_ETHERNET_PACKET_SIZE	\ | 
 | 753 | 	(MAX_ETHERNET_BODY_SIZE + ETHERNET_HEADER_SIZE) | 
 | 754 |  | 
 | 755 | #define REGULAR_RX_BUF_SIZE		(MAX_ETHERNET_PACKET_SIZE + 4) | 
 | 756 | #define MAX_RX_BUF_SIZE			(1912 + 4) | 
 | 757 |  | 
 | 758 | #define ADDITIONAL_ENTRIES		16 | 
 | 759 | #define MAX_MULTICAST_LIST		32 | 
 | 760 |  | 
 | 761 | #define HW_MULTICAST_SIZE		8 | 
 | 762 |  | 
 | 763 | #define HW_TO_DEV_PORT(port)		(port - 1) | 
 | 764 |  | 
 | 765 | enum { | 
 | 766 | 	media_connected, | 
 | 767 | 	media_disconnected | 
 | 768 | }; | 
 | 769 |  | 
 | 770 | enum { | 
 | 771 | 	OID_COUNTER_UNKOWN, | 
 | 772 |  | 
 | 773 | 	OID_COUNTER_FIRST, | 
 | 774 |  | 
 | 775 | 	/* total transmit errors */ | 
 | 776 | 	OID_COUNTER_XMIT_ERROR, | 
 | 777 |  | 
 | 778 | 	/* total receive errors */ | 
 | 779 | 	OID_COUNTER_RCV_ERROR, | 
 | 780 |  | 
 | 781 | 	OID_COUNTER_LAST | 
 | 782 | }; | 
 | 783 |  | 
 | 784 | /* | 
 | 785 |  * Hardware descriptor definitions | 
 | 786 |  */ | 
 | 787 |  | 
 | 788 | #define DESC_ALIGNMENT			16 | 
 | 789 | #define BUFFER_ALIGNMENT		8 | 
 | 790 |  | 
 | 791 | #define NUM_OF_RX_DESC			64 | 
 | 792 | #define NUM_OF_TX_DESC			64 | 
 | 793 |  | 
 | 794 | #define KS_DESC_RX_FRAME_LEN		0x000007FF | 
 | 795 | #define KS_DESC_RX_FRAME_TYPE		0x00008000 | 
 | 796 | #define KS_DESC_RX_ERROR_CRC		0x00010000 | 
 | 797 | #define KS_DESC_RX_ERROR_RUNT		0x00020000 | 
 | 798 | #define KS_DESC_RX_ERROR_TOO_LONG	0x00040000 | 
 | 799 | #define KS_DESC_RX_ERROR_PHY		0x00080000 | 
 | 800 | #define KS884X_DESC_RX_PORT_MASK	0x00300000 | 
 | 801 | #define KS_DESC_RX_MULTICAST		0x01000000 | 
 | 802 | #define KS_DESC_RX_ERROR		0x02000000 | 
 | 803 | #define KS_DESC_RX_ERROR_CSUM_UDP	0x04000000 | 
 | 804 | #define KS_DESC_RX_ERROR_CSUM_TCP	0x08000000 | 
 | 805 | #define KS_DESC_RX_ERROR_CSUM_IP	0x10000000 | 
 | 806 | #define KS_DESC_RX_LAST			0x20000000 | 
 | 807 | #define KS_DESC_RX_FIRST		0x40000000 | 
 | 808 | #define KS_DESC_RX_ERROR_COND		\ | 
 | 809 | 	(KS_DESC_RX_ERROR_CRC |		\ | 
 | 810 | 	KS_DESC_RX_ERROR_RUNT |		\ | 
 | 811 | 	KS_DESC_RX_ERROR_PHY |		\ | 
 | 812 | 	KS_DESC_RX_ERROR_TOO_LONG) | 
 | 813 |  | 
 | 814 | #define KS_DESC_HW_OWNED		0x80000000 | 
 | 815 |  | 
 | 816 | #define KS_DESC_BUF_SIZE		0x000007FF | 
 | 817 | #define KS884X_DESC_TX_PORT_MASK	0x00300000 | 
 | 818 | #define KS_DESC_END_OF_RING		0x02000000 | 
 | 819 | #define KS_DESC_TX_CSUM_GEN_UDP		0x04000000 | 
 | 820 | #define KS_DESC_TX_CSUM_GEN_TCP		0x08000000 | 
 | 821 | #define KS_DESC_TX_CSUM_GEN_IP		0x10000000 | 
 | 822 | #define KS_DESC_TX_LAST			0x20000000 | 
 | 823 | #define KS_DESC_TX_FIRST		0x40000000 | 
 | 824 | #define KS_DESC_TX_INTERRUPT		0x80000000 | 
 | 825 |  | 
 | 826 | #define KS_DESC_PORT_SHIFT		20 | 
 | 827 |  | 
 | 828 | #define KS_DESC_RX_MASK			(KS_DESC_BUF_SIZE) | 
 | 829 |  | 
 | 830 | #define KS_DESC_TX_MASK			\ | 
 | 831 | 	(KS_DESC_TX_INTERRUPT |		\ | 
 | 832 | 	KS_DESC_TX_FIRST |		\ | 
 | 833 | 	KS_DESC_TX_LAST |		\ | 
 | 834 | 	KS_DESC_TX_CSUM_GEN_IP |	\ | 
 | 835 | 	KS_DESC_TX_CSUM_GEN_TCP |	\ | 
 | 836 | 	KS_DESC_TX_CSUM_GEN_UDP |	\ | 
 | 837 | 	KS_DESC_BUF_SIZE) | 
 | 838 |  | 
 | 839 | struct ksz_desc_rx_stat { | 
 | 840 | #ifdef __BIG_ENDIAN_BITFIELD | 
 | 841 | 	u32 hw_owned:1; | 
 | 842 | 	u32 first_desc:1; | 
 | 843 | 	u32 last_desc:1; | 
 | 844 | 	u32 csum_err_ip:1; | 
 | 845 | 	u32 csum_err_tcp:1; | 
 | 846 | 	u32 csum_err_udp:1; | 
 | 847 | 	u32 error:1; | 
 | 848 | 	u32 multicast:1; | 
 | 849 | 	u32 src_port:4; | 
 | 850 | 	u32 err_phy:1; | 
 | 851 | 	u32 err_too_long:1; | 
 | 852 | 	u32 err_runt:1; | 
 | 853 | 	u32 err_crc:1; | 
 | 854 | 	u32 frame_type:1; | 
 | 855 | 	u32 reserved1:4; | 
 | 856 | 	u32 frame_len:11; | 
 | 857 | #else | 
 | 858 | 	u32 frame_len:11; | 
 | 859 | 	u32 reserved1:4; | 
 | 860 | 	u32 frame_type:1; | 
 | 861 | 	u32 err_crc:1; | 
 | 862 | 	u32 err_runt:1; | 
 | 863 | 	u32 err_too_long:1; | 
 | 864 | 	u32 err_phy:1; | 
 | 865 | 	u32 src_port:4; | 
 | 866 | 	u32 multicast:1; | 
 | 867 | 	u32 error:1; | 
 | 868 | 	u32 csum_err_udp:1; | 
 | 869 | 	u32 csum_err_tcp:1; | 
 | 870 | 	u32 csum_err_ip:1; | 
 | 871 | 	u32 last_desc:1; | 
 | 872 | 	u32 first_desc:1; | 
 | 873 | 	u32 hw_owned:1; | 
 | 874 | #endif | 
 | 875 | }; | 
 | 876 |  | 
 | 877 | struct ksz_desc_tx_stat { | 
 | 878 | #ifdef __BIG_ENDIAN_BITFIELD | 
 | 879 | 	u32 hw_owned:1; | 
 | 880 | 	u32 reserved1:31; | 
 | 881 | #else | 
 | 882 | 	u32 reserved1:31; | 
 | 883 | 	u32 hw_owned:1; | 
 | 884 | #endif | 
 | 885 | }; | 
 | 886 |  | 
 | 887 | struct ksz_desc_rx_buf { | 
 | 888 | #ifdef __BIG_ENDIAN_BITFIELD | 
 | 889 | 	u32 reserved4:6; | 
 | 890 | 	u32 end_of_ring:1; | 
 | 891 | 	u32 reserved3:14; | 
 | 892 | 	u32 buf_size:11; | 
 | 893 | #else | 
 | 894 | 	u32 buf_size:11; | 
 | 895 | 	u32 reserved3:14; | 
 | 896 | 	u32 end_of_ring:1; | 
 | 897 | 	u32 reserved4:6; | 
 | 898 | #endif | 
 | 899 | }; | 
 | 900 |  | 
 | 901 | struct ksz_desc_tx_buf { | 
 | 902 | #ifdef __BIG_ENDIAN_BITFIELD | 
 | 903 | 	u32 intr:1; | 
 | 904 | 	u32 first_seg:1; | 
 | 905 | 	u32 last_seg:1; | 
 | 906 | 	u32 csum_gen_ip:1; | 
 | 907 | 	u32 csum_gen_tcp:1; | 
 | 908 | 	u32 csum_gen_udp:1; | 
 | 909 | 	u32 end_of_ring:1; | 
 | 910 | 	u32 reserved4:1; | 
 | 911 | 	u32 dest_port:4; | 
 | 912 | 	u32 reserved3:9; | 
 | 913 | 	u32 buf_size:11; | 
 | 914 | #else | 
 | 915 | 	u32 buf_size:11; | 
 | 916 | 	u32 reserved3:9; | 
 | 917 | 	u32 dest_port:4; | 
 | 918 | 	u32 reserved4:1; | 
 | 919 | 	u32 end_of_ring:1; | 
 | 920 | 	u32 csum_gen_udp:1; | 
 | 921 | 	u32 csum_gen_tcp:1; | 
 | 922 | 	u32 csum_gen_ip:1; | 
 | 923 | 	u32 last_seg:1; | 
 | 924 | 	u32 first_seg:1; | 
 | 925 | 	u32 intr:1; | 
 | 926 | #endif | 
 | 927 | }; | 
 | 928 |  | 
 | 929 | union desc_stat { | 
 | 930 | 	struct ksz_desc_rx_stat rx; | 
 | 931 | 	struct ksz_desc_tx_stat tx; | 
 | 932 | 	u32 data; | 
 | 933 | }; | 
 | 934 |  | 
 | 935 | union desc_buf { | 
 | 936 | 	struct ksz_desc_rx_buf rx; | 
 | 937 | 	struct ksz_desc_tx_buf tx; | 
 | 938 | 	u32 data; | 
 | 939 | }; | 
 | 940 |  | 
 | 941 | /** | 
 | 942 |  * struct ksz_hw_desc - Hardware descriptor data structure | 
 | 943 |  * @ctrl:	Descriptor control value. | 
 | 944 |  * @buf:	Descriptor buffer value. | 
 | 945 |  * @addr:	Physical address of memory buffer. | 
 | 946 |  * @next:	Pointer to next hardware descriptor. | 
 | 947 |  */ | 
 | 948 | struct ksz_hw_desc { | 
 | 949 | 	union desc_stat ctrl; | 
 | 950 | 	union desc_buf buf; | 
 | 951 | 	u32 addr; | 
 | 952 | 	u32 next; | 
 | 953 | }; | 
 | 954 |  | 
 | 955 | /** | 
 | 956 |  * struct ksz_sw_desc - Software descriptor data structure | 
 | 957 |  * @ctrl:	Descriptor control value. | 
 | 958 |  * @buf:	Descriptor buffer value. | 
 | 959 |  * @buf_size:	Current buffers size value in hardware descriptor. | 
 | 960 |  */ | 
 | 961 | struct ksz_sw_desc { | 
 | 962 | 	union desc_stat ctrl; | 
 | 963 | 	union desc_buf buf; | 
 | 964 | 	u32 buf_size; | 
 | 965 | }; | 
 | 966 |  | 
 | 967 | /** | 
 | 968 |  * struct ksz_dma_buf - OS dependent DMA buffer data structure | 
 | 969 |  * @skb:	Associated socket buffer. | 
 | 970 |  * @dma:	Associated physical DMA address. | 
 | 971 |  * len:		Actual len used. | 
 | 972 |  */ | 
 | 973 | struct ksz_dma_buf { | 
 | 974 | 	struct sk_buff *skb; | 
 | 975 | 	dma_addr_t dma; | 
 | 976 | 	int len; | 
 | 977 | }; | 
 | 978 |  | 
 | 979 | /** | 
 | 980 |  * struct ksz_desc - Descriptor structure | 
 | 981 |  * @phw:	Hardware descriptor pointer to uncached physical memory. | 
 | 982 |  * @sw:		Cached memory to hold hardware descriptor values for | 
 | 983 |  * 		manipulation. | 
 | 984 |  * @dma_buf:	Operating system dependent data structure to hold physical | 
 | 985 |  * 		memory buffer allocation information. | 
 | 986 |  */ | 
 | 987 | struct ksz_desc { | 
 | 988 | 	struct ksz_hw_desc *phw; | 
 | 989 | 	struct ksz_sw_desc sw; | 
 | 990 | 	struct ksz_dma_buf dma_buf; | 
 | 991 | }; | 
 | 992 |  | 
 | 993 | #define DMA_BUFFER(desc)  ((struct ksz_dma_buf *)(&(desc)->dma_buf)) | 
 | 994 |  | 
 | 995 | /** | 
 | 996 |  * struct ksz_desc_info - Descriptor information data structure | 
 | 997 |  * @ring:	First descriptor in the ring. | 
 | 998 |  * @cur:	Current descriptor being manipulated. | 
 | 999 |  * @ring_virt:	First hardware descriptor in the ring. | 
 | 1000 |  * @ring_phys:	The physical address of the first descriptor of the ring. | 
 | 1001 |  * @size:	Size of hardware descriptor. | 
 | 1002 |  * @alloc:	Number of descriptors allocated. | 
 | 1003 |  * @avail:	Number of descriptors available for use. | 
 | 1004 |  * @last:	Index for last descriptor released to hardware. | 
 | 1005 |  * @next:	Index for next descriptor available for use. | 
 | 1006 |  * @mask:	Mask for index wrapping. | 
 | 1007 |  */ | 
 | 1008 | struct ksz_desc_info { | 
 | 1009 | 	struct ksz_desc *ring; | 
 | 1010 | 	struct ksz_desc *cur; | 
 | 1011 | 	struct ksz_hw_desc *ring_virt; | 
 | 1012 | 	u32 ring_phys; | 
 | 1013 | 	int size; | 
 | 1014 | 	int alloc; | 
 | 1015 | 	int avail; | 
 | 1016 | 	int last; | 
 | 1017 | 	int next; | 
 | 1018 | 	int mask; | 
 | 1019 | }; | 
 | 1020 |  | 
 | 1021 | /* | 
 | 1022 |  * KSZ8842 switch definitions | 
 | 1023 |  */ | 
 | 1024 |  | 
 | 1025 | enum { | 
 | 1026 | 	TABLE_STATIC_MAC = 0, | 
 | 1027 | 	TABLE_VLAN, | 
 | 1028 | 	TABLE_DYNAMIC_MAC, | 
 | 1029 | 	TABLE_MIB | 
 | 1030 | }; | 
 | 1031 |  | 
 | 1032 | #define LEARNED_MAC_TABLE_ENTRIES	1024 | 
 | 1033 | #define STATIC_MAC_TABLE_ENTRIES	8 | 
 | 1034 |  | 
 | 1035 | /** | 
 | 1036 |  * struct ksz_mac_table - Static MAC table data structure | 
 | 1037 |  * @mac_addr:	MAC address to filter. | 
 | 1038 |  * @vid:	VID value. | 
 | 1039 |  * @fid:	FID value. | 
 | 1040 |  * @ports:	Port membership. | 
 | 1041 |  * @override:	Override setting. | 
 | 1042 |  * @use_fid:	FID use setting. | 
 | 1043 |  * @valid:	Valid setting indicating the entry is being used. | 
 | 1044 |  */ | 
 | 1045 | struct ksz_mac_table { | 
 | 1046 | 	u8 mac_addr[MAC_ADDR_LEN]; | 
 | 1047 | 	u16 vid; | 
 | 1048 | 	u8 fid; | 
 | 1049 | 	u8 ports; | 
 | 1050 | 	u8 override:1; | 
 | 1051 | 	u8 use_fid:1; | 
 | 1052 | 	u8 valid:1; | 
 | 1053 | }; | 
 | 1054 |  | 
 | 1055 | #define VLAN_TABLE_ENTRIES		16 | 
 | 1056 |  | 
 | 1057 | /** | 
 | 1058 |  * struct ksz_vlan_table - VLAN table data structure | 
 | 1059 |  * @vid:	VID value. | 
 | 1060 |  * @fid:	FID value. | 
 | 1061 |  * @member:	Port membership. | 
 | 1062 |  */ | 
 | 1063 | struct ksz_vlan_table { | 
 | 1064 | 	u16 vid; | 
 | 1065 | 	u8 fid; | 
 | 1066 | 	u8 member; | 
 | 1067 | }; | 
 | 1068 |  | 
 | 1069 | #define DIFFSERV_ENTRIES		64 | 
 | 1070 | #define PRIO_802_1P_ENTRIES		8 | 
 | 1071 | #define PRIO_QUEUES			4 | 
 | 1072 |  | 
 | 1073 | #define SWITCH_PORT_NUM			2 | 
 | 1074 | #define TOTAL_PORT_NUM			(SWITCH_PORT_NUM + 1) | 
 | 1075 | #define HOST_MASK			(1 << SWITCH_PORT_NUM) | 
 | 1076 | #define PORT_MASK			7 | 
 | 1077 |  | 
 | 1078 | #define MAIN_PORT			0 | 
 | 1079 | #define OTHER_PORT			1 | 
 | 1080 | #define HOST_PORT			SWITCH_PORT_NUM | 
 | 1081 |  | 
 | 1082 | #define PORT_COUNTER_NUM		0x20 | 
 | 1083 | #define TOTAL_PORT_COUNTER_NUM		(PORT_COUNTER_NUM + 2) | 
 | 1084 |  | 
 | 1085 | #define MIB_COUNTER_RX_LO_PRIORITY	0x00 | 
 | 1086 | #define MIB_COUNTER_RX_HI_PRIORITY	0x01 | 
 | 1087 | #define MIB_COUNTER_RX_UNDERSIZE	0x02 | 
 | 1088 | #define MIB_COUNTER_RX_FRAGMENT		0x03 | 
 | 1089 | #define MIB_COUNTER_RX_OVERSIZE		0x04 | 
 | 1090 | #define MIB_COUNTER_RX_JABBER		0x05 | 
 | 1091 | #define MIB_COUNTER_RX_SYMBOL_ERR	0x06 | 
 | 1092 | #define MIB_COUNTER_RX_CRC_ERR		0x07 | 
 | 1093 | #define MIB_COUNTER_RX_ALIGNMENT_ERR	0x08 | 
 | 1094 | #define MIB_COUNTER_RX_CTRL_8808	0x09 | 
 | 1095 | #define MIB_COUNTER_RX_PAUSE		0x0A | 
 | 1096 | #define MIB_COUNTER_RX_BROADCAST	0x0B | 
 | 1097 | #define MIB_COUNTER_RX_MULTICAST	0x0C | 
 | 1098 | #define MIB_COUNTER_RX_UNICAST		0x0D | 
 | 1099 | #define MIB_COUNTER_RX_OCTET_64		0x0E | 
 | 1100 | #define MIB_COUNTER_RX_OCTET_65_127	0x0F | 
 | 1101 | #define MIB_COUNTER_RX_OCTET_128_255	0x10 | 
 | 1102 | #define MIB_COUNTER_RX_OCTET_256_511	0x11 | 
 | 1103 | #define MIB_COUNTER_RX_OCTET_512_1023	0x12 | 
 | 1104 | #define MIB_COUNTER_RX_OCTET_1024_1522	0x13 | 
 | 1105 | #define MIB_COUNTER_TX_LO_PRIORITY	0x14 | 
 | 1106 | #define MIB_COUNTER_TX_HI_PRIORITY	0x15 | 
 | 1107 | #define MIB_COUNTER_TX_LATE_COLLISION	0x16 | 
 | 1108 | #define MIB_COUNTER_TX_PAUSE		0x17 | 
 | 1109 | #define MIB_COUNTER_TX_BROADCAST	0x18 | 
 | 1110 | #define MIB_COUNTER_TX_MULTICAST	0x19 | 
 | 1111 | #define MIB_COUNTER_TX_UNICAST		0x1A | 
 | 1112 | #define MIB_COUNTER_TX_DEFERRED		0x1B | 
 | 1113 | #define MIB_COUNTER_TX_TOTAL_COLLISION	0x1C | 
 | 1114 | #define MIB_COUNTER_TX_EXCESS_COLLISION	0x1D | 
 | 1115 | #define MIB_COUNTER_TX_SINGLE_COLLISION	0x1E | 
 | 1116 | #define MIB_COUNTER_TX_MULTI_COLLISION	0x1F | 
 | 1117 |  | 
 | 1118 | #define MIB_COUNTER_RX_DROPPED_PACKET	0x20 | 
 | 1119 | #define MIB_COUNTER_TX_DROPPED_PACKET	0x21 | 
 | 1120 |  | 
 | 1121 | /** | 
 | 1122 |  * struct ksz_port_mib - Port MIB data structure | 
 | 1123 |  * @cnt_ptr:	Current pointer to MIB counter index. | 
 | 1124 |  * @link_down:	Indication the link has just gone down. | 
 | 1125 |  * @state:	Connection status of the port. | 
 | 1126 |  * @mib_start:	The starting counter index.  Some ports do not start at 0. | 
 | 1127 |  * @counter:	64-bit MIB counter value. | 
 | 1128 |  * @dropped:	Temporary buffer to remember last read packet dropped values. | 
 | 1129 |  * | 
 | 1130 |  * MIB counters needs to be read periodically so that counters do not get | 
 | 1131 |  * overflowed and give incorrect values.  A right balance is needed to | 
 | 1132 |  * satisfy this condition and not waste too much CPU time. | 
 | 1133 |  * | 
 | 1134 |  * It is pointless to read MIB counters when the port is disconnected.  The | 
 | 1135 |  * @state provides the connection status so that MIB counters are read only | 
 | 1136 |  * when the port is connected.  The @link_down indicates the port is just | 
 | 1137 |  * disconnected so that all MIB counters are read one last time to update the | 
 | 1138 |  * information. | 
 | 1139 |  */ | 
 | 1140 | struct ksz_port_mib { | 
 | 1141 | 	u8 cnt_ptr; | 
 | 1142 | 	u8 link_down; | 
 | 1143 | 	u8 state; | 
 | 1144 | 	u8 mib_start; | 
 | 1145 |  | 
 | 1146 | 	u64 counter[TOTAL_PORT_COUNTER_NUM]; | 
 | 1147 | 	u32 dropped[2]; | 
 | 1148 | }; | 
 | 1149 |  | 
 | 1150 | /** | 
 | 1151 |  * struct ksz_port_cfg - Port configuration data structure | 
 | 1152 |  * @vid:	VID value. | 
 | 1153 |  * @member:	Port membership. | 
 | 1154 |  * @port_prio:	Port priority. | 
 | 1155 |  * @rx_rate:	Receive priority rate. | 
 | 1156 |  * @tx_rate:	Transmit priority rate. | 
 | 1157 |  * @stp_state:	Current Spanning Tree Protocol state. | 
 | 1158 |  */ | 
 | 1159 | struct ksz_port_cfg { | 
 | 1160 | 	u16 vid; | 
 | 1161 | 	u8 member; | 
 | 1162 | 	u8 port_prio; | 
 | 1163 | 	u32 rx_rate[PRIO_QUEUES]; | 
 | 1164 | 	u32 tx_rate[PRIO_QUEUES]; | 
 | 1165 | 	int stp_state; | 
 | 1166 | }; | 
 | 1167 |  | 
 | 1168 | /** | 
 | 1169 |  * struct ksz_switch - KSZ8842 switch data structure | 
 | 1170 |  * @mac_table:	MAC table entries information. | 
 | 1171 |  * @vlan_table:	VLAN table entries information. | 
 | 1172 |  * @port_cfg:	Port configuration information. | 
 | 1173 |  * @diffserv:	DiffServ priority settings.  Possible values from 6-bit of ToS | 
 | 1174 |  * 		(bit7 ~ bit2) field. | 
 | 1175 |  * @p_802_1p:	802.1P priority settings.  Possible values from 3-bit of 802.1p | 
 | 1176 |  * 		Tag priority field. | 
 | 1177 |  * @br_addr:	Bridge address.  Used for STP. | 
 | 1178 |  * @other_addr:	Other MAC address.  Used for multiple network device mode. | 
 | 1179 |  * @broad_per:	Broadcast storm percentage. | 
 | 1180 |  * @member:	Current port membership.  Used for STP. | 
 | 1181 |  */ | 
 | 1182 | struct ksz_switch { | 
 | 1183 | 	struct ksz_mac_table mac_table[STATIC_MAC_TABLE_ENTRIES]; | 
 | 1184 | 	struct ksz_vlan_table vlan_table[VLAN_TABLE_ENTRIES]; | 
 | 1185 | 	struct ksz_port_cfg port_cfg[TOTAL_PORT_NUM]; | 
 | 1186 |  | 
 | 1187 | 	u8 diffserv[DIFFSERV_ENTRIES]; | 
 | 1188 | 	u8 p_802_1p[PRIO_802_1P_ENTRIES]; | 
 | 1189 |  | 
 | 1190 | 	u8 br_addr[MAC_ADDR_LEN]; | 
 | 1191 | 	u8 other_addr[MAC_ADDR_LEN]; | 
 | 1192 |  | 
 | 1193 | 	u8 broad_per; | 
 | 1194 | 	u8 member; | 
 | 1195 | }; | 
 | 1196 |  | 
 | 1197 | #define TX_RATE_UNIT			10000 | 
 | 1198 |  | 
 | 1199 | /** | 
 | 1200 |  * struct ksz_port_info - Port information data structure | 
 | 1201 |  * @state:	Connection status of the port. | 
 | 1202 |  * @tx_rate:	Transmit rate divided by 10000 to get Mbit. | 
 | 1203 |  * @duplex:	Duplex mode. | 
 | 1204 |  * @advertised:	Advertised auto-negotiation setting.  Used to determine link. | 
 | 1205 |  * @partner:	Auto-negotiation partner setting.  Used to determine link. | 
 | 1206 |  * @port_id:	Port index to access actual hardware register. | 
 | 1207 |  * @pdev:	Pointer to OS dependent network device. | 
 | 1208 |  */ | 
 | 1209 | struct ksz_port_info { | 
 | 1210 | 	uint state; | 
 | 1211 | 	uint tx_rate; | 
 | 1212 | 	u8 duplex; | 
 | 1213 | 	u8 advertised; | 
 | 1214 | 	u8 partner; | 
 | 1215 | 	u8 port_id; | 
 | 1216 | 	void *pdev; | 
 | 1217 | }; | 
 | 1218 |  | 
 | 1219 | #define MAX_TX_HELD_SIZE		52000 | 
 | 1220 |  | 
 | 1221 | /* Hardware features and bug fixes. */ | 
 | 1222 | #define LINK_INT_WORKING		(1 << 0) | 
 | 1223 | #define SMALL_PACKET_TX_BUG		(1 << 1) | 
 | 1224 | #define HALF_DUPLEX_SIGNAL_BUG		(1 << 2) | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 1225 | #define RX_HUGE_FRAME			(1 << 4) | 
 | 1226 | #define STP_SUPPORT			(1 << 8) | 
 | 1227 |  | 
 | 1228 | /* Software overrides. */ | 
 | 1229 | #define PAUSE_FLOW_CTRL			(1 << 0) | 
 | 1230 | #define FAST_AGING			(1 << 1) | 
 | 1231 |  | 
 | 1232 | /** | 
 | 1233 |  * struct ksz_hw - KSZ884X hardware data structure | 
 | 1234 |  * @io:			Virtual address assigned. | 
 | 1235 |  * @ksz_switch:		Pointer to KSZ8842 switch. | 
 | 1236 |  * @port_info:		Port information. | 
 | 1237 |  * @port_mib:		Port MIB information. | 
 | 1238 |  * @dev_count:		Number of network devices this hardware supports. | 
 | 1239 |  * @dst_ports:		Destination ports in switch for transmission. | 
 | 1240 |  * @id:			Hardware ID.  Used for display only. | 
 | 1241 |  * @mib_cnt:		Number of MIB counters this hardware has. | 
 | 1242 |  * @mib_port_cnt:	Number of ports with MIB counters. | 
 | 1243 |  * @tx_cfg:		Cached transmit control settings. | 
 | 1244 |  * @rx_cfg:		Cached receive control settings. | 
 | 1245 |  * @intr_mask:		Current interrupt mask. | 
 | 1246 |  * @intr_set:		Current interrup set. | 
 | 1247 |  * @intr_blocked:	Interrupt blocked. | 
 | 1248 |  * @rx_desc_info:	Receive descriptor information. | 
 | 1249 |  * @tx_desc_info:	Transmit descriptor information. | 
 | 1250 |  * @tx_int_cnt:		Transmit interrupt count.  Used for TX optimization. | 
 | 1251 |  * @tx_int_mask:	Transmit interrupt mask.  Used for TX optimization. | 
 | 1252 |  * @tx_size:		Transmit data size.  Used for TX optimization. | 
 | 1253 |  * 			The maximum is defined by MAX_TX_HELD_SIZE. | 
 | 1254 |  * @perm_addr:		Permanent MAC address. | 
 | 1255 |  * @override_addr:	Overrided MAC address. | 
 | 1256 |  * @address:		Additional MAC address entries. | 
 | 1257 |  * @addr_list_size:	Additional MAC address list size. | 
 | 1258 |  * @mac_override:	Indication of MAC address overrided. | 
 | 1259 |  * @promiscuous:	Counter to keep track of promiscuous mode set. | 
 | 1260 |  * @all_multi:		Counter to keep track of all multicast mode set. | 
 | 1261 |  * @multi_list:		Multicast address entries. | 
 | 1262 |  * @multi_bits:		Cached multicast hash table settings. | 
 | 1263 |  * @multi_list_size:	Multicast address list size. | 
 | 1264 |  * @enabled:		Indication of hardware enabled. | 
 | 1265 |  * @rx_stop:		Indication of receive process stop. | 
 | 1266 |  * @features:		Hardware features to enable. | 
 | 1267 |  * @overrides:		Hardware features to override. | 
 | 1268 |  * @parent:		Pointer to parent, network device private structure. | 
 | 1269 |  */ | 
 | 1270 | struct ksz_hw { | 
 | 1271 | 	void __iomem *io; | 
 | 1272 |  | 
 | 1273 | 	struct ksz_switch *ksz_switch; | 
 | 1274 | 	struct ksz_port_info port_info[SWITCH_PORT_NUM]; | 
 | 1275 | 	struct ksz_port_mib port_mib[TOTAL_PORT_NUM]; | 
 | 1276 | 	int dev_count; | 
 | 1277 | 	int dst_ports; | 
 | 1278 | 	int id; | 
 | 1279 | 	int mib_cnt; | 
 | 1280 | 	int mib_port_cnt; | 
 | 1281 |  | 
 | 1282 | 	u32 tx_cfg; | 
 | 1283 | 	u32 rx_cfg; | 
 | 1284 | 	u32 intr_mask; | 
 | 1285 | 	u32 intr_set; | 
 | 1286 | 	uint intr_blocked; | 
 | 1287 |  | 
 | 1288 | 	struct ksz_desc_info rx_desc_info; | 
 | 1289 | 	struct ksz_desc_info tx_desc_info; | 
 | 1290 |  | 
 | 1291 | 	int tx_int_cnt; | 
 | 1292 | 	int tx_int_mask; | 
 | 1293 | 	int tx_size; | 
 | 1294 |  | 
 | 1295 | 	u8 perm_addr[MAC_ADDR_LEN]; | 
 | 1296 | 	u8 override_addr[MAC_ADDR_LEN]; | 
 | 1297 | 	u8 address[ADDITIONAL_ENTRIES][MAC_ADDR_LEN]; | 
 | 1298 | 	u8 addr_list_size; | 
 | 1299 | 	u8 mac_override; | 
 | 1300 | 	u8 promiscuous; | 
 | 1301 | 	u8 all_multi; | 
 | 1302 | 	u8 multi_list[MAX_MULTICAST_LIST][MAC_ADDR_LEN]; | 
 | 1303 | 	u8 multi_bits[HW_MULTICAST_SIZE]; | 
 | 1304 | 	u8 multi_list_size; | 
 | 1305 |  | 
 | 1306 | 	u8 enabled; | 
 | 1307 | 	u8 rx_stop; | 
 | 1308 | 	u8 reserved2[1]; | 
 | 1309 |  | 
 | 1310 | 	uint features; | 
 | 1311 | 	uint overrides; | 
 | 1312 |  | 
 | 1313 | 	void *parent; | 
 | 1314 | }; | 
 | 1315 |  | 
 | 1316 | enum { | 
 | 1317 | 	PHY_NO_FLOW_CTRL, | 
 | 1318 | 	PHY_FLOW_CTRL, | 
 | 1319 | 	PHY_TX_ONLY, | 
 | 1320 | 	PHY_RX_ONLY | 
 | 1321 | }; | 
 | 1322 |  | 
 | 1323 | /** | 
 | 1324 |  * struct ksz_port - Virtual port data structure | 
 | 1325 |  * @duplex:		Duplex mode setting.  1 for half duplex, 2 for full | 
 | 1326 |  * 			duplex, and 0 for auto, which normally results in full | 
 | 1327 |  * 			duplex. | 
 | 1328 |  * @speed:		Speed setting.  10 for 10 Mbit, 100 for 100 Mbit, and | 
 | 1329 |  * 			0 for auto, which normally results in 100 Mbit. | 
 | 1330 |  * @force_link:		Force link setting.  0 for auto-negotiation, and 1 for | 
 | 1331 |  * 			force. | 
 | 1332 |  * @flow_ctrl:		Flow control setting.  PHY_NO_FLOW_CTRL for no flow | 
 | 1333 |  * 			control, and PHY_FLOW_CTRL for flow control. | 
 | 1334 |  * 			PHY_TX_ONLY and PHY_RX_ONLY are not supported for 100 | 
 | 1335 |  * 			Mbit PHY. | 
 | 1336 |  * @first_port:		Index of first port this port supports. | 
 | 1337 |  * @mib_port_cnt:	Number of ports with MIB counters. | 
 | 1338 |  * @port_cnt:		Number of ports this port supports. | 
 | 1339 |  * @counter:		Port statistics counter. | 
 | 1340 |  * @hw:			Pointer to hardware structure. | 
 | 1341 |  * @linked:		Pointer to port information linked to this port. | 
 | 1342 |  */ | 
 | 1343 | struct ksz_port { | 
 | 1344 | 	u8 duplex; | 
 | 1345 | 	u8 speed; | 
 | 1346 | 	u8 force_link; | 
 | 1347 | 	u8 flow_ctrl; | 
 | 1348 |  | 
 | 1349 | 	int first_port; | 
 | 1350 | 	int mib_port_cnt; | 
 | 1351 | 	int port_cnt; | 
 | 1352 | 	u64 counter[OID_COUNTER_LAST]; | 
 | 1353 |  | 
 | 1354 | 	struct ksz_hw *hw; | 
 | 1355 | 	struct ksz_port_info *linked; | 
 | 1356 | }; | 
 | 1357 |  | 
 | 1358 | /** | 
 | 1359 |  * struct ksz_timer_info - Timer information data structure | 
 | 1360 |  * @timer:	Kernel timer. | 
 | 1361 |  * @cnt:	Running timer counter. | 
 | 1362 |  * @max:	Number of times to run timer; -1 for infinity. | 
 | 1363 |  * @period:	Timer period in jiffies. | 
 | 1364 |  */ | 
 | 1365 | struct ksz_timer_info { | 
 | 1366 | 	struct timer_list timer; | 
 | 1367 | 	int cnt; | 
 | 1368 | 	int max; | 
 | 1369 | 	int period; | 
 | 1370 | }; | 
 | 1371 |  | 
 | 1372 | /** | 
 | 1373 |  * struct ksz_shared_mem - OS dependent shared memory data structure | 
 | 1374 |  * @dma_addr:	Physical DMA address allocated. | 
 | 1375 |  * @alloc_size:	Allocation size. | 
 | 1376 |  * @phys:	Actual physical address used. | 
 | 1377 |  * @alloc_virt:	Virtual address allocated. | 
 | 1378 |  * @virt:	Actual virtual address used. | 
 | 1379 |  */ | 
 | 1380 | struct ksz_shared_mem { | 
 | 1381 | 	dma_addr_t dma_addr; | 
 | 1382 | 	uint alloc_size; | 
 | 1383 | 	uint phys; | 
 | 1384 | 	u8 *alloc_virt; | 
 | 1385 | 	u8 *virt; | 
 | 1386 | }; | 
 | 1387 |  | 
 | 1388 | /** | 
 | 1389 |  * struct ksz_counter_info - OS dependent counter information data structure | 
 | 1390 |  * @counter:	Wait queue to wakeup after counters are read. | 
 | 1391 |  * @time:	Next time in jiffies to read counter. | 
 | 1392 |  * @read:	Indication of counters read in full or not. | 
 | 1393 |  */ | 
 | 1394 | struct ksz_counter_info { | 
 | 1395 | 	wait_queue_head_t counter; | 
 | 1396 | 	unsigned long time; | 
 | 1397 | 	int read; | 
 | 1398 | }; | 
 | 1399 |  | 
 | 1400 | /** | 
 | 1401 |  * struct dev_info - Network device information data structure | 
 | 1402 |  * @dev:		Pointer to network device. | 
 | 1403 |  * @pdev:		Pointer to PCI device. | 
 | 1404 |  * @hw:			Hardware structure. | 
 | 1405 |  * @desc_pool:		Physical memory used for descriptor pool. | 
 | 1406 |  * @hwlock:		Spinlock to prevent hardware from accessing. | 
 | 1407 |  * @lock:		Mutex lock to prevent device from accessing. | 
 | 1408 |  * @dev_rcv:		Receive process function used. | 
 | 1409 |  * @last_skb:		Socket buffer allocated for descriptor rx fragments. | 
 | 1410 |  * @skb_index:		Buffer index for receiving fragments. | 
 | 1411 |  * @skb_len:		Buffer length for receiving fragments. | 
 | 1412 |  * @mib_read:		Workqueue to read MIB counters. | 
 | 1413 |  * @mib_timer_info:	Timer to read MIB counters. | 
 | 1414 |  * @counter:		Used for MIB reading. | 
 | 1415 |  * @mtu:		Current MTU used.  The default is REGULAR_RX_BUF_SIZE; | 
 | 1416 |  * 			the maximum is MAX_RX_BUF_SIZE. | 
 | 1417 |  * @opened:		Counter to keep track of device open. | 
 | 1418 |  * @rx_tasklet:		Receive processing tasklet. | 
 | 1419 |  * @tx_tasklet:		Transmit processing tasklet. | 
 | 1420 |  * @wol_enable:		Wake-on-LAN enable set by ethtool. | 
 | 1421 |  * @wol_support:	Wake-on-LAN support used by ethtool. | 
 | 1422 |  * @pme_wait:		Used for KSZ8841 power management. | 
 | 1423 |  */ | 
 | 1424 | struct dev_info { | 
 | 1425 | 	struct net_device *dev; | 
 | 1426 | 	struct pci_dev *pdev; | 
 | 1427 |  | 
 | 1428 | 	struct ksz_hw hw; | 
 | 1429 | 	struct ksz_shared_mem desc_pool; | 
 | 1430 |  | 
 | 1431 | 	spinlock_t hwlock; | 
 | 1432 | 	struct mutex lock; | 
 | 1433 |  | 
 | 1434 | 	int (*dev_rcv)(struct dev_info *); | 
 | 1435 |  | 
 | 1436 | 	struct sk_buff *last_skb; | 
 | 1437 | 	int skb_index; | 
 | 1438 | 	int skb_len; | 
 | 1439 |  | 
 | 1440 | 	struct work_struct mib_read; | 
 | 1441 | 	struct ksz_timer_info mib_timer_info; | 
 | 1442 | 	struct ksz_counter_info counter[TOTAL_PORT_NUM]; | 
 | 1443 |  | 
 | 1444 | 	int mtu; | 
 | 1445 | 	int opened; | 
 | 1446 |  | 
 | 1447 | 	struct tasklet_struct rx_tasklet; | 
 | 1448 | 	struct tasklet_struct tx_tasklet; | 
 | 1449 |  | 
 | 1450 | 	int wol_enable; | 
 | 1451 | 	int wol_support; | 
 | 1452 | 	unsigned long pme_wait; | 
 | 1453 | }; | 
 | 1454 |  | 
 | 1455 | /** | 
 | 1456 |  * struct dev_priv - Network device private data structure | 
 | 1457 |  * @adapter:		Adapter device information. | 
 | 1458 |  * @port:		Port information. | 
 | 1459 |  * @monitor_time_info:	Timer to monitor ports. | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 1460 |  * @proc_sem:		Semaphore for proc accessing. | 
 | 1461 |  * @id:			Device ID. | 
 | 1462 |  * @mii_if:		MII interface information. | 
 | 1463 |  * @advertising:	Temporary variable to store advertised settings. | 
 | 1464 |  * @msg_enable:		The message flags controlling driver output. | 
 | 1465 |  * @media_state:	The connection status of the device. | 
 | 1466 |  * @multicast:		The all multicast state of the device. | 
 | 1467 |  * @promiscuous:	The promiscuous state of the device. | 
 | 1468 |  */ | 
 | 1469 | struct dev_priv { | 
 | 1470 | 	struct dev_info *adapter; | 
 | 1471 | 	struct ksz_port port; | 
 | 1472 | 	struct ksz_timer_info monitor_timer_info; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 1473 |  | 
 | 1474 | 	struct semaphore proc_sem; | 
 | 1475 | 	int id; | 
 | 1476 |  | 
 | 1477 | 	struct mii_if_info mii_if; | 
 | 1478 | 	u32 advertising; | 
 | 1479 |  | 
 | 1480 | 	u32 msg_enable; | 
 | 1481 | 	int media_state; | 
 | 1482 | 	int multicast; | 
 | 1483 | 	int promiscuous; | 
 | 1484 | }; | 
 | 1485 |  | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 1486 | #define DRV_NAME		"KSZ884X PCI" | 
 | 1487 | #define DEVICE_NAME		"KSZ884x PCI" | 
 | 1488 | #define DRV_VERSION		"1.0.0" | 
 | 1489 | #define DRV_RELDATE		"Feb 8, 2010" | 
 | 1490 |  | 
 | 1491 | static char version[] __devinitdata = | 
 | 1492 | 	"Micrel " DEVICE_NAME " " DRV_VERSION " (" DRV_RELDATE ")"; | 
 | 1493 |  | 
 | 1494 | static u8 DEFAULT_MAC_ADDRESS[] = { 0x00, 0x10, 0xA1, 0x88, 0x42, 0x01 }; | 
 | 1495 |  | 
 | 1496 | /* | 
 | 1497 |  * Interrupt processing primary routines | 
 | 1498 |  */ | 
 | 1499 |  | 
 | 1500 | static inline void hw_ack_intr(struct ksz_hw *hw, uint interrupt) | 
 | 1501 | { | 
 | 1502 | 	writel(interrupt, hw->io + KS884X_INTERRUPTS_STATUS); | 
 | 1503 | } | 
 | 1504 |  | 
 | 1505 | static inline void hw_dis_intr(struct ksz_hw *hw) | 
 | 1506 | { | 
 | 1507 | 	hw->intr_blocked = hw->intr_mask; | 
 | 1508 | 	writel(0, hw->io + KS884X_INTERRUPTS_ENABLE); | 
 | 1509 | 	hw->intr_set = readl(hw->io + KS884X_INTERRUPTS_ENABLE); | 
 | 1510 | } | 
 | 1511 |  | 
 | 1512 | static inline void hw_set_intr(struct ksz_hw *hw, uint interrupt) | 
 | 1513 | { | 
 | 1514 | 	hw->intr_set = interrupt; | 
 | 1515 | 	writel(interrupt, hw->io + KS884X_INTERRUPTS_ENABLE); | 
 | 1516 | } | 
 | 1517 |  | 
 | 1518 | static inline void hw_ena_intr(struct ksz_hw *hw) | 
 | 1519 | { | 
 | 1520 | 	hw->intr_blocked = 0; | 
 | 1521 | 	hw_set_intr(hw, hw->intr_mask); | 
 | 1522 | } | 
 | 1523 |  | 
 | 1524 | static inline void hw_dis_intr_bit(struct ksz_hw *hw, uint bit) | 
 | 1525 | { | 
 | 1526 | 	hw->intr_mask &= ~(bit); | 
 | 1527 | } | 
 | 1528 |  | 
 | 1529 | static inline void hw_turn_off_intr(struct ksz_hw *hw, uint interrupt) | 
 | 1530 | { | 
 | 1531 | 	u32 read_intr; | 
 | 1532 |  | 
 | 1533 | 	read_intr = readl(hw->io + KS884X_INTERRUPTS_ENABLE); | 
 | 1534 | 	hw->intr_set = read_intr & ~interrupt; | 
 | 1535 | 	writel(hw->intr_set, hw->io + KS884X_INTERRUPTS_ENABLE); | 
 | 1536 | 	hw_dis_intr_bit(hw, interrupt); | 
 | 1537 | } | 
 | 1538 |  | 
 | 1539 | /** | 
 | 1540 |  * hw_turn_on_intr - turn on specified interrupts | 
 | 1541 |  * @hw: 	The hardware instance. | 
 | 1542 |  * @bit:	The interrupt bits to be on. | 
 | 1543 |  * | 
 | 1544 |  * This routine turns on the specified interrupts in the interrupt mask so that | 
 | 1545 |  * those interrupts will be enabled. | 
 | 1546 |  */ | 
 | 1547 | static void hw_turn_on_intr(struct ksz_hw *hw, u32 bit) | 
 | 1548 | { | 
 | 1549 | 	hw->intr_mask |= bit; | 
 | 1550 |  | 
 | 1551 | 	if (!hw->intr_blocked) | 
 | 1552 | 		hw_set_intr(hw, hw->intr_mask); | 
 | 1553 | } | 
 | 1554 |  | 
 | 1555 | static inline void hw_ena_intr_bit(struct ksz_hw *hw, uint interrupt) | 
 | 1556 | { | 
 | 1557 | 	u32 read_intr; | 
 | 1558 |  | 
 | 1559 | 	read_intr = readl(hw->io + KS884X_INTERRUPTS_ENABLE); | 
 | 1560 | 	hw->intr_set = read_intr | interrupt; | 
 | 1561 | 	writel(hw->intr_set, hw->io + KS884X_INTERRUPTS_ENABLE); | 
 | 1562 | } | 
 | 1563 |  | 
 | 1564 | static inline void hw_read_intr(struct ksz_hw *hw, uint *status) | 
 | 1565 | { | 
 | 1566 | 	*status = readl(hw->io + KS884X_INTERRUPTS_STATUS); | 
 | 1567 | 	*status = *status & hw->intr_set; | 
 | 1568 | } | 
 | 1569 |  | 
 | 1570 | static inline void hw_restore_intr(struct ksz_hw *hw, uint interrupt) | 
 | 1571 | { | 
 | 1572 | 	if (interrupt) | 
 | 1573 | 		hw_ena_intr(hw); | 
 | 1574 | } | 
 | 1575 |  | 
 | 1576 | /** | 
 | 1577 |  * hw_block_intr - block hardware interrupts | 
 | 1578 |  * | 
 | 1579 |  * This function blocks all interrupts of the hardware and returns the current | 
 | 1580 |  * interrupt enable mask so that interrupts can be restored later. | 
 | 1581 |  * | 
 | 1582 |  * Return the current interrupt enable mask. | 
 | 1583 |  */ | 
 | 1584 | static uint hw_block_intr(struct ksz_hw *hw) | 
 | 1585 | { | 
 | 1586 | 	uint interrupt = 0; | 
 | 1587 |  | 
 | 1588 | 	if (!hw->intr_blocked) { | 
 | 1589 | 		hw_dis_intr(hw); | 
 | 1590 | 		interrupt = hw->intr_blocked; | 
 | 1591 | 	} | 
 | 1592 | 	return interrupt; | 
 | 1593 | } | 
 | 1594 |  | 
 | 1595 | /* | 
 | 1596 |  * Hardware descriptor routines | 
 | 1597 |  */ | 
 | 1598 |  | 
 | 1599 | static inline void reset_desc(struct ksz_desc *desc, union desc_stat status) | 
 | 1600 | { | 
 | 1601 | 	status.rx.hw_owned = 0; | 
 | 1602 | 	desc->phw->ctrl.data = cpu_to_le32(status.data); | 
 | 1603 | } | 
 | 1604 |  | 
 | 1605 | static inline void release_desc(struct ksz_desc *desc) | 
 | 1606 | { | 
 | 1607 | 	desc->sw.ctrl.tx.hw_owned = 1; | 
 | 1608 | 	if (desc->sw.buf_size != desc->sw.buf.data) { | 
 | 1609 | 		desc->sw.buf_size = desc->sw.buf.data; | 
 | 1610 | 		desc->phw->buf.data = cpu_to_le32(desc->sw.buf.data); | 
 | 1611 | 	} | 
 | 1612 | 	desc->phw->ctrl.data = cpu_to_le32(desc->sw.ctrl.data); | 
 | 1613 | } | 
 | 1614 |  | 
 | 1615 | static void get_rx_pkt(struct ksz_desc_info *info, struct ksz_desc **desc) | 
 | 1616 | { | 
 | 1617 | 	*desc = &info->ring[info->last]; | 
 | 1618 | 	info->last++; | 
 | 1619 | 	info->last &= info->mask; | 
 | 1620 | 	info->avail--; | 
 | 1621 | 	(*desc)->sw.buf.data &= ~KS_DESC_RX_MASK; | 
 | 1622 | } | 
 | 1623 |  | 
 | 1624 | static inline void set_rx_buf(struct ksz_desc *desc, u32 addr) | 
 | 1625 | { | 
 | 1626 | 	desc->phw->addr = cpu_to_le32(addr); | 
 | 1627 | } | 
 | 1628 |  | 
 | 1629 | static inline void set_rx_len(struct ksz_desc *desc, u32 len) | 
 | 1630 | { | 
 | 1631 | 	desc->sw.buf.rx.buf_size = len; | 
 | 1632 | } | 
 | 1633 |  | 
 | 1634 | static inline void get_tx_pkt(struct ksz_desc_info *info, | 
 | 1635 | 	struct ksz_desc **desc) | 
 | 1636 | { | 
 | 1637 | 	*desc = &info->ring[info->next]; | 
 | 1638 | 	info->next++; | 
 | 1639 | 	info->next &= info->mask; | 
 | 1640 | 	info->avail--; | 
 | 1641 | 	(*desc)->sw.buf.data &= ~KS_DESC_TX_MASK; | 
 | 1642 | } | 
 | 1643 |  | 
 | 1644 | static inline void set_tx_buf(struct ksz_desc *desc, u32 addr) | 
 | 1645 | { | 
 | 1646 | 	desc->phw->addr = cpu_to_le32(addr); | 
 | 1647 | } | 
 | 1648 |  | 
 | 1649 | static inline void set_tx_len(struct ksz_desc *desc, u32 len) | 
 | 1650 | { | 
 | 1651 | 	desc->sw.buf.tx.buf_size = len; | 
 | 1652 | } | 
 | 1653 |  | 
 | 1654 | /* Switch functions */ | 
 | 1655 |  | 
 | 1656 | #define TABLE_READ			0x10 | 
 | 1657 | #define TABLE_SEL_SHIFT			2 | 
 | 1658 |  | 
 | 1659 | #define HW_DELAY(hw, reg)			\ | 
 | 1660 | 	do {					\ | 
 | 1661 | 		u16 dummy;			\ | 
 | 1662 | 		dummy = readw(hw->io + reg);	\ | 
 | 1663 | 	} while (0) | 
 | 1664 |  | 
 | 1665 | /** | 
 | 1666 |  * sw_r_table - read 4 bytes of data from switch table | 
 | 1667 |  * @hw:		The hardware instance. | 
 | 1668 |  * @table:	The table selector. | 
 | 1669 |  * @addr:	The address of the table entry. | 
 | 1670 |  * @data:	Buffer to store the read data. | 
 | 1671 |  * | 
 | 1672 |  * This routine reads 4 bytes of data from the table of the switch. | 
 | 1673 |  * Hardware interrupts are disabled to minimize corruption of read data. | 
 | 1674 |  */ | 
 | 1675 | static void sw_r_table(struct ksz_hw *hw, int table, u16 addr, u32 *data) | 
 | 1676 | { | 
 | 1677 | 	u16 ctrl_addr; | 
 | 1678 | 	uint interrupt; | 
 | 1679 |  | 
 | 1680 | 	ctrl_addr = (((table << TABLE_SEL_SHIFT) | TABLE_READ) << 8) | addr; | 
 | 1681 |  | 
 | 1682 | 	interrupt = hw_block_intr(hw); | 
 | 1683 |  | 
 | 1684 | 	writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET); | 
 | 1685 | 	HW_DELAY(hw, KS884X_IACR_OFFSET); | 
 | 1686 | 	*data = readl(hw->io + KS884X_ACC_DATA_0_OFFSET); | 
 | 1687 |  | 
 | 1688 | 	hw_restore_intr(hw, interrupt); | 
 | 1689 | } | 
 | 1690 |  | 
 | 1691 | /** | 
 | 1692 |  * sw_w_table_64 - write 8 bytes of data to the switch table | 
 | 1693 |  * @hw:		The hardware instance. | 
 | 1694 |  * @table:	The table selector. | 
 | 1695 |  * @addr:	The address of the table entry. | 
 | 1696 |  * @data_hi:	The high part of data to be written (bit63 ~ bit32). | 
 | 1697 |  * @data_lo:	The low part of data to be written (bit31 ~ bit0). | 
 | 1698 |  * | 
 | 1699 |  * This routine writes 8 bytes of data to the table of the switch. | 
 | 1700 |  * Hardware interrupts are disabled to minimize corruption of written data. | 
 | 1701 |  */ | 
 | 1702 | static void sw_w_table_64(struct ksz_hw *hw, int table, u16 addr, u32 data_hi, | 
 | 1703 | 	u32 data_lo) | 
 | 1704 | { | 
 | 1705 | 	u16 ctrl_addr; | 
 | 1706 | 	uint interrupt; | 
 | 1707 |  | 
 | 1708 | 	ctrl_addr = ((table << TABLE_SEL_SHIFT) << 8) | addr; | 
 | 1709 |  | 
 | 1710 | 	interrupt = hw_block_intr(hw); | 
 | 1711 |  | 
 | 1712 | 	writel(data_hi, hw->io + KS884X_ACC_DATA_4_OFFSET); | 
 | 1713 | 	writel(data_lo, hw->io + KS884X_ACC_DATA_0_OFFSET); | 
 | 1714 |  | 
 | 1715 | 	writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET); | 
 | 1716 | 	HW_DELAY(hw, KS884X_IACR_OFFSET); | 
 | 1717 |  | 
 | 1718 | 	hw_restore_intr(hw, interrupt); | 
 | 1719 | } | 
 | 1720 |  | 
 | 1721 | /** | 
 | 1722 |  * sw_w_sta_mac_table - write to the static MAC table | 
 | 1723 |  * @hw: 	The hardware instance. | 
 | 1724 |  * @addr:	The address of the table entry. | 
 | 1725 |  * @mac_addr:	The MAC address. | 
 | 1726 |  * @ports:	The port members. | 
 | 1727 |  * @override:	The flag to override the port receive/transmit settings. | 
 | 1728 |  * @valid:	The flag to indicate entry is valid. | 
 | 1729 |  * @use_fid:	The flag to indicate the FID is valid. | 
 | 1730 |  * @fid:	The FID value. | 
 | 1731 |  * | 
 | 1732 |  * This routine writes an entry of the static MAC table of the switch.  It | 
 | 1733 |  * calls sw_w_table_64() to write the data. | 
 | 1734 |  */ | 
 | 1735 | static void sw_w_sta_mac_table(struct ksz_hw *hw, u16 addr, u8 *mac_addr, | 
 | 1736 | 	u8 ports, int override, int valid, int use_fid, u8 fid) | 
 | 1737 | { | 
 | 1738 | 	u32 data_hi; | 
 | 1739 | 	u32 data_lo; | 
 | 1740 |  | 
 | 1741 | 	data_lo = ((u32) mac_addr[2] << 24) | | 
 | 1742 | 		((u32) mac_addr[3] << 16) | | 
 | 1743 | 		((u32) mac_addr[4] << 8) | mac_addr[5]; | 
 | 1744 | 	data_hi = ((u32) mac_addr[0] << 8) | mac_addr[1]; | 
 | 1745 | 	data_hi |= (u32) ports << STATIC_MAC_FWD_PORTS_SHIFT; | 
 | 1746 |  | 
 | 1747 | 	if (override) | 
 | 1748 | 		data_hi |= STATIC_MAC_TABLE_OVERRIDE; | 
 | 1749 | 	if (use_fid) { | 
 | 1750 | 		data_hi |= STATIC_MAC_TABLE_USE_FID; | 
 | 1751 | 		data_hi |= (u32) fid << STATIC_MAC_FID_SHIFT; | 
 | 1752 | 	} | 
 | 1753 | 	if (valid) | 
 | 1754 | 		data_hi |= STATIC_MAC_TABLE_VALID; | 
 | 1755 |  | 
 | 1756 | 	sw_w_table_64(hw, TABLE_STATIC_MAC, addr, data_hi, data_lo); | 
 | 1757 | } | 
 | 1758 |  | 
 | 1759 | /** | 
 | 1760 |  * sw_r_vlan_table - read from the VLAN table | 
 | 1761 |  * @hw: 	The hardware instance. | 
 | 1762 |  * @addr:	The address of the table entry. | 
 | 1763 |  * @vid:	Buffer to store the VID. | 
 | 1764 |  * @fid:	Buffer to store the VID. | 
 | 1765 |  * @member:	Buffer to store the port membership. | 
 | 1766 |  * | 
 | 1767 |  * This function reads an entry of the VLAN table of the switch.  It calls | 
 | 1768 |  * sw_r_table() to get the data. | 
 | 1769 |  * | 
 | 1770 |  * Return 0 if the entry is valid; otherwise -1. | 
 | 1771 |  */ | 
 | 1772 | static int sw_r_vlan_table(struct ksz_hw *hw, u16 addr, u16 *vid, u8 *fid, | 
 | 1773 | 	u8 *member) | 
 | 1774 | { | 
 | 1775 | 	u32 data; | 
 | 1776 |  | 
 | 1777 | 	sw_r_table(hw, TABLE_VLAN, addr, &data); | 
 | 1778 | 	if (data & VLAN_TABLE_VALID) { | 
 | 1779 | 		*vid = (u16)(data & VLAN_TABLE_VID); | 
 | 1780 | 		*fid = (u8)((data & VLAN_TABLE_FID) >> VLAN_TABLE_FID_SHIFT); | 
 | 1781 | 		*member = (u8)((data & VLAN_TABLE_MEMBERSHIP) >> | 
 | 1782 | 			VLAN_TABLE_MEMBERSHIP_SHIFT); | 
 | 1783 | 		return 0; | 
 | 1784 | 	} | 
 | 1785 | 	return -1; | 
 | 1786 | } | 
 | 1787 |  | 
 | 1788 | /** | 
 | 1789 |  * port_r_mib_cnt - read MIB counter | 
 | 1790 |  * @hw: 	The hardware instance. | 
 | 1791 |  * @port:	The port index. | 
 | 1792 |  * @addr:	The address of the counter. | 
 | 1793 |  * @cnt:	Buffer to store the counter. | 
 | 1794 |  * | 
 | 1795 |  * This routine reads a MIB counter of the port. | 
 | 1796 |  * Hardware interrupts are disabled to minimize corruption of read data. | 
 | 1797 |  */ | 
 | 1798 | static void port_r_mib_cnt(struct ksz_hw *hw, int port, u16 addr, u64 *cnt) | 
 | 1799 | { | 
 | 1800 | 	u32 data; | 
 | 1801 | 	u16 ctrl_addr; | 
 | 1802 | 	uint interrupt; | 
 | 1803 | 	int timeout; | 
 | 1804 |  | 
 | 1805 | 	ctrl_addr = addr + PORT_COUNTER_NUM * port; | 
 | 1806 |  | 
 | 1807 | 	interrupt = hw_block_intr(hw); | 
 | 1808 |  | 
 | 1809 | 	ctrl_addr |= (((TABLE_MIB << TABLE_SEL_SHIFT) | TABLE_READ) << 8); | 
 | 1810 | 	writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET); | 
 | 1811 | 	HW_DELAY(hw, KS884X_IACR_OFFSET); | 
 | 1812 |  | 
 | 1813 | 	for (timeout = 100; timeout > 0; timeout--) { | 
 | 1814 | 		data = readl(hw->io + KS884X_ACC_DATA_0_OFFSET); | 
 | 1815 |  | 
 | 1816 | 		if (data & MIB_COUNTER_VALID) { | 
 | 1817 | 			if (data & MIB_COUNTER_OVERFLOW) | 
 | 1818 | 				*cnt += MIB_COUNTER_VALUE + 1; | 
 | 1819 | 			*cnt += data & MIB_COUNTER_VALUE; | 
 | 1820 | 			break; | 
 | 1821 | 		} | 
 | 1822 | 	} | 
 | 1823 |  | 
 | 1824 | 	hw_restore_intr(hw, interrupt); | 
 | 1825 | } | 
 | 1826 |  | 
 | 1827 | /** | 
 | 1828 |  * port_r_mib_pkt - read dropped packet counts | 
 | 1829 |  * @hw: 	The hardware instance. | 
 | 1830 |  * @port:	The port index. | 
 | 1831 |  * @cnt:	Buffer to store the receive and transmit dropped packet counts. | 
 | 1832 |  * | 
 | 1833 |  * This routine reads the dropped packet counts of the port. | 
 | 1834 |  * Hardware interrupts are disabled to minimize corruption of read data. | 
 | 1835 |  */ | 
 | 1836 | static void port_r_mib_pkt(struct ksz_hw *hw, int port, u32 *last, u64 *cnt) | 
 | 1837 | { | 
 | 1838 | 	u32 cur; | 
 | 1839 | 	u32 data; | 
 | 1840 | 	u16 ctrl_addr; | 
 | 1841 | 	uint interrupt; | 
 | 1842 | 	int index; | 
 | 1843 |  | 
 | 1844 | 	index = KS_MIB_PACKET_DROPPED_RX_0 + port; | 
 | 1845 | 	do { | 
 | 1846 | 		interrupt = hw_block_intr(hw); | 
 | 1847 |  | 
 | 1848 | 		ctrl_addr = (u16) index; | 
 | 1849 | 		ctrl_addr |= (((TABLE_MIB << TABLE_SEL_SHIFT) | TABLE_READ) | 
 | 1850 | 			<< 8); | 
 | 1851 | 		writew(ctrl_addr, hw->io + KS884X_IACR_OFFSET); | 
 | 1852 | 		HW_DELAY(hw, KS884X_IACR_OFFSET); | 
 | 1853 | 		data = readl(hw->io + KS884X_ACC_DATA_0_OFFSET); | 
 | 1854 |  | 
 | 1855 | 		hw_restore_intr(hw, interrupt); | 
 | 1856 |  | 
 | 1857 | 		data &= MIB_PACKET_DROPPED; | 
 | 1858 | 		cur = *last; | 
 | 1859 | 		if (data != cur) { | 
 | 1860 | 			*last = data; | 
 | 1861 | 			if (data < cur) | 
 | 1862 | 				data += MIB_PACKET_DROPPED + 1; | 
 | 1863 | 			data -= cur; | 
 | 1864 | 			*cnt += data; | 
 | 1865 | 		} | 
 | 1866 | 		++last; | 
 | 1867 | 		++cnt; | 
 | 1868 | 		index -= KS_MIB_PACKET_DROPPED_TX - | 
 | 1869 | 			KS_MIB_PACKET_DROPPED_TX_0 + 1; | 
 | 1870 | 	} while (index >= KS_MIB_PACKET_DROPPED_TX_0 + port); | 
 | 1871 | } | 
 | 1872 |  | 
 | 1873 | /** | 
 | 1874 |  * port_r_cnt - read MIB counters periodically | 
 | 1875 |  * @hw: 	The hardware instance. | 
 | 1876 |  * @port:	The port index. | 
 | 1877 |  * | 
 | 1878 |  * This routine is used to read the counters of the port periodically to avoid | 
 | 1879 |  * counter overflow.  The hardware should be acquired first before calling this | 
 | 1880 |  * routine. | 
 | 1881 |  * | 
 | 1882 |  * Return non-zero when not all counters not read. | 
 | 1883 |  */ | 
 | 1884 | static int port_r_cnt(struct ksz_hw *hw, int port) | 
 | 1885 | { | 
 | 1886 | 	struct ksz_port_mib *mib = &hw->port_mib[port]; | 
 | 1887 |  | 
 | 1888 | 	if (mib->mib_start < PORT_COUNTER_NUM) | 
 | 1889 | 		while (mib->cnt_ptr < PORT_COUNTER_NUM) { | 
 | 1890 | 			port_r_mib_cnt(hw, port, mib->cnt_ptr, | 
 | 1891 | 				&mib->counter[mib->cnt_ptr]); | 
 | 1892 | 			++mib->cnt_ptr; | 
 | 1893 | 		} | 
 | 1894 | 	if (hw->mib_cnt > PORT_COUNTER_NUM) | 
 | 1895 | 		port_r_mib_pkt(hw, port, mib->dropped, | 
 | 1896 | 			&mib->counter[PORT_COUNTER_NUM]); | 
 | 1897 | 	mib->cnt_ptr = 0; | 
 | 1898 | 	return 0; | 
 | 1899 | } | 
 | 1900 |  | 
 | 1901 | /** | 
 | 1902 |  * port_init_cnt - initialize MIB counter values | 
 | 1903 |  * @hw: 	The hardware instance. | 
 | 1904 |  * @port:	The port index. | 
 | 1905 |  * | 
 | 1906 |  * This routine is used to initialize all counters to zero if the hardware | 
 | 1907 |  * cannot do it after reset. | 
 | 1908 |  */ | 
 | 1909 | static void port_init_cnt(struct ksz_hw *hw, int port) | 
 | 1910 | { | 
 | 1911 | 	struct ksz_port_mib *mib = &hw->port_mib[port]; | 
 | 1912 |  | 
 | 1913 | 	mib->cnt_ptr = 0; | 
 | 1914 | 	if (mib->mib_start < PORT_COUNTER_NUM) | 
 | 1915 | 		do { | 
 | 1916 | 			port_r_mib_cnt(hw, port, mib->cnt_ptr, | 
 | 1917 | 				&mib->counter[mib->cnt_ptr]); | 
 | 1918 | 			++mib->cnt_ptr; | 
 | 1919 | 		} while (mib->cnt_ptr < PORT_COUNTER_NUM); | 
 | 1920 | 	if (hw->mib_cnt > PORT_COUNTER_NUM) | 
 | 1921 | 		port_r_mib_pkt(hw, port, mib->dropped, | 
 | 1922 | 			&mib->counter[PORT_COUNTER_NUM]); | 
 | 1923 | 	memset((void *) mib->counter, 0, sizeof(u64) * TOTAL_PORT_COUNTER_NUM); | 
 | 1924 | 	mib->cnt_ptr = 0; | 
 | 1925 | } | 
 | 1926 |  | 
 | 1927 | /* | 
 | 1928 |  * Port functions | 
 | 1929 |  */ | 
 | 1930 |  | 
 | 1931 | /** | 
 | 1932 |  * port_chk - check port register bits | 
 | 1933 |  * @hw: 	The hardware instance. | 
 | 1934 |  * @port:	The port index. | 
 | 1935 |  * @offset:	The offset of the port register. | 
 | 1936 |  * @bits:	The data bits to check. | 
 | 1937 |  * | 
 | 1938 |  * This function checks whether the specified bits of the port register are set | 
 | 1939 |  * or not. | 
 | 1940 |  * | 
 | 1941 |  * Return 0 if the bits are not set. | 
 | 1942 |  */ | 
 | 1943 | static int port_chk(struct ksz_hw *hw, int port, int offset, u16 bits) | 
 | 1944 | { | 
 | 1945 | 	u32 addr; | 
 | 1946 | 	u16 data; | 
 | 1947 |  | 
 | 1948 | 	PORT_CTRL_ADDR(port, addr); | 
 | 1949 | 	addr += offset; | 
 | 1950 | 	data = readw(hw->io + addr); | 
 | 1951 | 	return (data & bits) == bits; | 
 | 1952 | } | 
 | 1953 |  | 
 | 1954 | /** | 
 | 1955 |  * port_cfg - set port register bits | 
 | 1956 |  * @hw: 	The hardware instance. | 
 | 1957 |  * @port:	The port index. | 
 | 1958 |  * @offset:	The offset of the port register. | 
 | 1959 |  * @bits:	The data bits to set. | 
 | 1960 |  * @set:	The flag indicating whether the bits are to be set or not. | 
 | 1961 |  * | 
 | 1962 |  * This routine sets or resets the specified bits of the port register. | 
 | 1963 |  */ | 
 | 1964 | static void port_cfg(struct ksz_hw *hw, int port, int offset, u16 bits, | 
 | 1965 | 	int set) | 
 | 1966 | { | 
 | 1967 | 	u32 addr; | 
 | 1968 | 	u16 data; | 
 | 1969 |  | 
 | 1970 | 	PORT_CTRL_ADDR(port, addr); | 
 | 1971 | 	addr += offset; | 
 | 1972 | 	data = readw(hw->io + addr); | 
 | 1973 | 	if (set) | 
 | 1974 | 		data |= bits; | 
 | 1975 | 	else | 
 | 1976 | 		data &= ~bits; | 
 | 1977 | 	writew(data, hw->io + addr); | 
 | 1978 | } | 
 | 1979 |  | 
 | 1980 | /** | 
 | 1981 |  * port_chk_shift - check port bit | 
 | 1982 |  * @hw: 	The hardware instance. | 
 | 1983 |  * @port:	The port index. | 
 | 1984 |  * @offset:	The offset of the register. | 
 | 1985 |  * @shift:	Number of bits to shift. | 
 | 1986 |  * | 
 | 1987 |  * This function checks whether the specified port is set in the register or | 
 | 1988 |  * not. | 
 | 1989 |  * | 
 | 1990 |  * Return 0 if the port is not set. | 
 | 1991 |  */ | 
 | 1992 | static int port_chk_shift(struct ksz_hw *hw, int port, u32 addr, int shift) | 
 | 1993 | { | 
 | 1994 | 	u16 data; | 
 | 1995 | 	u16 bit = 1 << port; | 
 | 1996 |  | 
 | 1997 | 	data = readw(hw->io + addr); | 
 | 1998 | 	data >>= shift; | 
 | 1999 | 	return (data & bit) == bit; | 
 | 2000 | } | 
 | 2001 |  | 
 | 2002 | /** | 
 | 2003 |  * port_cfg_shift - set port bit | 
 | 2004 |  * @hw: 	The hardware instance. | 
 | 2005 |  * @port:	The port index. | 
 | 2006 |  * @offset:	The offset of the register. | 
 | 2007 |  * @shift:	Number of bits to shift. | 
 | 2008 |  * @set:	The flag indicating whether the port is to be set or not. | 
 | 2009 |  * | 
 | 2010 |  * This routine sets or resets the specified port in the register. | 
 | 2011 |  */ | 
 | 2012 | static void port_cfg_shift(struct ksz_hw *hw, int port, u32 addr, int shift, | 
 | 2013 | 	int set) | 
 | 2014 | { | 
 | 2015 | 	u16 data; | 
 | 2016 | 	u16 bits = 1 << port; | 
 | 2017 |  | 
 | 2018 | 	data = readw(hw->io + addr); | 
 | 2019 | 	bits <<= shift; | 
 | 2020 | 	if (set) | 
 | 2021 | 		data |= bits; | 
 | 2022 | 	else | 
 | 2023 | 		data &= ~bits; | 
 | 2024 | 	writew(data, hw->io + addr); | 
 | 2025 | } | 
 | 2026 |  | 
 | 2027 | /** | 
 | 2028 |  * port_r8 - read byte from port register | 
 | 2029 |  * @hw: 	The hardware instance. | 
 | 2030 |  * @port:	The port index. | 
 | 2031 |  * @offset:	The offset of the port register. | 
 | 2032 |  * @data:	Buffer to store the data. | 
 | 2033 |  * | 
 | 2034 |  * This routine reads a byte from the port register. | 
 | 2035 |  */ | 
 | 2036 | static void port_r8(struct ksz_hw *hw, int port, int offset, u8 *data) | 
 | 2037 | { | 
 | 2038 | 	u32 addr; | 
 | 2039 |  | 
 | 2040 | 	PORT_CTRL_ADDR(port, addr); | 
 | 2041 | 	addr += offset; | 
 | 2042 | 	*data = readb(hw->io + addr); | 
 | 2043 | } | 
 | 2044 |  | 
 | 2045 | /** | 
 | 2046 |  * port_r16 - read word from port register. | 
 | 2047 |  * @hw: 	The hardware instance. | 
 | 2048 |  * @port:	The port index. | 
 | 2049 |  * @offset:	The offset of the port register. | 
 | 2050 |  * @data:	Buffer to store the data. | 
 | 2051 |  * | 
 | 2052 |  * This routine reads a word from the port register. | 
 | 2053 |  */ | 
 | 2054 | static void port_r16(struct ksz_hw *hw, int port, int offset, u16 *data) | 
 | 2055 | { | 
 | 2056 | 	u32 addr; | 
 | 2057 |  | 
 | 2058 | 	PORT_CTRL_ADDR(port, addr); | 
 | 2059 | 	addr += offset; | 
 | 2060 | 	*data = readw(hw->io + addr); | 
 | 2061 | } | 
 | 2062 |  | 
 | 2063 | /** | 
 | 2064 |  * port_w16 - write word to port register. | 
 | 2065 |  * @hw: 	The hardware instance. | 
 | 2066 |  * @port:	The port index. | 
 | 2067 |  * @offset:	The offset of the port register. | 
 | 2068 |  * @data:	Data to write. | 
 | 2069 |  * | 
 | 2070 |  * This routine writes a word to the port register. | 
 | 2071 |  */ | 
 | 2072 | static void port_w16(struct ksz_hw *hw, int port, int offset, u16 data) | 
 | 2073 | { | 
 | 2074 | 	u32 addr; | 
 | 2075 |  | 
 | 2076 | 	PORT_CTRL_ADDR(port, addr); | 
 | 2077 | 	addr += offset; | 
 | 2078 | 	writew(data, hw->io + addr); | 
 | 2079 | } | 
 | 2080 |  | 
 | 2081 | /** | 
 | 2082 |  * sw_chk - check switch register bits | 
 | 2083 |  * @hw: 	The hardware instance. | 
 | 2084 |  * @addr:	The address of the switch register. | 
 | 2085 |  * @bits:	The data bits to check. | 
 | 2086 |  * | 
 | 2087 |  * This function checks whether the specified bits of the switch register are | 
 | 2088 |  * set or not. | 
 | 2089 |  * | 
 | 2090 |  * Return 0 if the bits are not set. | 
 | 2091 |  */ | 
 | 2092 | static int sw_chk(struct ksz_hw *hw, u32 addr, u16 bits) | 
 | 2093 | { | 
 | 2094 | 	u16 data; | 
 | 2095 |  | 
 | 2096 | 	data = readw(hw->io + addr); | 
 | 2097 | 	return (data & bits) == bits; | 
 | 2098 | } | 
 | 2099 |  | 
 | 2100 | /** | 
 | 2101 |  * sw_cfg - set switch register bits | 
 | 2102 |  * @hw: 	The hardware instance. | 
 | 2103 |  * @addr:	The address of the switch register. | 
 | 2104 |  * @bits:	The data bits to set. | 
 | 2105 |  * @set:	The flag indicating whether the bits are to be set or not. | 
 | 2106 |  * | 
 | 2107 |  * This function sets or resets the specified bits of the switch register. | 
 | 2108 |  */ | 
 | 2109 | static void sw_cfg(struct ksz_hw *hw, u32 addr, u16 bits, int set) | 
 | 2110 | { | 
 | 2111 | 	u16 data; | 
 | 2112 |  | 
 | 2113 | 	data = readw(hw->io + addr); | 
 | 2114 | 	if (set) | 
 | 2115 | 		data |= bits; | 
 | 2116 | 	else | 
 | 2117 | 		data &= ~bits; | 
 | 2118 | 	writew(data, hw->io + addr); | 
 | 2119 | } | 
 | 2120 |  | 
 | 2121 | /* Bandwidth */ | 
 | 2122 |  | 
 | 2123 | static inline void port_cfg_broad_storm(struct ksz_hw *hw, int p, int set) | 
 | 2124 | { | 
 | 2125 | 	port_cfg(hw, p, | 
 | 2126 | 		KS8842_PORT_CTRL_1_OFFSET, PORT_BROADCAST_STORM, set); | 
 | 2127 | } | 
 | 2128 |  | 
 | 2129 | static inline int port_chk_broad_storm(struct ksz_hw *hw, int p) | 
 | 2130 | { | 
 | 2131 | 	return port_chk(hw, p, | 
 | 2132 | 		KS8842_PORT_CTRL_1_OFFSET, PORT_BROADCAST_STORM); | 
 | 2133 | } | 
 | 2134 |  | 
 | 2135 | /* Driver set switch broadcast storm protection at 10% rate. */ | 
 | 2136 | #define BROADCAST_STORM_PROTECTION_RATE	10 | 
 | 2137 |  | 
 | 2138 | /* 148,800 frames * 67 ms / 100 */ | 
 | 2139 | #define BROADCAST_STORM_VALUE		9969 | 
 | 2140 |  | 
 | 2141 | /** | 
 | 2142 |  * sw_cfg_broad_storm - configure broadcast storm threshold | 
 | 2143 |  * @hw: 	The hardware instance. | 
 | 2144 |  * @percent:	Broadcast storm threshold in percent of transmit rate. | 
 | 2145 |  * | 
 | 2146 |  * This routine configures the broadcast storm threshold of the switch. | 
 | 2147 |  */ | 
 | 2148 | static void sw_cfg_broad_storm(struct ksz_hw *hw, u8 percent) | 
 | 2149 | { | 
 | 2150 | 	u16 data; | 
 | 2151 | 	u32 value = ((u32) BROADCAST_STORM_VALUE * (u32) percent / 100); | 
 | 2152 |  | 
 | 2153 | 	if (value > BROADCAST_STORM_RATE) | 
 | 2154 | 		value = BROADCAST_STORM_RATE; | 
 | 2155 |  | 
 | 2156 | 	data = readw(hw->io + KS8842_SWITCH_CTRL_3_OFFSET); | 
 | 2157 | 	data &= ~(BROADCAST_STORM_RATE_LO | BROADCAST_STORM_RATE_HI); | 
 | 2158 | 	data |= ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8); | 
 | 2159 | 	writew(data, hw->io + KS8842_SWITCH_CTRL_3_OFFSET); | 
 | 2160 | } | 
 | 2161 |  | 
 | 2162 | /** | 
 | 2163 |  * sw_get_board_storm - get broadcast storm threshold | 
 | 2164 |  * @hw: 	The hardware instance. | 
 | 2165 |  * @percent:	Buffer to store the broadcast storm threshold percentage. | 
 | 2166 |  * | 
 | 2167 |  * This routine retrieves the broadcast storm threshold of the switch. | 
 | 2168 |  */ | 
 | 2169 | static void sw_get_broad_storm(struct ksz_hw *hw, u8 *percent) | 
 | 2170 | { | 
 | 2171 | 	int num; | 
 | 2172 | 	u16 data; | 
 | 2173 |  | 
 | 2174 | 	data = readw(hw->io + KS8842_SWITCH_CTRL_3_OFFSET); | 
 | 2175 | 	num = (data & BROADCAST_STORM_RATE_HI); | 
 | 2176 | 	num <<= 8; | 
 | 2177 | 	num |= (data & BROADCAST_STORM_RATE_LO) >> 8; | 
 | 2178 | 	num = (num * 100 + BROADCAST_STORM_VALUE / 2) / BROADCAST_STORM_VALUE; | 
 | 2179 | 	*percent = (u8) num; | 
 | 2180 | } | 
 | 2181 |  | 
 | 2182 | /** | 
 | 2183 |  * sw_dis_broad_storm - disable broadstorm | 
 | 2184 |  * @hw: 	The hardware instance. | 
 | 2185 |  * @port:	The port index. | 
 | 2186 |  * | 
 | 2187 |  * This routine disables the broadcast storm limit function of the switch. | 
 | 2188 |  */ | 
 | 2189 | static void sw_dis_broad_storm(struct ksz_hw *hw, int port) | 
 | 2190 | { | 
 | 2191 | 	port_cfg_broad_storm(hw, port, 0); | 
 | 2192 | } | 
 | 2193 |  | 
 | 2194 | /** | 
 | 2195 |  * sw_ena_broad_storm - enable broadcast storm | 
 | 2196 |  * @hw: 	The hardware instance. | 
 | 2197 |  * @port:	The port index. | 
 | 2198 |  * | 
 | 2199 |  * This routine enables the broadcast storm limit function of the switch. | 
 | 2200 |  */ | 
 | 2201 | static void sw_ena_broad_storm(struct ksz_hw *hw, int port) | 
 | 2202 | { | 
 | 2203 | 	sw_cfg_broad_storm(hw, hw->ksz_switch->broad_per); | 
 | 2204 | 	port_cfg_broad_storm(hw, port, 1); | 
 | 2205 | } | 
 | 2206 |  | 
 | 2207 | /** | 
 | 2208 |  * sw_init_broad_storm - initialize broadcast storm | 
 | 2209 |  * @hw: 	The hardware instance. | 
 | 2210 |  * | 
 | 2211 |  * This routine initializes the broadcast storm limit function of the switch. | 
 | 2212 |  */ | 
 | 2213 | static void sw_init_broad_storm(struct ksz_hw *hw) | 
 | 2214 | { | 
 | 2215 | 	int port; | 
 | 2216 |  | 
 | 2217 | 	hw->ksz_switch->broad_per = 1; | 
 | 2218 | 	sw_cfg_broad_storm(hw, hw->ksz_switch->broad_per); | 
 | 2219 | 	for (port = 0; port < TOTAL_PORT_NUM; port++) | 
 | 2220 | 		sw_dis_broad_storm(hw, port); | 
 | 2221 | 	sw_cfg(hw, KS8842_SWITCH_CTRL_2_OFFSET, MULTICAST_STORM_DISABLE, 1); | 
 | 2222 | } | 
 | 2223 |  | 
 | 2224 | /** | 
 | 2225 |  * hw_cfg_broad_storm - configure broadcast storm | 
 | 2226 |  * @hw: 	The hardware instance. | 
 | 2227 |  * @percent:	Broadcast storm threshold in percent of transmit rate. | 
 | 2228 |  * | 
 | 2229 |  * This routine configures the broadcast storm threshold of the switch. | 
 | 2230 |  * It is called by user functions.  The hardware should be acquired first. | 
 | 2231 |  */ | 
 | 2232 | static void hw_cfg_broad_storm(struct ksz_hw *hw, u8 percent) | 
 | 2233 | { | 
 | 2234 | 	if (percent > 100) | 
 | 2235 | 		percent = 100; | 
 | 2236 |  | 
 | 2237 | 	sw_cfg_broad_storm(hw, percent); | 
 | 2238 | 	sw_get_broad_storm(hw, &percent); | 
 | 2239 | 	hw->ksz_switch->broad_per = percent; | 
 | 2240 | } | 
 | 2241 |  | 
 | 2242 | /** | 
 | 2243 |  * sw_dis_prio_rate - disable switch priority rate | 
 | 2244 |  * @hw: 	The hardware instance. | 
 | 2245 |  * @port:	The port index. | 
 | 2246 |  * | 
 | 2247 |  * This routine disables the priority rate function of the switch. | 
 | 2248 |  */ | 
 | 2249 | static void sw_dis_prio_rate(struct ksz_hw *hw, int port) | 
 | 2250 | { | 
 | 2251 | 	u32 addr; | 
 | 2252 |  | 
 | 2253 | 	PORT_CTRL_ADDR(port, addr); | 
 | 2254 | 	addr += KS8842_PORT_IN_RATE_OFFSET; | 
 | 2255 | 	writel(0, hw->io + addr); | 
 | 2256 | } | 
 | 2257 |  | 
 | 2258 | /** | 
 | 2259 |  * sw_init_prio_rate - initialize switch prioirty rate | 
 | 2260 |  * @hw: 	The hardware instance. | 
 | 2261 |  * | 
 | 2262 |  * This routine initializes the priority rate function of the switch. | 
 | 2263 |  */ | 
 | 2264 | static void sw_init_prio_rate(struct ksz_hw *hw) | 
 | 2265 | { | 
 | 2266 | 	int port; | 
 | 2267 | 	int prio; | 
 | 2268 | 	struct ksz_switch *sw = hw->ksz_switch; | 
 | 2269 |  | 
 | 2270 | 	for (port = 0; port < TOTAL_PORT_NUM; port++) { | 
 | 2271 | 		for (prio = 0; prio < PRIO_QUEUES; prio++) { | 
 | 2272 | 			sw->port_cfg[port].rx_rate[prio] = | 
 | 2273 | 			sw->port_cfg[port].tx_rate[prio] = 0; | 
 | 2274 | 		} | 
 | 2275 | 		sw_dis_prio_rate(hw, port); | 
 | 2276 | 	} | 
 | 2277 | } | 
 | 2278 |  | 
 | 2279 | /* Communication */ | 
 | 2280 |  | 
 | 2281 | static inline void port_cfg_back_pressure(struct ksz_hw *hw, int p, int set) | 
 | 2282 | { | 
 | 2283 | 	port_cfg(hw, p, | 
 | 2284 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_BACK_PRESSURE, set); | 
 | 2285 | } | 
 | 2286 |  | 
 | 2287 | static inline void port_cfg_force_flow_ctrl(struct ksz_hw *hw, int p, int set) | 
 | 2288 | { | 
 | 2289 | 	port_cfg(hw, p, | 
 | 2290 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_FORCE_FLOW_CTRL, set); | 
 | 2291 | } | 
 | 2292 |  | 
 | 2293 | static inline int port_chk_back_pressure(struct ksz_hw *hw, int p) | 
 | 2294 | { | 
 | 2295 | 	return port_chk(hw, p, | 
 | 2296 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_BACK_PRESSURE); | 
 | 2297 | } | 
 | 2298 |  | 
 | 2299 | static inline int port_chk_force_flow_ctrl(struct ksz_hw *hw, int p) | 
 | 2300 | { | 
 | 2301 | 	return port_chk(hw, p, | 
 | 2302 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_FORCE_FLOW_CTRL); | 
 | 2303 | } | 
 | 2304 |  | 
 | 2305 | /* Spanning Tree */ | 
 | 2306 |  | 
 | 2307 | static inline void port_cfg_dis_learn(struct ksz_hw *hw, int p, int set) | 
 | 2308 | { | 
 | 2309 | 	port_cfg(hw, p, | 
 | 2310 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_LEARN_DISABLE, set); | 
 | 2311 | } | 
 | 2312 |  | 
 | 2313 | static inline void port_cfg_rx(struct ksz_hw *hw, int p, int set) | 
 | 2314 | { | 
 | 2315 | 	port_cfg(hw, p, | 
 | 2316 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_RX_ENABLE, set); | 
 | 2317 | } | 
 | 2318 |  | 
 | 2319 | static inline void port_cfg_tx(struct ksz_hw *hw, int p, int set) | 
 | 2320 | { | 
 | 2321 | 	port_cfg(hw, p, | 
 | 2322 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_TX_ENABLE, set); | 
 | 2323 | } | 
 | 2324 |  | 
 | 2325 | static inline void sw_cfg_fast_aging(struct ksz_hw *hw, int set) | 
 | 2326 | { | 
 | 2327 | 	sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET, SWITCH_FAST_AGING, set); | 
 | 2328 | } | 
 | 2329 |  | 
 | 2330 | static inline void sw_flush_dyn_mac_table(struct ksz_hw *hw) | 
 | 2331 | { | 
 | 2332 | 	if (!(hw->overrides & FAST_AGING)) { | 
 | 2333 | 		sw_cfg_fast_aging(hw, 1); | 
 | 2334 | 		mdelay(1); | 
 | 2335 | 		sw_cfg_fast_aging(hw, 0); | 
 | 2336 | 	} | 
 | 2337 | } | 
 | 2338 |  | 
 | 2339 | /* VLAN */ | 
 | 2340 |  | 
 | 2341 | static inline void port_cfg_ins_tag(struct ksz_hw *hw, int p, int insert) | 
 | 2342 | { | 
 | 2343 | 	port_cfg(hw, p, | 
 | 2344 | 		KS8842_PORT_CTRL_1_OFFSET, PORT_INSERT_TAG, insert); | 
 | 2345 | } | 
 | 2346 |  | 
 | 2347 | static inline void port_cfg_rmv_tag(struct ksz_hw *hw, int p, int remove) | 
 | 2348 | { | 
 | 2349 | 	port_cfg(hw, p, | 
 | 2350 | 		KS8842_PORT_CTRL_1_OFFSET, PORT_REMOVE_TAG, remove); | 
 | 2351 | } | 
 | 2352 |  | 
 | 2353 | static inline int port_chk_ins_tag(struct ksz_hw *hw, int p) | 
 | 2354 | { | 
 | 2355 | 	return port_chk(hw, p, | 
 | 2356 | 		KS8842_PORT_CTRL_1_OFFSET, PORT_INSERT_TAG); | 
 | 2357 | } | 
 | 2358 |  | 
 | 2359 | static inline int port_chk_rmv_tag(struct ksz_hw *hw, int p) | 
 | 2360 | { | 
 | 2361 | 	return port_chk(hw, p, | 
 | 2362 | 		KS8842_PORT_CTRL_1_OFFSET, PORT_REMOVE_TAG); | 
 | 2363 | } | 
 | 2364 |  | 
 | 2365 | static inline void port_cfg_dis_non_vid(struct ksz_hw *hw, int p, int set) | 
 | 2366 | { | 
 | 2367 | 	port_cfg(hw, p, | 
 | 2368 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_DISCARD_NON_VID, set); | 
 | 2369 | } | 
 | 2370 |  | 
 | 2371 | static inline void port_cfg_in_filter(struct ksz_hw *hw, int p, int set) | 
 | 2372 | { | 
 | 2373 | 	port_cfg(hw, p, | 
 | 2374 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_INGRESS_VLAN_FILTER, set); | 
 | 2375 | } | 
 | 2376 |  | 
 | 2377 | static inline int port_chk_dis_non_vid(struct ksz_hw *hw, int p) | 
 | 2378 | { | 
 | 2379 | 	return port_chk(hw, p, | 
 | 2380 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_DISCARD_NON_VID); | 
 | 2381 | } | 
 | 2382 |  | 
 | 2383 | static inline int port_chk_in_filter(struct ksz_hw *hw, int p) | 
 | 2384 | { | 
 | 2385 | 	return port_chk(hw, p, | 
 | 2386 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_INGRESS_VLAN_FILTER); | 
 | 2387 | } | 
 | 2388 |  | 
 | 2389 | /* Mirroring */ | 
 | 2390 |  | 
 | 2391 | static inline void port_cfg_mirror_sniffer(struct ksz_hw *hw, int p, int set) | 
 | 2392 | { | 
 | 2393 | 	port_cfg(hw, p, | 
 | 2394 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_MIRROR_SNIFFER, set); | 
 | 2395 | } | 
 | 2396 |  | 
 | 2397 | static inline void port_cfg_mirror_rx(struct ksz_hw *hw, int p, int set) | 
 | 2398 | { | 
 | 2399 | 	port_cfg(hw, p, | 
 | 2400 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_MIRROR_RX, set); | 
 | 2401 | } | 
 | 2402 |  | 
 | 2403 | static inline void port_cfg_mirror_tx(struct ksz_hw *hw, int p, int set) | 
 | 2404 | { | 
 | 2405 | 	port_cfg(hw, p, | 
 | 2406 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_MIRROR_TX, set); | 
 | 2407 | } | 
 | 2408 |  | 
 | 2409 | static inline void sw_cfg_mirror_rx_tx(struct ksz_hw *hw, int set) | 
 | 2410 | { | 
 | 2411 | 	sw_cfg(hw, KS8842_SWITCH_CTRL_2_OFFSET, SWITCH_MIRROR_RX_TX, set); | 
 | 2412 | } | 
 | 2413 |  | 
 | 2414 | static void sw_init_mirror(struct ksz_hw *hw) | 
 | 2415 | { | 
 | 2416 | 	int port; | 
 | 2417 |  | 
 | 2418 | 	for (port = 0; port < TOTAL_PORT_NUM; port++) { | 
 | 2419 | 		port_cfg_mirror_sniffer(hw, port, 0); | 
 | 2420 | 		port_cfg_mirror_rx(hw, port, 0); | 
 | 2421 | 		port_cfg_mirror_tx(hw, port, 0); | 
 | 2422 | 	} | 
 | 2423 | 	sw_cfg_mirror_rx_tx(hw, 0); | 
 | 2424 | } | 
 | 2425 |  | 
 | 2426 | static inline void sw_cfg_unk_def_deliver(struct ksz_hw *hw, int set) | 
 | 2427 | { | 
 | 2428 | 	sw_cfg(hw, KS8842_SWITCH_CTRL_7_OFFSET, | 
 | 2429 | 		SWITCH_UNK_DEF_PORT_ENABLE, set); | 
 | 2430 | } | 
 | 2431 |  | 
 | 2432 | static inline int sw_cfg_chk_unk_def_deliver(struct ksz_hw *hw) | 
 | 2433 | { | 
 | 2434 | 	return sw_chk(hw, KS8842_SWITCH_CTRL_7_OFFSET, | 
 | 2435 | 		SWITCH_UNK_DEF_PORT_ENABLE); | 
 | 2436 | } | 
 | 2437 |  | 
 | 2438 | static inline void sw_cfg_unk_def_port(struct ksz_hw *hw, int port, int set) | 
 | 2439 | { | 
 | 2440 | 	port_cfg_shift(hw, port, KS8842_SWITCH_CTRL_7_OFFSET, 0, set); | 
 | 2441 | } | 
 | 2442 |  | 
 | 2443 | static inline int sw_chk_unk_def_port(struct ksz_hw *hw, int port) | 
 | 2444 | { | 
 | 2445 | 	return port_chk_shift(hw, port, KS8842_SWITCH_CTRL_7_OFFSET, 0); | 
 | 2446 | } | 
 | 2447 |  | 
 | 2448 | /* Priority */ | 
 | 2449 |  | 
 | 2450 | static inline void port_cfg_diffserv(struct ksz_hw *hw, int p, int set) | 
 | 2451 | { | 
 | 2452 | 	port_cfg(hw, p, | 
 | 2453 | 		KS8842_PORT_CTRL_1_OFFSET, PORT_DIFFSERV_ENABLE, set); | 
 | 2454 | } | 
 | 2455 |  | 
 | 2456 | static inline void port_cfg_802_1p(struct ksz_hw *hw, int p, int set) | 
 | 2457 | { | 
 | 2458 | 	port_cfg(hw, p, | 
 | 2459 | 		KS8842_PORT_CTRL_1_OFFSET, PORT_802_1P_ENABLE, set); | 
 | 2460 | } | 
 | 2461 |  | 
 | 2462 | static inline void port_cfg_replace_vid(struct ksz_hw *hw, int p, int set) | 
 | 2463 | { | 
 | 2464 | 	port_cfg(hw, p, | 
 | 2465 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_USER_PRIORITY_CEILING, set); | 
 | 2466 | } | 
 | 2467 |  | 
 | 2468 | static inline void port_cfg_prio(struct ksz_hw *hw, int p, int set) | 
 | 2469 | { | 
 | 2470 | 	port_cfg(hw, p, | 
 | 2471 | 		KS8842_PORT_CTRL_1_OFFSET, PORT_PRIO_QUEUE_ENABLE, set); | 
 | 2472 | } | 
 | 2473 |  | 
 | 2474 | static inline int port_chk_diffserv(struct ksz_hw *hw, int p) | 
 | 2475 | { | 
 | 2476 | 	return port_chk(hw, p, | 
 | 2477 | 		KS8842_PORT_CTRL_1_OFFSET, PORT_DIFFSERV_ENABLE); | 
 | 2478 | } | 
 | 2479 |  | 
 | 2480 | static inline int port_chk_802_1p(struct ksz_hw *hw, int p) | 
 | 2481 | { | 
 | 2482 | 	return port_chk(hw, p, | 
 | 2483 | 		KS8842_PORT_CTRL_1_OFFSET, PORT_802_1P_ENABLE); | 
 | 2484 | } | 
 | 2485 |  | 
 | 2486 | static inline int port_chk_replace_vid(struct ksz_hw *hw, int p) | 
 | 2487 | { | 
 | 2488 | 	return port_chk(hw, p, | 
 | 2489 | 		KS8842_PORT_CTRL_2_OFFSET, PORT_USER_PRIORITY_CEILING); | 
 | 2490 | } | 
 | 2491 |  | 
 | 2492 | static inline int port_chk_prio(struct ksz_hw *hw, int p) | 
 | 2493 | { | 
 | 2494 | 	return port_chk(hw, p, | 
 | 2495 | 		KS8842_PORT_CTRL_1_OFFSET, PORT_PRIO_QUEUE_ENABLE); | 
 | 2496 | } | 
 | 2497 |  | 
 | 2498 | /** | 
 | 2499 |  * sw_dis_diffserv - disable switch DiffServ priority | 
 | 2500 |  * @hw: 	The hardware instance. | 
 | 2501 |  * @port:	The port index. | 
 | 2502 |  * | 
 | 2503 |  * This routine disables the DiffServ priority function of the switch. | 
 | 2504 |  */ | 
 | 2505 | static void sw_dis_diffserv(struct ksz_hw *hw, int port) | 
 | 2506 | { | 
 | 2507 | 	port_cfg_diffserv(hw, port, 0); | 
 | 2508 | } | 
 | 2509 |  | 
 | 2510 | /** | 
 | 2511 |  * sw_dis_802_1p - disable switch 802.1p priority | 
 | 2512 |  * @hw: 	The hardware instance. | 
 | 2513 |  * @port:	The port index. | 
 | 2514 |  * | 
 | 2515 |  * This routine disables the 802.1p priority function of the switch. | 
 | 2516 |  */ | 
 | 2517 | static void sw_dis_802_1p(struct ksz_hw *hw, int port) | 
 | 2518 | { | 
 | 2519 | 	port_cfg_802_1p(hw, port, 0); | 
 | 2520 | } | 
 | 2521 |  | 
 | 2522 | /** | 
 | 2523 |  * sw_cfg_replace_null_vid - | 
 | 2524 |  * @hw: 	The hardware instance. | 
 | 2525 |  * @set:	The flag to disable or enable. | 
 | 2526 |  * | 
 | 2527 |  */ | 
 | 2528 | static void sw_cfg_replace_null_vid(struct ksz_hw *hw, int set) | 
 | 2529 | { | 
 | 2530 | 	sw_cfg(hw, KS8842_SWITCH_CTRL_3_OFFSET, SWITCH_REPLACE_NULL_VID, set); | 
 | 2531 | } | 
 | 2532 |  | 
 | 2533 | /** | 
 | 2534 |  * sw_cfg_replace_vid - enable switch 802.10 priority re-mapping | 
 | 2535 |  * @hw: 	The hardware instance. | 
 | 2536 |  * @port:	The port index. | 
 | 2537 |  * @set:	The flag to disable or enable. | 
 | 2538 |  * | 
 | 2539 |  * This routine enables the 802.1p priority re-mapping function of the switch. | 
 | 2540 |  * That allows 802.1p priority field to be replaced with the port's default | 
 | 2541 |  * tag's priority value if the ingress packet's 802.1p priority has a higher | 
 | 2542 |  * priority than port's default tag's priority. | 
 | 2543 |  */ | 
 | 2544 | static void sw_cfg_replace_vid(struct ksz_hw *hw, int port, int set) | 
 | 2545 | { | 
 | 2546 | 	port_cfg_replace_vid(hw, port, set); | 
 | 2547 | } | 
 | 2548 |  | 
 | 2549 | /** | 
 | 2550 |  * sw_cfg_port_based - configure switch port based priority | 
 | 2551 |  * @hw: 	The hardware instance. | 
 | 2552 |  * @port:	The port index. | 
 | 2553 |  * @prio:	The priority to set. | 
 | 2554 |  * | 
 | 2555 |  * This routine configures the port based priority of the switch. | 
 | 2556 |  */ | 
 | 2557 | static void sw_cfg_port_based(struct ksz_hw *hw, int port, u8 prio) | 
 | 2558 | { | 
 | 2559 | 	u16 data; | 
 | 2560 |  | 
 | 2561 | 	if (prio > PORT_BASED_PRIORITY_BASE) | 
 | 2562 | 		prio = PORT_BASED_PRIORITY_BASE; | 
 | 2563 |  | 
 | 2564 | 	hw->ksz_switch->port_cfg[port].port_prio = prio; | 
 | 2565 |  | 
 | 2566 | 	port_r16(hw, port, KS8842_PORT_CTRL_1_OFFSET, &data); | 
 | 2567 | 	data &= ~PORT_BASED_PRIORITY_MASK; | 
 | 2568 | 	data |= prio << PORT_BASED_PRIORITY_SHIFT; | 
 | 2569 | 	port_w16(hw, port, KS8842_PORT_CTRL_1_OFFSET, data); | 
 | 2570 | } | 
 | 2571 |  | 
 | 2572 | /** | 
 | 2573 |  * sw_dis_multi_queue - disable transmit multiple queues | 
 | 2574 |  * @hw: 	The hardware instance. | 
 | 2575 |  * @port:	The port index. | 
 | 2576 |  * | 
 | 2577 |  * This routine disables the transmit multiple queues selection of the switch | 
 | 2578 |  * port.  Only single transmit queue on the port. | 
 | 2579 |  */ | 
 | 2580 | static void sw_dis_multi_queue(struct ksz_hw *hw, int port) | 
 | 2581 | { | 
 | 2582 | 	port_cfg_prio(hw, port, 0); | 
 | 2583 | } | 
 | 2584 |  | 
 | 2585 | /** | 
 | 2586 |  * sw_init_prio - initialize switch priority | 
 | 2587 |  * @hw: 	The hardware instance. | 
 | 2588 |  * | 
 | 2589 |  * This routine initializes the switch QoS priority functions. | 
 | 2590 |  */ | 
 | 2591 | static void sw_init_prio(struct ksz_hw *hw) | 
 | 2592 | { | 
 | 2593 | 	int port; | 
 | 2594 | 	int tos; | 
 | 2595 | 	struct ksz_switch *sw = hw->ksz_switch; | 
 | 2596 |  | 
 | 2597 | 	/* | 
 | 2598 | 	 * Init all the 802.1p tag priority value to be assigned to different | 
 | 2599 | 	 * priority queue. | 
 | 2600 | 	 */ | 
 | 2601 | 	sw->p_802_1p[0] = 0; | 
 | 2602 | 	sw->p_802_1p[1] = 0; | 
 | 2603 | 	sw->p_802_1p[2] = 1; | 
 | 2604 | 	sw->p_802_1p[3] = 1; | 
 | 2605 | 	sw->p_802_1p[4] = 2; | 
 | 2606 | 	sw->p_802_1p[5] = 2; | 
 | 2607 | 	sw->p_802_1p[6] = 3; | 
 | 2608 | 	sw->p_802_1p[7] = 3; | 
 | 2609 |  | 
 | 2610 | 	/* | 
 | 2611 | 	 * Init all the DiffServ priority value to be assigned to priority | 
 | 2612 | 	 * queue 0. | 
 | 2613 | 	 */ | 
 | 2614 | 	for (tos = 0; tos < DIFFSERV_ENTRIES; tos++) | 
 | 2615 | 		sw->diffserv[tos] = 0; | 
 | 2616 |  | 
 | 2617 | 	/* All QoS functions disabled. */ | 
 | 2618 | 	for (port = 0; port < TOTAL_PORT_NUM; port++) { | 
 | 2619 | 		sw_dis_multi_queue(hw, port); | 
 | 2620 | 		sw_dis_diffserv(hw, port); | 
 | 2621 | 		sw_dis_802_1p(hw, port); | 
 | 2622 | 		sw_cfg_replace_vid(hw, port, 0); | 
 | 2623 |  | 
 | 2624 | 		sw->port_cfg[port].port_prio = 0; | 
 | 2625 | 		sw_cfg_port_based(hw, port, sw->port_cfg[port].port_prio); | 
 | 2626 | 	} | 
 | 2627 | 	sw_cfg_replace_null_vid(hw, 0); | 
 | 2628 | } | 
 | 2629 |  | 
 | 2630 | /** | 
 | 2631 |  * port_get_def_vid - get port default VID. | 
 | 2632 |  * @hw: 	The hardware instance. | 
 | 2633 |  * @port:	The port index. | 
 | 2634 |  * @vid:	Buffer to store the VID. | 
 | 2635 |  * | 
 | 2636 |  * This routine retrieves the default VID of the port. | 
 | 2637 |  */ | 
 | 2638 | static void port_get_def_vid(struct ksz_hw *hw, int port, u16 *vid) | 
 | 2639 | { | 
 | 2640 | 	u32 addr; | 
 | 2641 |  | 
 | 2642 | 	PORT_CTRL_ADDR(port, addr); | 
 | 2643 | 	addr += KS8842_PORT_CTRL_VID_OFFSET; | 
 | 2644 | 	*vid = readw(hw->io + addr); | 
 | 2645 | } | 
 | 2646 |  | 
 | 2647 | /** | 
 | 2648 |  * sw_init_vlan - initialize switch VLAN | 
 | 2649 |  * @hw: 	The hardware instance. | 
 | 2650 |  * | 
 | 2651 |  * This routine initializes the VLAN function of the switch. | 
 | 2652 |  */ | 
 | 2653 | static void sw_init_vlan(struct ksz_hw *hw) | 
 | 2654 | { | 
 | 2655 | 	int port; | 
 | 2656 | 	int entry; | 
 | 2657 | 	struct ksz_switch *sw = hw->ksz_switch; | 
 | 2658 |  | 
 | 2659 | 	/* Read 16 VLAN entries from device's VLAN table. */ | 
 | 2660 | 	for (entry = 0; entry < VLAN_TABLE_ENTRIES; entry++) { | 
 | 2661 | 		sw_r_vlan_table(hw, entry, | 
 | 2662 | 			&sw->vlan_table[entry].vid, | 
 | 2663 | 			&sw->vlan_table[entry].fid, | 
 | 2664 | 			&sw->vlan_table[entry].member); | 
 | 2665 | 	} | 
 | 2666 |  | 
 | 2667 | 	for (port = 0; port < TOTAL_PORT_NUM; port++) { | 
 | 2668 | 		port_get_def_vid(hw, port, &sw->port_cfg[port].vid); | 
 | 2669 | 		sw->port_cfg[port].member = PORT_MASK; | 
 | 2670 | 	} | 
 | 2671 | } | 
 | 2672 |  | 
 | 2673 | /** | 
 | 2674 |  * sw_cfg_port_base_vlan - configure port-based VLAN membership | 
 | 2675 |  * @hw: 	The hardware instance. | 
 | 2676 |  * @port:	The port index. | 
 | 2677 |  * @member:	The port-based VLAN membership. | 
 | 2678 |  * | 
 | 2679 |  * This routine configures the port-based VLAN membership of the port. | 
 | 2680 |  */ | 
 | 2681 | static void sw_cfg_port_base_vlan(struct ksz_hw *hw, int port, u8 member) | 
 | 2682 | { | 
 | 2683 | 	u32 addr; | 
 | 2684 | 	u8 data; | 
 | 2685 |  | 
 | 2686 | 	PORT_CTRL_ADDR(port, addr); | 
 | 2687 | 	addr += KS8842_PORT_CTRL_2_OFFSET; | 
 | 2688 |  | 
 | 2689 | 	data = readb(hw->io + addr); | 
 | 2690 | 	data &= ~PORT_VLAN_MEMBERSHIP; | 
 | 2691 | 	data |= (member & PORT_MASK); | 
 | 2692 | 	writeb(data, hw->io + addr); | 
 | 2693 |  | 
 | 2694 | 	hw->ksz_switch->port_cfg[port].member = member; | 
 | 2695 | } | 
 | 2696 |  | 
 | 2697 | /** | 
 | 2698 |  * sw_get_addr - get the switch MAC address. | 
 | 2699 |  * @hw: 	The hardware instance. | 
 | 2700 |  * @mac_addr:	Buffer to store the MAC address. | 
 | 2701 |  * | 
 | 2702 |  * This function retrieves the MAC address of the switch. | 
 | 2703 |  */ | 
 | 2704 | static inline void sw_get_addr(struct ksz_hw *hw, u8 *mac_addr) | 
 | 2705 | { | 
 | 2706 | 	int i; | 
 | 2707 |  | 
 | 2708 | 	for (i = 0; i < 6; i += 2) { | 
 | 2709 | 		mac_addr[i] = readb(hw->io + KS8842_MAC_ADDR_0_OFFSET + i); | 
 | 2710 | 		mac_addr[1 + i] = readb(hw->io + KS8842_MAC_ADDR_1_OFFSET + i); | 
 | 2711 | 	} | 
 | 2712 | } | 
 | 2713 |  | 
 | 2714 | /** | 
 | 2715 |  * sw_set_addr - configure switch MAC address | 
 | 2716 |  * @hw: 	The hardware instance. | 
 | 2717 |  * @mac_addr:	The MAC address. | 
 | 2718 |  * | 
 | 2719 |  * This function configures the MAC address of the switch. | 
 | 2720 |  */ | 
 | 2721 | static void sw_set_addr(struct ksz_hw *hw, u8 *mac_addr) | 
 | 2722 | { | 
 | 2723 | 	int i; | 
 | 2724 |  | 
 | 2725 | 	for (i = 0; i < 6; i += 2) { | 
 | 2726 | 		writeb(mac_addr[i], hw->io + KS8842_MAC_ADDR_0_OFFSET + i); | 
 | 2727 | 		writeb(mac_addr[1 + i], hw->io + KS8842_MAC_ADDR_1_OFFSET + i); | 
 | 2728 | 	} | 
 | 2729 | } | 
 | 2730 |  | 
 | 2731 | /** | 
 | 2732 |  * sw_set_global_ctrl - set switch global control | 
 | 2733 |  * @hw: 	The hardware instance. | 
 | 2734 |  * | 
 | 2735 |  * This routine sets the global control of the switch function. | 
 | 2736 |  */ | 
 | 2737 | static void sw_set_global_ctrl(struct ksz_hw *hw) | 
 | 2738 | { | 
 | 2739 | 	u16 data; | 
 | 2740 |  | 
 | 2741 | 	/* Enable switch MII flow control. */ | 
 | 2742 | 	data = readw(hw->io + KS8842_SWITCH_CTRL_3_OFFSET); | 
 | 2743 | 	data |= SWITCH_FLOW_CTRL; | 
 | 2744 | 	writew(data, hw->io + KS8842_SWITCH_CTRL_3_OFFSET); | 
 | 2745 |  | 
 | 2746 | 	data = readw(hw->io + KS8842_SWITCH_CTRL_1_OFFSET); | 
 | 2747 |  | 
 | 2748 | 	/* Enable aggressive back off algorithm in half duplex mode. */ | 
 | 2749 | 	data |= SWITCH_AGGR_BACKOFF; | 
 | 2750 |  | 
 | 2751 | 	/* Enable automatic fast aging when link changed detected. */ | 
 | 2752 | 	data |= SWITCH_AGING_ENABLE; | 
 | 2753 | 	data |= SWITCH_LINK_AUTO_AGING; | 
 | 2754 |  | 
 | 2755 | 	if (hw->overrides & FAST_AGING) | 
 | 2756 | 		data |= SWITCH_FAST_AGING; | 
 | 2757 | 	else | 
 | 2758 | 		data &= ~SWITCH_FAST_AGING; | 
 | 2759 | 	writew(data, hw->io + KS8842_SWITCH_CTRL_1_OFFSET); | 
 | 2760 |  | 
 | 2761 | 	data = readw(hw->io + KS8842_SWITCH_CTRL_2_OFFSET); | 
 | 2762 |  | 
 | 2763 | 	/* Enable no excessive collision drop. */ | 
 | 2764 | 	data |= NO_EXC_COLLISION_DROP; | 
 | 2765 | 	writew(data, hw->io + KS8842_SWITCH_CTRL_2_OFFSET); | 
 | 2766 | } | 
 | 2767 |  | 
 | 2768 | enum { | 
 | 2769 | 	STP_STATE_DISABLED = 0, | 
 | 2770 | 	STP_STATE_LISTENING, | 
 | 2771 | 	STP_STATE_LEARNING, | 
 | 2772 | 	STP_STATE_FORWARDING, | 
 | 2773 | 	STP_STATE_BLOCKED, | 
 | 2774 | 	STP_STATE_SIMPLE | 
 | 2775 | }; | 
 | 2776 |  | 
 | 2777 | /** | 
 | 2778 |  * port_set_stp_state - configure port spanning tree state | 
 | 2779 |  * @hw: 	The hardware instance. | 
 | 2780 |  * @port:	The port index. | 
 | 2781 |  * @state:	The spanning tree state. | 
 | 2782 |  * | 
 | 2783 |  * This routine configures the spanning tree state of the port. | 
 | 2784 |  */ | 
 | 2785 | static void port_set_stp_state(struct ksz_hw *hw, int port, int state) | 
 | 2786 | { | 
 | 2787 | 	u16 data; | 
 | 2788 |  | 
 | 2789 | 	port_r16(hw, port, KS8842_PORT_CTRL_2_OFFSET, &data); | 
 | 2790 | 	switch (state) { | 
 | 2791 | 	case STP_STATE_DISABLED: | 
 | 2792 | 		data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE); | 
 | 2793 | 		data |= PORT_LEARN_DISABLE; | 
 | 2794 | 		break; | 
 | 2795 | 	case STP_STATE_LISTENING: | 
 | 2796 | /* | 
 | 2797 |  * No need to turn on transmit because of port direct mode. | 
 | 2798 |  * Turning on receive is required if static MAC table is not setup. | 
 | 2799 |  */ | 
 | 2800 | 		data &= ~PORT_TX_ENABLE; | 
 | 2801 | 		data |= PORT_RX_ENABLE; | 
 | 2802 | 		data |= PORT_LEARN_DISABLE; | 
 | 2803 | 		break; | 
 | 2804 | 	case STP_STATE_LEARNING: | 
 | 2805 | 		data &= ~PORT_TX_ENABLE; | 
 | 2806 | 		data |= PORT_RX_ENABLE; | 
 | 2807 | 		data &= ~PORT_LEARN_DISABLE; | 
 | 2808 | 		break; | 
 | 2809 | 	case STP_STATE_FORWARDING: | 
 | 2810 | 		data |= (PORT_TX_ENABLE | PORT_RX_ENABLE); | 
 | 2811 | 		data &= ~PORT_LEARN_DISABLE; | 
 | 2812 | 		break; | 
 | 2813 | 	case STP_STATE_BLOCKED: | 
 | 2814 | /* | 
 | 2815 |  * Need to setup static MAC table with override to keep receiving BPDU | 
 | 2816 |  * messages.  See sw_init_stp routine. | 
 | 2817 |  */ | 
 | 2818 | 		data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE); | 
 | 2819 | 		data |= PORT_LEARN_DISABLE; | 
 | 2820 | 		break; | 
 | 2821 | 	case STP_STATE_SIMPLE: | 
 | 2822 | 		data |= (PORT_TX_ENABLE | PORT_RX_ENABLE); | 
 | 2823 | 		data |= PORT_LEARN_DISABLE; | 
 | 2824 | 		break; | 
 | 2825 | 	} | 
 | 2826 | 	port_w16(hw, port, KS8842_PORT_CTRL_2_OFFSET, data); | 
 | 2827 | 	hw->ksz_switch->port_cfg[port].stp_state = state; | 
 | 2828 | } | 
 | 2829 |  | 
 | 2830 | #define STP_ENTRY			0 | 
 | 2831 | #define BROADCAST_ENTRY			1 | 
 | 2832 | #define BRIDGE_ADDR_ENTRY		2 | 
 | 2833 | #define IPV6_ADDR_ENTRY			3 | 
 | 2834 |  | 
 | 2835 | /** | 
 | 2836 |  * sw_clr_sta_mac_table - clear static MAC table | 
 | 2837 |  * @hw: 	The hardware instance. | 
 | 2838 |  * | 
 | 2839 |  * This routine clears the static MAC table. | 
 | 2840 |  */ | 
 | 2841 | static void sw_clr_sta_mac_table(struct ksz_hw *hw) | 
 | 2842 | { | 
 | 2843 | 	struct ksz_mac_table *entry; | 
 | 2844 | 	int i; | 
 | 2845 |  | 
 | 2846 | 	for (i = 0; i < STATIC_MAC_TABLE_ENTRIES; i++) { | 
 | 2847 | 		entry = &hw->ksz_switch->mac_table[i]; | 
 | 2848 | 		sw_w_sta_mac_table(hw, i, | 
 | 2849 | 			entry->mac_addr, entry->ports, | 
 | 2850 | 			entry->override, 0, | 
 | 2851 | 			entry->use_fid, entry->fid); | 
 | 2852 | 	} | 
 | 2853 | } | 
 | 2854 |  | 
 | 2855 | /** | 
 | 2856 |  * sw_init_stp - initialize switch spanning tree support | 
 | 2857 |  * @hw: 	The hardware instance. | 
 | 2858 |  * | 
 | 2859 |  * This routine initializes the spanning tree support of the switch. | 
 | 2860 |  */ | 
 | 2861 | static void sw_init_stp(struct ksz_hw *hw) | 
 | 2862 | { | 
 | 2863 | 	struct ksz_mac_table *entry; | 
 | 2864 |  | 
 | 2865 | 	entry = &hw->ksz_switch->mac_table[STP_ENTRY]; | 
 | 2866 | 	entry->mac_addr[0] = 0x01; | 
 | 2867 | 	entry->mac_addr[1] = 0x80; | 
 | 2868 | 	entry->mac_addr[2] = 0xC2; | 
 | 2869 | 	entry->mac_addr[3] = 0x00; | 
 | 2870 | 	entry->mac_addr[4] = 0x00; | 
 | 2871 | 	entry->mac_addr[5] = 0x00; | 
 | 2872 | 	entry->ports = HOST_MASK; | 
 | 2873 | 	entry->override = 1; | 
 | 2874 | 	entry->valid = 1; | 
 | 2875 | 	sw_w_sta_mac_table(hw, STP_ENTRY, | 
 | 2876 | 		entry->mac_addr, entry->ports, | 
 | 2877 | 		entry->override, entry->valid, | 
 | 2878 | 		entry->use_fid, entry->fid); | 
 | 2879 | } | 
 | 2880 |  | 
 | 2881 | /** | 
 | 2882 |  * sw_block_addr - block certain packets from the host port | 
 | 2883 |  * @hw: 	The hardware instance. | 
 | 2884 |  * | 
 | 2885 |  * This routine blocks certain packets from reaching to the host port. | 
 | 2886 |  */ | 
 | 2887 | static void sw_block_addr(struct ksz_hw *hw) | 
 | 2888 | { | 
 | 2889 | 	struct ksz_mac_table *entry; | 
 | 2890 | 	int i; | 
 | 2891 |  | 
 | 2892 | 	for (i = BROADCAST_ENTRY; i <= IPV6_ADDR_ENTRY; i++) { | 
 | 2893 | 		entry = &hw->ksz_switch->mac_table[i]; | 
 | 2894 | 		entry->valid = 0; | 
 | 2895 | 		sw_w_sta_mac_table(hw, i, | 
 | 2896 | 			entry->mac_addr, entry->ports, | 
 | 2897 | 			entry->override, entry->valid, | 
 | 2898 | 			entry->use_fid, entry->fid); | 
 | 2899 | 	} | 
 | 2900 | } | 
 | 2901 |  | 
 | 2902 | #define PHY_LINK_SUPPORT		\ | 
 | 2903 | 	(PHY_AUTO_NEG_ASYM_PAUSE |	\ | 
 | 2904 | 	PHY_AUTO_NEG_SYM_PAUSE |	\ | 
 | 2905 | 	PHY_AUTO_NEG_100BT4 |		\ | 
 | 2906 | 	PHY_AUTO_NEG_100BTX_FD |	\ | 
 | 2907 | 	PHY_AUTO_NEG_100BTX |		\ | 
 | 2908 | 	PHY_AUTO_NEG_10BT_FD |		\ | 
 | 2909 | 	PHY_AUTO_NEG_10BT) | 
 | 2910 |  | 
 | 2911 | static inline void hw_r_phy_ctrl(struct ksz_hw *hw, int phy, u16 *data) | 
 | 2912 | { | 
 | 2913 | 	*data = readw(hw->io + phy + KS884X_PHY_CTRL_OFFSET); | 
 | 2914 | } | 
 | 2915 |  | 
 | 2916 | static inline void hw_w_phy_ctrl(struct ksz_hw *hw, int phy, u16 data) | 
 | 2917 | { | 
 | 2918 | 	writew(data, hw->io + phy + KS884X_PHY_CTRL_OFFSET); | 
 | 2919 | } | 
 | 2920 |  | 
 | 2921 | static inline void hw_r_phy_link_stat(struct ksz_hw *hw, int phy, u16 *data) | 
 | 2922 | { | 
 | 2923 | 	*data = readw(hw->io + phy + KS884X_PHY_STATUS_OFFSET); | 
 | 2924 | } | 
 | 2925 |  | 
 | 2926 | static inline void hw_r_phy_auto_neg(struct ksz_hw *hw, int phy, u16 *data) | 
 | 2927 | { | 
 | 2928 | 	*data = readw(hw->io + phy + KS884X_PHY_AUTO_NEG_OFFSET); | 
 | 2929 | } | 
 | 2930 |  | 
 | 2931 | static inline void hw_w_phy_auto_neg(struct ksz_hw *hw, int phy, u16 data) | 
 | 2932 | { | 
 | 2933 | 	writew(data, hw->io + phy + KS884X_PHY_AUTO_NEG_OFFSET); | 
 | 2934 | } | 
 | 2935 |  | 
 | 2936 | static inline void hw_r_phy_rem_cap(struct ksz_hw *hw, int phy, u16 *data) | 
 | 2937 | { | 
 | 2938 | 	*data = readw(hw->io + phy + KS884X_PHY_REMOTE_CAP_OFFSET); | 
 | 2939 | } | 
 | 2940 |  | 
 | 2941 | static inline void hw_r_phy_crossover(struct ksz_hw *hw, int phy, u16 *data) | 
 | 2942 | { | 
 | 2943 | 	*data = readw(hw->io + phy + KS884X_PHY_CTRL_OFFSET); | 
 | 2944 | } | 
 | 2945 |  | 
 | 2946 | static inline void hw_w_phy_crossover(struct ksz_hw *hw, int phy, u16 data) | 
 | 2947 | { | 
 | 2948 | 	writew(data, hw->io + phy + KS884X_PHY_CTRL_OFFSET); | 
 | 2949 | } | 
 | 2950 |  | 
 | 2951 | static inline void hw_r_phy_polarity(struct ksz_hw *hw, int phy, u16 *data) | 
 | 2952 | { | 
 | 2953 | 	*data = readw(hw->io + phy + KS884X_PHY_PHY_CTRL_OFFSET); | 
 | 2954 | } | 
 | 2955 |  | 
 | 2956 | static inline void hw_w_phy_polarity(struct ksz_hw *hw, int phy, u16 data) | 
 | 2957 | { | 
 | 2958 | 	writew(data, hw->io + phy + KS884X_PHY_PHY_CTRL_OFFSET); | 
 | 2959 | } | 
 | 2960 |  | 
 | 2961 | static inline void hw_r_phy_link_md(struct ksz_hw *hw, int phy, u16 *data) | 
 | 2962 | { | 
 | 2963 | 	*data = readw(hw->io + phy + KS884X_PHY_LINK_MD_OFFSET); | 
 | 2964 | } | 
 | 2965 |  | 
 | 2966 | static inline void hw_w_phy_link_md(struct ksz_hw *hw, int phy, u16 data) | 
 | 2967 | { | 
 | 2968 | 	writew(data, hw->io + phy + KS884X_PHY_LINK_MD_OFFSET); | 
 | 2969 | } | 
 | 2970 |  | 
 | 2971 | /** | 
 | 2972 |  * hw_r_phy - read data from PHY register | 
 | 2973 |  * @hw: 	The hardware instance. | 
 | 2974 |  * @port:	Port to read. | 
 | 2975 |  * @reg:	PHY register to read. | 
 | 2976 |  * @val:	Buffer to store the read data. | 
 | 2977 |  * | 
 | 2978 |  * This routine reads data from the PHY register. | 
 | 2979 |  */ | 
 | 2980 | static void hw_r_phy(struct ksz_hw *hw, int port, u16 reg, u16 *val) | 
 | 2981 | { | 
 | 2982 | 	int phy; | 
 | 2983 |  | 
 | 2984 | 	phy = KS884X_PHY_1_CTRL_OFFSET + port * PHY_CTRL_INTERVAL + reg; | 
 | 2985 | 	*val = readw(hw->io + phy); | 
 | 2986 | } | 
 | 2987 |  | 
 | 2988 | /** | 
 | 2989 |  * port_w_phy - write data to PHY register | 
 | 2990 |  * @hw: 	The hardware instance. | 
 | 2991 |  * @port:	Port to write. | 
 | 2992 |  * @reg:	PHY register to write. | 
 | 2993 |  * @val:	Word data to write. | 
 | 2994 |  * | 
 | 2995 |  * This routine writes data to the PHY register. | 
 | 2996 |  */ | 
 | 2997 | static void hw_w_phy(struct ksz_hw *hw, int port, u16 reg, u16 val) | 
 | 2998 | { | 
 | 2999 | 	int phy; | 
 | 3000 |  | 
 | 3001 | 	phy = KS884X_PHY_1_CTRL_OFFSET + port * PHY_CTRL_INTERVAL + reg; | 
 | 3002 | 	writew(val, hw->io + phy); | 
 | 3003 | } | 
 | 3004 |  | 
 | 3005 | /* | 
 | 3006 |  * EEPROM access functions | 
 | 3007 |  */ | 
 | 3008 |  | 
 | 3009 | #define AT93C_CODE			0 | 
 | 3010 | #define AT93C_WR_OFF			0x00 | 
 | 3011 | #define AT93C_WR_ALL			0x10 | 
 | 3012 | #define AT93C_ER_ALL			0x20 | 
 | 3013 | #define AT93C_WR_ON			0x30 | 
 | 3014 |  | 
 | 3015 | #define AT93C_WRITE			1 | 
 | 3016 | #define AT93C_READ			2 | 
 | 3017 | #define AT93C_ERASE			3 | 
 | 3018 |  | 
 | 3019 | #define EEPROM_DELAY			4 | 
 | 3020 |  | 
 | 3021 | static inline void drop_gpio(struct ksz_hw *hw, u8 gpio) | 
 | 3022 | { | 
 | 3023 | 	u16 data; | 
 | 3024 |  | 
 | 3025 | 	data = readw(hw->io + KS884X_EEPROM_CTRL_OFFSET); | 
 | 3026 | 	data &= ~gpio; | 
 | 3027 | 	writew(data, hw->io + KS884X_EEPROM_CTRL_OFFSET); | 
 | 3028 | } | 
 | 3029 |  | 
 | 3030 | static inline void raise_gpio(struct ksz_hw *hw, u8 gpio) | 
 | 3031 | { | 
 | 3032 | 	u16 data; | 
 | 3033 |  | 
 | 3034 | 	data = readw(hw->io + KS884X_EEPROM_CTRL_OFFSET); | 
 | 3035 | 	data |= gpio; | 
 | 3036 | 	writew(data, hw->io + KS884X_EEPROM_CTRL_OFFSET); | 
 | 3037 | } | 
 | 3038 |  | 
 | 3039 | static inline u8 state_gpio(struct ksz_hw *hw, u8 gpio) | 
 | 3040 | { | 
 | 3041 | 	u16 data; | 
 | 3042 |  | 
 | 3043 | 	data = readw(hw->io + KS884X_EEPROM_CTRL_OFFSET); | 
 | 3044 | 	return (u8)(data & gpio); | 
 | 3045 | } | 
 | 3046 |  | 
 | 3047 | static void eeprom_clk(struct ksz_hw *hw) | 
 | 3048 | { | 
 | 3049 | 	raise_gpio(hw, EEPROM_SERIAL_CLOCK); | 
 | 3050 | 	udelay(EEPROM_DELAY); | 
 | 3051 | 	drop_gpio(hw, EEPROM_SERIAL_CLOCK); | 
 | 3052 | 	udelay(EEPROM_DELAY); | 
 | 3053 | } | 
 | 3054 |  | 
 | 3055 | static u16 spi_r(struct ksz_hw *hw) | 
 | 3056 | { | 
 | 3057 | 	int i; | 
 | 3058 | 	u16 temp = 0; | 
 | 3059 |  | 
 | 3060 | 	for (i = 15; i >= 0; i--) { | 
 | 3061 | 		raise_gpio(hw, EEPROM_SERIAL_CLOCK); | 
 | 3062 | 		udelay(EEPROM_DELAY); | 
 | 3063 |  | 
 | 3064 | 		temp |= (state_gpio(hw, EEPROM_DATA_IN)) ? 1 << i : 0; | 
 | 3065 |  | 
 | 3066 | 		drop_gpio(hw, EEPROM_SERIAL_CLOCK); | 
 | 3067 | 		udelay(EEPROM_DELAY); | 
 | 3068 | 	} | 
 | 3069 | 	return temp; | 
 | 3070 | } | 
 | 3071 |  | 
 | 3072 | static void spi_w(struct ksz_hw *hw, u16 data) | 
 | 3073 | { | 
 | 3074 | 	int i; | 
 | 3075 |  | 
 | 3076 | 	for (i = 15; i >= 0; i--) { | 
 | 3077 | 		(data & (0x01 << i)) ? raise_gpio(hw, EEPROM_DATA_OUT) : | 
 | 3078 | 			drop_gpio(hw, EEPROM_DATA_OUT); | 
 | 3079 | 		eeprom_clk(hw); | 
 | 3080 | 	} | 
 | 3081 | } | 
 | 3082 |  | 
 | 3083 | static void spi_reg(struct ksz_hw *hw, u8 data, u8 reg) | 
 | 3084 | { | 
 | 3085 | 	int i; | 
 | 3086 |  | 
 | 3087 | 	/* Initial start bit */ | 
 | 3088 | 	raise_gpio(hw, EEPROM_DATA_OUT); | 
 | 3089 | 	eeprom_clk(hw); | 
 | 3090 |  | 
 | 3091 | 	/* AT93C operation */ | 
 | 3092 | 	for (i = 1; i >= 0; i--) { | 
 | 3093 | 		(data & (0x01 << i)) ? raise_gpio(hw, EEPROM_DATA_OUT) : | 
 | 3094 | 			drop_gpio(hw, EEPROM_DATA_OUT); | 
 | 3095 | 		eeprom_clk(hw); | 
 | 3096 | 	} | 
 | 3097 |  | 
 | 3098 | 	/* Address location */ | 
 | 3099 | 	for (i = 5; i >= 0; i--) { | 
 | 3100 | 		(reg & (0x01 << i)) ? raise_gpio(hw, EEPROM_DATA_OUT) : | 
 | 3101 | 			drop_gpio(hw, EEPROM_DATA_OUT); | 
 | 3102 | 		eeprom_clk(hw); | 
 | 3103 | 	} | 
 | 3104 | } | 
 | 3105 |  | 
 | 3106 | #define EEPROM_DATA_RESERVED		0 | 
 | 3107 | #define EEPROM_DATA_MAC_ADDR_0		1 | 
 | 3108 | #define EEPROM_DATA_MAC_ADDR_1		2 | 
 | 3109 | #define EEPROM_DATA_MAC_ADDR_2		3 | 
 | 3110 | #define EEPROM_DATA_SUBSYS_ID		4 | 
 | 3111 | #define EEPROM_DATA_SUBSYS_VEN_ID	5 | 
 | 3112 | #define EEPROM_DATA_PM_CAP		6 | 
 | 3113 |  | 
 | 3114 | /* User defined EEPROM data */ | 
 | 3115 | #define EEPROM_DATA_OTHER_MAC_ADDR	9 | 
 | 3116 |  | 
 | 3117 | /** | 
 | 3118 |  * eeprom_read - read from AT93C46 EEPROM | 
 | 3119 |  * @hw: 	The hardware instance. | 
 | 3120 |  * @reg:	The register offset. | 
 | 3121 |  * | 
 | 3122 |  * This function reads a word from the AT93C46 EEPROM. | 
 | 3123 |  * | 
 | 3124 |  * Return the data value. | 
 | 3125 |  */ | 
 | 3126 | static u16 eeprom_read(struct ksz_hw *hw, u8 reg) | 
 | 3127 | { | 
 | 3128 | 	u16 data; | 
 | 3129 |  | 
 | 3130 | 	raise_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT); | 
 | 3131 |  | 
 | 3132 | 	spi_reg(hw, AT93C_READ, reg); | 
 | 3133 | 	data = spi_r(hw); | 
 | 3134 |  | 
 | 3135 | 	drop_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT); | 
 | 3136 |  | 
 | 3137 | 	return data; | 
 | 3138 | } | 
 | 3139 |  | 
 | 3140 | /** | 
 | 3141 |  * eeprom_write - write to AT93C46 EEPROM | 
 | 3142 |  * @hw: 	The hardware instance. | 
 | 3143 |  * @reg:	The register offset. | 
 | 3144 |  * @data:	The data value. | 
 | 3145 |  * | 
 | 3146 |  * This procedure writes a word to the AT93C46 EEPROM. | 
 | 3147 |  */ | 
 | 3148 | static void eeprom_write(struct ksz_hw *hw, u8 reg, u16 data) | 
 | 3149 | { | 
 | 3150 | 	int timeout; | 
 | 3151 |  | 
 | 3152 | 	raise_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT); | 
 | 3153 |  | 
 | 3154 | 	/* Enable write. */ | 
 | 3155 | 	spi_reg(hw, AT93C_CODE, AT93C_WR_ON); | 
 | 3156 | 	drop_gpio(hw, EEPROM_CHIP_SELECT); | 
 | 3157 | 	udelay(1); | 
 | 3158 |  | 
 | 3159 | 	/* Erase the register. */ | 
 | 3160 | 	raise_gpio(hw, EEPROM_CHIP_SELECT); | 
 | 3161 | 	spi_reg(hw, AT93C_ERASE, reg); | 
 | 3162 | 	drop_gpio(hw, EEPROM_CHIP_SELECT); | 
 | 3163 | 	udelay(1); | 
 | 3164 |  | 
 | 3165 | 	/* Check operation complete. */ | 
 | 3166 | 	raise_gpio(hw, EEPROM_CHIP_SELECT); | 
 | 3167 | 	timeout = 8; | 
 | 3168 | 	mdelay(2); | 
 | 3169 | 	do { | 
 | 3170 | 		mdelay(1); | 
 | 3171 | 	} while (!state_gpio(hw, EEPROM_DATA_IN) && --timeout); | 
 | 3172 | 	drop_gpio(hw, EEPROM_CHIP_SELECT); | 
 | 3173 | 	udelay(1); | 
 | 3174 |  | 
 | 3175 | 	/* Write the register. */ | 
 | 3176 | 	raise_gpio(hw, EEPROM_CHIP_SELECT); | 
 | 3177 | 	spi_reg(hw, AT93C_WRITE, reg); | 
 | 3178 | 	spi_w(hw, data); | 
 | 3179 | 	drop_gpio(hw, EEPROM_CHIP_SELECT); | 
 | 3180 | 	udelay(1); | 
 | 3181 |  | 
 | 3182 | 	/* Check operation complete. */ | 
 | 3183 | 	raise_gpio(hw, EEPROM_CHIP_SELECT); | 
 | 3184 | 	timeout = 8; | 
 | 3185 | 	mdelay(2); | 
 | 3186 | 	do { | 
 | 3187 | 		mdelay(1); | 
 | 3188 | 	} while (!state_gpio(hw, EEPROM_DATA_IN) && --timeout); | 
 | 3189 | 	drop_gpio(hw, EEPROM_CHIP_SELECT); | 
 | 3190 | 	udelay(1); | 
 | 3191 |  | 
 | 3192 | 	/* Disable write. */ | 
 | 3193 | 	raise_gpio(hw, EEPROM_CHIP_SELECT); | 
 | 3194 | 	spi_reg(hw, AT93C_CODE, AT93C_WR_OFF); | 
 | 3195 |  | 
 | 3196 | 	drop_gpio(hw, EEPROM_ACCESS_ENABLE | EEPROM_CHIP_SELECT); | 
 | 3197 | } | 
 | 3198 |  | 
 | 3199 | /* | 
 | 3200 |  * Link detection routines | 
 | 3201 |  */ | 
 | 3202 |  | 
 | 3203 | static u16 advertised_flow_ctrl(struct ksz_port *port, u16 ctrl) | 
 | 3204 | { | 
 | 3205 | 	ctrl &= ~PORT_AUTO_NEG_SYM_PAUSE; | 
 | 3206 | 	switch (port->flow_ctrl) { | 
 | 3207 | 	case PHY_FLOW_CTRL: | 
 | 3208 | 		ctrl |= PORT_AUTO_NEG_SYM_PAUSE; | 
 | 3209 | 		break; | 
 | 3210 | 	/* Not supported. */ | 
 | 3211 | 	case PHY_TX_ONLY: | 
 | 3212 | 	case PHY_RX_ONLY: | 
 | 3213 | 	default: | 
 | 3214 | 		break; | 
 | 3215 | 	} | 
 | 3216 | 	return ctrl; | 
 | 3217 | } | 
 | 3218 |  | 
 | 3219 | static void set_flow_ctrl(struct ksz_hw *hw, int rx, int tx) | 
 | 3220 | { | 
 | 3221 | 	u32 rx_cfg; | 
 | 3222 | 	u32 tx_cfg; | 
 | 3223 |  | 
 | 3224 | 	rx_cfg = hw->rx_cfg; | 
 | 3225 | 	tx_cfg = hw->tx_cfg; | 
 | 3226 | 	if (rx) | 
 | 3227 | 		hw->rx_cfg |= DMA_RX_FLOW_ENABLE; | 
 | 3228 | 	else | 
 | 3229 | 		hw->rx_cfg &= ~DMA_RX_FLOW_ENABLE; | 
 | 3230 | 	if (tx) | 
 | 3231 | 		hw->tx_cfg |= DMA_TX_FLOW_ENABLE; | 
 | 3232 | 	else | 
 | 3233 | 		hw->tx_cfg &= ~DMA_TX_FLOW_ENABLE; | 
 | 3234 | 	if (hw->enabled) { | 
 | 3235 | 		if (rx_cfg != hw->rx_cfg) | 
 | 3236 | 			writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL); | 
 | 3237 | 		if (tx_cfg != hw->tx_cfg) | 
 | 3238 | 			writel(hw->tx_cfg, hw->io + KS_DMA_TX_CTRL); | 
 | 3239 | 	} | 
 | 3240 | } | 
 | 3241 |  | 
 | 3242 | static void determine_flow_ctrl(struct ksz_hw *hw, struct ksz_port *port, | 
 | 3243 | 	u16 local, u16 remote) | 
 | 3244 | { | 
 | 3245 | 	int rx; | 
 | 3246 | 	int tx; | 
 | 3247 |  | 
 | 3248 | 	if (hw->overrides & PAUSE_FLOW_CTRL) | 
 | 3249 | 		return; | 
 | 3250 |  | 
 | 3251 | 	rx = tx = 0; | 
 | 3252 | 	if (port->force_link) | 
 | 3253 | 		rx = tx = 1; | 
 | 3254 | 	if (remote & PHY_AUTO_NEG_SYM_PAUSE) { | 
 | 3255 | 		if (local & PHY_AUTO_NEG_SYM_PAUSE) { | 
 | 3256 | 			rx = tx = 1; | 
 | 3257 | 		} else if ((remote & PHY_AUTO_NEG_ASYM_PAUSE) && | 
 | 3258 | 				(local & PHY_AUTO_NEG_PAUSE) == | 
 | 3259 | 				PHY_AUTO_NEG_ASYM_PAUSE) { | 
 | 3260 | 			tx = 1; | 
 | 3261 | 		} | 
 | 3262 | 	} else if (remote & PHY_AUTO_NEG_ASYM_PAUSE) { | 
 | 3263 | 		if ((local & PHY_AUTO_NEG_PAUSE) == PHY_AUTO_NEG_PAUSE) | 
 | 3264 | 			rx = 1; | 
 | 3265 | 	} | 
 | 3266 | 	if (!hw->ksz_switch) | 
 | 3267 | 		set_flow_ctrl(hw, rx, tx); | 
 | 3268 | } | 
 | 3269 |  | 
 | 3270 | static inline void port_cfg_change(struct ksz_hw *hw, struct ksz_port *port, | 
 | 3271 | 	struct ksz_port_info *info, u16 link_status) | 
 | 3272 | { | 
 | 3273 | 	if ((hw->features & HALF_DUPLEX_SIGNAL_BUG) && | 
 | 3274 | 			!(hw->overrides & PAUSE_FLOW_CTRL)) { | 
 | 3275 | 		u32 cfg = hw->tx_cfg; | 
 | 3276 |  | 
 | 3277 | 		/* Disable flow control in the half duplex mode. */ | 
 | 3278 | 		if (1 == info->duplex) | 
 | 3279 | 			hw->tx_cfg &= ~DMA_TX_FLOW_ENABLE; | 
 | 3280 | 		if (hw->enabled && cfg != hw->tx_cfg) | 
 | 3281 | 			writel(hw->tx_cfg, hw->io + KS_DMA_TX_CTRL); | 
 | 3282 | 	} | 
 | 3283 | } | 
 | 3284 |  | 
 | 3285 | /** | 
 | 3286 |  * port_get_link_speed - get current link status | 
 | 3287 |  * @port: 	The port instance. | 
 | 3288 |  * | 
 | 3289 |  * This routine reads PHY registers to determine the current link status of the | 
 | 3290 |  * switch ports. | 
 | 3291 |  */ | 
 | 3292 | static void port_get_link_speed(struct ksz_port *port) | 
 | 3293 | { | 
 | 3294 | 	uint interrupt; | 
 | 3295 | 	struct ksz_port_info *info; | 
 | 3296 | 	struct ksz_port_info *linked = NULL; | 
 | 3297 | 	struct ksz_hw *hw = port->hw; | 
 | 3298 | 	u16 data; | 
 | 3299 | 	u16 status; | 
 | 3300 | 	u8 local; | 
 | 3301 | 	u8 remote; | 
 | 3302 | 	int i; | 
 | 3303 | 	int p; | 
 | 3304 | 	int change = 0; | 
 | 3305 |  | 
 | 3306 | 	interrupt = hw_block_intr(hw); | 
 | 3307 |  | 
 | 3308 | 	for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) { | 
 | 3309 | 		info = &hw->port_info[p]; | 
 | 3310 | 		port_r16(hw, p, KS884X_PORT_CTRL_4_OFFSET, &data); | 
 | 3311 | 		port_r16(hw, p, KS884X_PORT_STATUS_OFFSET, &status); | 
 | 3312 |  | 
 | 3313 | 		/* | 
 | 3314 | 		 * Link status is changing all the time even when there is no | 
 | 3315 | 		 * cable connection! | 
 | 3316 | 		 */ | 
 | 3317 | 		remote = status & (PORT_AUTO_NEG_COMPLETE | | 
 | 3318 | 			PORT_STATUS_LINK_GOOD); | 
 | 3319 | 		local = (u8) data; | 
 | 3320 |  | 
 | 3321 | 		/* No change to status. */ | 
 | 3322 | 		if (local == info->advertised && remote == info->partner) | 
 | 3323 | 			continue; | 
 | 3324 |  | 
 | 3325 | 		info->advertised = local; | 
 | 3326 | 		info->partner = remote; | 
 | 3327 | 		if (status & PORT_STATUS_LINK_GOOD) { | 
 | 3328 |  | 
 | 3329 | 			/* Remember the first linked port. */ | 
 | 3330 | 			if (!linked) | 
 | 3331 | 				linked = info; | 
 | 3332 |  | 
 | 3333 | 			info->tx_rate = 10 * TX_RATE_UNIT; | 
 | 3334 | 			if (status & PORT_STATUS_SPEED_100MBIT) | 
 | 3335 | 				info->tx_rate = 100 * TX_RATE_UNIT; | 
 | 3336 |  | 
 | 3337 | 			info->duplex = 1; | 
 | 3338 | 			if (status & PORT_STATUS_FULL_DUPLEX) | 
 | 3339 | 				info->duplex = 2; | 
 | 3340 |  | 
 | 3341 | 			if (media_connected != info->state) { | 
 | 3342 | 				hw_r_phy(hw, p, KS884X_PHY_AUTO_NEG_OFFSET, | 
 | 3343 | 					&data); | 
 | 3344 | 				hw_r_phy(hw, p, KS884X_PHY_REMOTE_CAP_OFFSET, | 
 | 3345 | 					&status); | 
 | 3346 | 				determine_flow_ctrl(hw, port, data, status); | 
 | 3347 | 				if (hw->ksz_switch) { | 
 | 3348 | 					port_cfg_back_pressure(hw, p, | 
 | 3349 | 						(1 == info->duplex)); | 
 | 3350 | 				} | 
 | 3351 | 				change |= 1 << i; | 
 | 3352 | 				port_cfg_change(hw, port, info, status); | 
 | 3353 | 			} | 
 | 3354 | 			info->state = media_connected; | 
 | 3355 | 		} else { | 
 | 3356 | 			if (media_disconnected != info->state) { | 
 | 3357 | 				change |= 1 << i; | 
 | 3358 |  | 
 | 3359 | 				/* Indicate the link just goes down. */ | 
 | 3360 | 				hw->port_mib[p].link_down = 1; | 
 | 3361 | 			} | 
 | 3362 | 			info->state = media_disconnected; | 
 | 3363 | 		} | 
 | 3364 | 		hw->port_mib[p].state = (u8) info->state; | 
 | 3365 | 	} | 
 | 3366 |  | 
 | 3367 | 	if (linked && media_disconnected == port->linked->state) | 
 | 3368 | 		port->linked = linked; | 
 | 3369 |  | 
 | 3370 | 	hw_restore_intr(hw, interrupt); | 
 | 3371 | } | 
 | 3372 |  | 
 | 3373 | #define PHY_RESET_TIMEOUT		10 | 
 | 3374 |  | 
 | 3375 | /** | 
 | 3376 |  * port_set_link_speed - set port speed | 
 | 3377 |  * @port: 	The port instance. | 
 | 3378 |  * | 
 | 3379 |  * This routine sets the link speed of the switch ports. | 
 | 3380 |  */ | 
 | 3381 | static void port_set_link_speed(struct ksz_port *port) | 
 | 3382 | { | 
 | 3383 | 	struct ksz_port_info *info; | 
 | 3384 | 	struct ksz_hw *hw = port->hw; | 
 | 3385 | 	u16 data; | 
 | 3386 | 	u16 cfg; | 
 | 3387 | 	u8 status; | 
 | 3388 | 	int i; | 
 | 3389 | 	int p; | 
 | 3390 |  | 
 | 3391 | 	for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) { | 
 | 3392 | 		info = &hw->port_info[p]; | 
 | 3393 |  | 
 | 3394 | 		port_r16(hw, p, KS884X_PORT_CTRL_4_OFFSET, &data); | 
 | 3395 | 		port_r8(hw, p, KS884X_PORT_STATUS_OFFSET, &status); | 
 | 3396 |  | 
 | 3397 | 		cfg = 0; | 
 | 3398 | 		if (status & PORT_STATUS_LINK_GOOD) | 
 | 3399 | 			cfg = data; | 
 | 3400 |  | 
 | 3401 | 		data |= PORT_AUTO_NEG_ENABLE; | 
 | 3402 | 		data = advertised_flow_ctrl(port, data); | 
 | 3403 |  | 
 | 3404 | 		data |= PORT_AUTO_NEG_100BTX_FD | PORT_AUTO_NEG_100BTX | | 
 | 3405 | 			PORT_AUTO_NEG_10BT_FD | PORT_AUTO_NEG_10BT; | 
 | 3406 |  | 
 | 3407 | 		/* Check if manual configuration is specified by the user. */ | 
 | 3408 | 		if (port->speed || port->duplex) { | 
 | 3409 | 			if (10 == port->speed) | 
 | 3410 | 				data &= ~(PORT_AUTO_NEG_100BTX_FD | | 
 | 3411 | 					PORT_AUTO_NEG_100BTX); | 
 | 3412 | 			else if (100 == port->speed) | 
 | 3413 | 				data &= ~(PORT_AUTO_NEG_10BT_FD | | 
 | 3414 | 					PORT_AUTO_NEG_10BT); | 
 | 3415 | 			if (1 == port->duplex) | 
 | 3416 | 				data &= ~(PORT_AUTO_NEG_100BTX_FD | | 
 | 3417 | 					PORT_AUTO_NEG_10BT_FD); | 
 | 3418 | 			else if (2 == port->duplex) | 
 | 3419 | 				data &= ~(PORT_AUTO_NEG_100BTX | | 
 | 3420 | 					PORT_AUTO_NEG_10BT); | 
 | 3421 | 		} | 
 | 3422 | 		if (data != cfg) { | 
 | 3423 | 			data |= PORT_AUTO_NEG_RESTART; | 
 | 3424 | 			port_w16(hw, p, KS884X_PORT_CTRL_4_OFFSET, data); | 
 | 3425 | 		} | 
 | 3426 | 	} | 
 | 3427 | } | 
 | 3428 |  | 
 | 3429 | /** | 
 | 3430 |  * port_force_link_speed - force port speed | 
 | 3431 |  * @port: 	The port instance. | 
 | 3432 |  * | 
 | 3433 |  * This routine forces the link speed of the switch ports. | 
 | 3434 |  */ | 
 | 3435 | static void port_force_link_speed(struct ksz_port *port) | 
 | 3436 | { | 
 | 3437 | 	struct ksz_hw *hw = port->hw; | 
 | 3438 | 	u16 data; | 
 | 3439 | 	int i; | 
 | 3440 | 	int phy; | 
 | 3441 | 	int p; | 
 | 3442 |  | 
 | 3443 | 	for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) { | 
 | 3444 | 		phy = KS884X_PHY_1_CTRL_OFFSET + p * PHY_CTRL_INTERVAL; | 
 | 3445 | 		hw_r_phy_ctrl(hw, phy, &data); | 
 | 3446 |  | 
 | 3447 | 		data &= ~PHY_AUTO_NEG_ENABLE; | 
 | 3448 |  | 
 | 3449 | 		if (10 == port->speed) | 
 | 3450 | 			data &= ~PHY_SPEED_100MBIT; | 
 | 3451 | 		else if (100 == port->speed) | 
 | 3452 | 			data |= PHY_SPEED_100MBIT; | 
 | 3453 | 		if (1 == port->duplex) | 
 | 3454 | 			data &= ~PHY_FULL_DUPLEX; | 
 | 3455 | 		else if (2 == port->duplex) | 
 | 3456 | 			data |= PHY_FULL_DUPLEX; | 
 | 3457 | 		hw_w_phy_ctrl(hw, phy, data); | 
 | 3458 | 	} | 
 | 3459 | } | 
 | 3460 |  | 
 | 3461 | static void port_set_power_saving(struct ksz_port *port, int enable) | 
 | 3462 | { | 
 | 3463 | 	struct ksz_hw *hw = port->hw; | 
 | 3464 | 	int i; | 
 | 3465 | 	int p; | 
 | 3466 |  | 
 | 3467 | 	for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) | 
 | 3468 | 		port_cfg(hw, p, | 
 | 3469 | 			KS884X_PORT_CTRL_4_OFFSET, PORT_POWER_DOWN, enable); | 
 | 3470 | } | 
 | 3471 |  | 
 | 3472 | /* | 
 | 3473 |  * KSZ8841 power management functions | 
 | 3474 |  */ | 
 | 3475 |  | 
 | 3476 | /** | 
 | 3477 |  * hw_chk_wol_pme_status - check PMEN pin | 
 | 3478 |  * @hw: 	The hardware instance. | 
 | 3479 |  * | 
 | 3480 |  * This function is used to check PMEN pin is asserted. | 
 | 3481 |  * | 
 | 3482 |  * Return 1 if PMEN pin is asserted; otherwise, 0. | 
 | 3483 |  */ | 
 | 3484 | static int hw_chk_wol_pme_status(struct ksz_hw *hw) | 
 | 3485 | { | 
 | 3486 | 	struct dev_info *hw_priv = container_of(hw, struct dev_info, hw); | 
 | 3487 | 	struct pci_dev *pdev = hw_priv->pdev; | 
 | 3488 | 	u16 data; | 
 | 3489 |  | 
 | 3490 | 	if (!pdev->pm_cap) | 
 | 3491 | 		return 0; | 
 | 3492 | 	pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &data); | 
 | 3493 | 	return (data & PCI_PM_CTRL_PME_STATUS) == PCI_PM_CTRL_PME_STATUS; | 
 | 3494 | } | 
 | 3495 |  | 
 | 3496 | /** | 
 | 3497 |  * hw_clr_wol_pme_status - clear PMEN pin | 
 | 3498 |  * @hw: 	The hardware instance. | 
 | 3499 |  * | 
 | 3500 |  * This routine is used to clear PME_Status to deassert PMEN pin. | 
 | 3501 |  */ | 
 | 3502 | static void hw_clr_wol_pme_status(struct ksz_hw *hw) | 
 | 3503 | { | 
 | 3504 | 	struct dev_info *hw_priv = container_of(hw, struct dev_info, hw); | 
 | 3505 | 	struct pci_dev *pdev = hw_priv->pdev; | 
 | 3506 | 	u16 data; | 
 | 3507 |  | 
 | 3508 | 	if (!pdev->pm_cap) | 
 | 3509 | 		return; | 
 | 3510 |  | 
 | 3511 | 	/* Clear PME_Status to deassert PMEN pin. */ | 
 | 3512 | 	pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &data); | 
 | 3513 | 	data |= PCI_PM_CTRL_PME_STATUS; | 
 | 3514 | 	pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, data); | 
 | 3515 | } | 
 | 3516 |  | 
 | 3517 | /** | 
 | 3518 |  * hw_cfg_wol_pme - enable or disable Wake-on-LAN | 
 | 3519 |  * @hw: 	The hardware instance. | 
 | 3520 |  * @set:	The flag indicating whether to enable or disable. | 
 | 3521 |  * | 
 | 3522 |  * This routine is used to enable or disable Wake-on-LAN. | 
 | 3523 |  */ | 
 | 3524 | static void hw_cfg_wol_pme(struct ksz_hw *hw, int set) | 
 | 3525 | { | 
 | 3526 | 	struct dev_info *hw_priv = container_of(hw, struct dev_info, hw); | 
 | 3527 | 	struct pci_dev *pdev = hw_priv->pdev; | 
 | 3528 | 	u16 data; | 
 | 3529 |  | 
 | 3530 | 	if (!pdev->pm_cap) | 
 | 3531 | 		return; | 
 | 3532 | 	pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &data); | 
 | 3533 | 	data &= ~PCI_PM_CTRL_STATE_MASK; | 
 | 3534 | 	if (set) | 
 | 3535 | 		data |= PCI_PM_CTRL_PME_ENABLE | PCI_D3hot; | 
 | 3536 | 	else | 
 | 3537 | 		data &= ~PCI_PM_CTRL_PME_ENABLE; | 
 | 3538 | 	pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, data); | 
 | 3539 | } | 
 | 3540 |  | 
 | 3541 | /** | 
 | 3542 |  * hw_cfg_wol - configure Wake-on-LAN features | 
 | 3543 |  * @hw: 	The hardware instance. | 
 | 3544 |  * @frame:	The pattern frame bit. | 
 | 3545 |  * @set:	The flag indicating whether to enable or disable. | 
 | 3546 |  * | 
 | 3547 |  * This routine is used to enable or disable certain Wake-on-LAN features. | 
 | 3548 |  */ | 
 | 3549 | static void hw_cfg_wol(struct ksz_hw *hw, u16 frame, int set) | 
 | 3550 | { | 
 | 3551 | 	u16 data; | 
 | 3552 |  | 
 | 3553 | 	data = readw(hw->io + KS8841_WOL_CTRL_OFFSET); | 
 | 3554 | 	if (set) | 
 | 3555 | 		data |= frame; | 
 | 3556 | 	else | 
 | 3557 | 		data &= ~frame; | 
 | 3558 | 	writew(data, hw->io + KS8841_WOL_CTRL_OFFSET); | 
 | 3559 | } | 
 | 3560 |  | 
 | 3561 | /** | 
 | 3562 |  * hw_set_wol_frame - program Wake-on-LAN pattern | 
 | 3563 |  * @hw: 	The hardware instance. | 
 | 3564 |  * @i:		The frame index. | 
 | 3565 |  * @mask_size:	The size of the mask. | 
 | 3566 |  * @mask:	Mask to ignore certain bytes in the pattern. | 
 | 3567 |  * @frame_size:	The size of the frame. | 
 | 3568 |  * @pattern:	The frame data. | 
 | 3569 |  * | 
 | 3570 |  * This routine is used to program Wake-on-LAN pattern. | 
 | 3571 |  */ | 
 | 3572 | static void hw_set_wol_frame(struct ksz_hw *hw, int i, uint mask_size, | 
| Joe Perches | b6bc765 | 2010-12-21 02:16:08 -0800 | [diff] [blame] | 3573 | 	const u8 *mask, uint frame_size, const u8 *pattern) | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 3574 | { | 
 | 3575 | 	int bits; | 
 | 3576 | 	int from; | 
 | 3577 | 	int len; | 
 | 3578 | 	int to; | 
 | 3579 | 	u32 crc; | 
 | 3580 | 	u8 data[64]; | 
 | 3581 | 	u8 val = 0; | 
 | 3582 |  | 
 | 3583 | 	if (frame_size > mask_size * 8) | 
 | 3584 | 		frame_size = mask_size * 8; | 
 | 3585 | 	if (frame_size > 64) | 
 | 3586 | 		frame_size = 64; | 
 | 3587 |  | 
 | 3588 | 	i *= 0x10; | 
 | 3589 | 	writel(0, hw->io + KS8841_WOL_FRAME_BYTE0_OFFSET + i); | 
 | 3590 | 	writel(0, hw->io + KS8841_WOL_FRAME_BYTE2_OFFSET + i); | 
 | 3591 |  | 
 | 3592 | 	bits = len = from = to = 0; | 
 | 3593 | 	do { | 
 | 3594 | 		if (bits) { | 
 | 3595 | 			if ((val & 1)) | 
 | 3596 | 				data[to++] = pattern[from]; | 
 | 3597 | 			val >>= 1; | 
 | 3598 | 			++from; | 
 | 3599 | 			--bits; | 
 | 3600 | 		} else { | 
 | 3601 | 			val = mask[len]; | 
 | 3602 | 			writeb(val, hw->io + KS8841_WOL_FRAME_BYTE0_OFFSET + i | 
 | 3603 | 				+ len); | 
 | 3604 | 			++len; | 
 | 3605 | 			if (val) | 
 | 3606 | 				bits = 8; | 
 | 3607 | 			else | 
 | 3608 | 				from += 8; | 
 | 3609 | 		} | 
 | 3610 | 	} while (from < (int) frame_size); | 
 | 3611 | 	if (val) { | 
 | 3612 | 		bits = mask[len - 1]; | 
 | 3613 | 		val <<= (from % 8); | 
 | 3614 | 		bits &= ~val; | 
 | 3615 | 		writeb(bits, hw->io + KS8841_WOL_FRAME_BYTE0_OFFSET + i + len - | 
 | 3616 | 			1); | 
 | 3617 | 	} | 
 | 3618 | 	crc = ether_crc(to, data); | 
 | 3619 | 	writel(crc, hw->io + KS8841_WOL_FRAME_CRC_OFFSET + i); | 
 | 3620 | } | 
 | 3621 |  | 
 | 3622 | /** | 
 | 3623 |  * hw_add_wol_arp - add ARP pattern | 
 | 3624 |  * @hw: 	The hardware instance. | 
 | 3625 |  * @ip_addr:	The IPv4 address assigned to the device. | 
 | 3626 |  * | 
 | 3627 |  * This routine is used to add ARP pattern for waking up the host. | 
 | 3628 |  */ | 
| Joe Perches | b6bc765 | 2010-12-21 02:16:08 -0800 | [diff] [blame] | 3629 | static void hw_add_wol_arp(struct ksz_hw *hw, const u8 *ip_addr) | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 3630 | { | 
| Joe Perches | b6bc765 | 2010-12-21 02:16:08 -0800 | [diff] [blame] | 3631 | 	static const u8 mask[6] = { 0x3F, 0xF0, 0x3F, 0x00, 0xC0, 0x03 }; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 3632 | 	u8 pattern[42] = { | 
 | 3633 | 		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | 
 | 3634 | 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 | 3635 | 		0x08, 0x06, | 
 | 3636 | 		0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, | 
 | 3637 | 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 | 3638 | 		0x00, 0x00, 0x00, 0x00, | 
 | 3639 | 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 
 | 3640 | 		0x00, 0x00, 0x00, 0x00 }; | 
 | 3641 |  | 
 | 3642 | 	memcpy(&pattern[38], ip_addr, 4); | 
 | 3643 | 	hw_set_wol_frame(hw, 3, 6, mask, 42, pattern); | 
 | 3644 | } | 
 | 3645 |  | 
 | 3646 | /** | 
 | 3647 |  * hw_add_wol_bcast - add broadcast pattern | 
 | 3648 |  * @hw: 	The hardware instance. | 
 | 3649 |  * | 
 | 3650 |  * This routine is used to add broadcast pattern for waking up the host. | 
 | 3651 |  */ | 
 | 3652 | static void hw_add_wol_bcast(struct ksz_hw *hw) | 
 | 3653 | { | 
| Joe Perches | b6bc765 | 2010-12-21 02:16:08 -0800 | [diff] [blame] | 3654 | 	static const u8 mask[] = { 0x3F }; | 
 | 3655 | 	static const u8 pattern[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 3656 |  | 
 | 3657 | 	hw_set_wol_frame(hw, 2, 1, mask, MAC_ADDR_LEN, pattern); | 
 | 3658 | } | 
 | 3659 |  | 
 | 3660 | /** | 
 | 3661 |  * hw_add_wol_mcast - add multicast pattern | 
 | 3662 |  * @hw: 	The hardware instance. | 
 | 3663 |  * | 
 | 3664 |  * This routine is used to add multicast pattern for waking up the host. | 
 | 3665 |  * | 
 | 3666 |  * It is assumed the multicast packet is the ICMPv6 neighbor solicitation used | 
 | 3667 |  * by IPv6 ping command.  Note that multicast packets are filtred through the | 
 | 3668 |  * multicast hash table, so not all multicast packets can wake up the host. | 
 | 3669 |  */ | 
 | 3670 | static void hw_add_wol_mcast(struct ksz_hw *hw) | 
 | 3671 | { | 
| Joe Perches | b6bc765 | 2010-12-21 02:16:08 -0800 | [diff] [blame] | 3672 | 	static const u8 mask[] = { 0x3F }; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 3673 | 	u8 pattern[] = { 0x33, 0x33, 0xFF, 0x00, 0x00, 0x00 }; | 
 | 3674 |  | 
 | 3675 | 	memcpy(&pattern[3], &hw->override_addr[3], 3); | 
 | 3676 | 	hw_set_wol_frame(hw, 1, 1, mask, 6, pattern); | 
 | 3677 | } | 
 | 3678 |  | 
 | 3679 | /** | 
 | 3680 |  * hw_add_wol_ucast - add unicast pattern | 
 | 3681 |  * @hw: 	The hardware instance. | 
 | 3682 |  * | 
 | 3683 |  * This routine is used to add unicast pattern to wakeup the host. | 
 | 3684 |  * | 
 | 3685 |  * It is assumed the unicast packet is directed to the device, as the hardware | 
 | 3686 |  * can only receive them in normal case. | 
 | 3687 |  */ | 
 | 3688 | static void hw_add_wol_ucast(struct ksz_hw *hw) | 
 | 3689 | { | 
| Joe Perches | b6bc765 | 2010-12-21 02:16:08 -0800 | [diff] [blame] | 3690 | 	static const u8 mask[] = { 0x3F }; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 3691 |  | 
 | 3692 | 	hw_set_wol_frame(hw, 0, 1, mask, MAC_ADDR_LEN, hw->override_addr); | 
 | 3693 | } | 
 | 3694 |  | 
 | 3695 | /** | 
 | 3696 |  * hw_enable_wol - enable Wake-on-LAN | 
 | 3697 |  * @hw: 	The hardware instance. | 
 | 3698 |  * @wol_enable:	The Wake-on-LAN settings. | 
 | 3699 |  * @net_addr:	The IPv4 address assigned to the device. | 
 | 3700 |  * | 
 | 3701 |  * This routine is used to enable Wake-on-LAN depending on driver settings. | 
 | 3702 |  */ | 
| Joe Perches | b6bc765 | 2010-12-21 02:16:08 -0800 | [diff] [blame] | 3703 | static void hw_enable_wol(struct ksz_hw *hw, u32 wol_enable, const u8 *net_addr) | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 3704 | { | 
 | 3705 | 	hw_cfg_wol(hw, KS8841_WOL_MAGIC_ENABLE, (wol_enable & WAKE_MAGIC)); | 
 | 3706 | 	hw_cfg_wol(hw, KS8841_WOL_FRAME0_ENABLE, (wol_enable & WAKE_UCAST)); | 
 | 3707 | 	hw_add_wol_ucast(hw); | 
 | 3708 | 	hw_cfg_wol(hw, KS8841_WOL_FRAME1_ENABLE, (wol_enable & WAKE_MCAST)); | 
 | 3709 | 	hw_add_wol_mcast(hw); | 
 | 3710 | 	hw_cfg_wol(hw, KS8841_WOL_FRAME2_ENABLE, (wol_enable & WAKE_BCAST)); | 
 | 3711 | 	hw_cfg_wol(hw, KS8841_WOL_FRAME3_ENABLE, (wol_enable & WAKE_ARP)); | 
 | 3712 | 	hw_add_wol_arp(hw, net_addr); | 
 | 3713 | } | 
 | 3714 |  | 
 | 3715 | /** | 
 | 3716 |  * hw_init - check driver is correct for the hardware | 
 | 3717 |  * @hw: 	The hardware instance. | 
 | 3718 |  * | 
 | 3719 |  * This function checks the hardware is correct for this driver and sets the | 
 | 3720 |  * hardware up for proper initialization. | 
 | 3721 |  * | 
 | 3722 |  * Return number of ports or 0 if not right. | 
 | 3723 |  */ | 
 | 3724 | static int hw_init(struct ksz_hw *hw) | 
 | 3725 | { | 
 | 3726 | 	int rc = 0; | 
 | 3727 | 	u16 data; | 
 | 3728 | 	u16 revision; | 
 | 3729 |  | 
 | 3730 | 	/* Set bus speed to 125MHz. */ | 
 | 3731 | 	writew(BUS_SPEED_125_MHZ, hw->io + KS884X_BUS_CTRL_OFFSET); | 
 | 3732 |  | 
 | 3733 | 	/* Check KSZ884x chip ID. */ | 
 | 3734 | 	data = readw(hw->io + KS884X_CHIP_ID_OFFSET); | 
 | 3735 |  | 
 | 3736 | 	revision = (data & KS884X_REVISION_MASK) >> KS884X_REVISION_SHIFT; | 
 | 3737 | 	data &= KS884X_CHIP_ID_MASK_41; | 
 | 3738 | 	if (REG_CHIP_ID_41 == data) | 
 | 3739 | 		rc = 1; | 
 | 3740 | 	else if (REG_CHIP_ID_42 == data) | 
 | 3741 | 		rc = 2; | 
 | 3742 | 	else | 
 | 3743 | 		return 0; | 
 | 3744 |  | 
 | 3745 | 	/* Setup hardware features or bug workarounds. */ | 
 | 3746 | 	if (revision <= 1) { | 
 | 3747 | 		hw->features |= SMALL_PACKET_TX_BUG; | 
 | 3748 | 		if (1 == rc) | 
 | 3749 | 			hw->features |= HALF_DUPLEX_SIGNAL_BUG; | 
 | 3750 | 	} | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 3751 | 	return rc; | 
 | 3752 | } | 
 | 3753 |  | 
 | 3754 | /** | 
 | 3755 |  * hw_reset - reset the hardware | 
 | 3756 |  * @hw: 	The hardware instance. | 
 | 3757 |  * | 
 | 3758 |  * This routine resets the hardware. | 
 | 3759 |  */ | 
 | 3760 | static void hw_reset(struct ksz_hw *hw) | 
 | 3761 | { | 
 | 3762 | 	writew(GLOBAL_SOFTWARE_RESET, hw->io + KS884X_GLOBAL_CTRL_OFFSET); | 
 | 3763 |  | 
 | 3764 | 	/* Wait for device to reset. */ | 
 | 3765 | 	mdelay(10); | 
 | 3766 |  | 
 | 3767 | 	/* Write 0 to clear device reset. */ | 
 | 3768 | 	writew(0, hw->io + KS884X_GLOBAL_CTRL_OFFSET); | 
 | 3769 | } | 
 | 3770 |  | 
 | 3771 | /** | 
 | 3772 |  * hw_setup - setup the hardware | 
 | 3773 |  * @hw: 	The hardware instance. | 
 | 3774 |  * | 
 | 3775 |  * This routine setup the hardware for proper operation. | 
 | 3776 |  */ | 
 | 3777 | static void hw_setup(struct ksz_hw *hw) | 
 | 3778 | { | 
 | 3779 | #if SET_DEFAULT_LED | 
 | 3780 | 	u16 data; | 
 | 3781 |  | 
 | 3782 | 	/* Change default LED mode. */ | 
 | 3783 | 	data = readw(hw->io + KS8842_SWITCH_CTRL_5_OFFSET); | 
 | 3784 | 	data &= ~LED_MODE; | 
 | 3785 | 	data |= SET_DEFAULT_LED; | 
 | 3786 | 	writew(data, hw->io + KS8842_SWITCH_CTRL_5_OFFSET); | 
 | 3787 | #endif | 
 | 3788 |  | 
 | 3789 | 	/* Setup transmit control. */ | 
 | 3790 | 	hw->tx_cfg = (DMA_TX_PAD_ENABLE | DMA_TX_CRC_ENABLE | | 
 | 3791 | 		(DMA_BURST_DEFAULT << DMA_BURST_SHIFT) | DMA_TX_ENABLE); | 
 | 3792 |  | 
 | 3793 | 	/* Setup receive control. */ | 
 | 3794 | 	hw->rx_cfg = (DMA_RX_BROADCAST | DMA_RX_UNICAST | | 
 | 3795 | 		(DMA_BURST_DEFAULT << DMA_BURST_SHIFT) | DMA_RX_ENABLE); | 
 | 3796 | 	hw->rx_cfg |= KS884X_DMA_RX_MULTICAST; | 
 | 3797 |  | 
 | 3798 | 	/* Hardware cannot handle UDP packet in IP fragments. */ | 
 | 3799 | 	hw->rx_cfg |= (DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP); | 
 | 3800 |  | 
 | 3801 | 	if (hw->all_multi) | 
 | 3802 | 		hw->rx_cfg |= DMA_RX_ALL_MULTICAST; | 
 | 3803 | 	if (hw->promiscuous) | 
 | 3804 | 		hw->rx_cfg |= DMA_RX_PROMISCUOUS; | 
 | 3805 | } | 
 | 3806 |  | 
 | 3807 | /** | 
 | 3808 |  * hw_setup_intr - setup interrupt mask | 
 | 3809 |  * @hw: 	The hardware instance. | 
 | 3810 |  * | 
 | 3811 |  * This routine setup the interrupt mask for proper operation. | 
 | 3812 |  */ | 
 | 3813 | static void hw_setup_intr(struct ksz_hw *hw) | 
 | 3814 | { | 
 | 3815 | 	hw->intr_mask = KS884X_INT_MASK | KS884X_INT_RX_OVERRUN; | 
 | 3816 | } | 
 | 3817 |  | 
 | 3818 | static void ksz_check_desc_num(struct ksz_desc_info *info) | 
 | 3819 | { | 
 | 3820 | #define MIN_DESC_SHIFT  2 | 
 | 3821 |  | 
 | 3822 | 	int alloc = info->alloc; | 
 | 3823 | 	int shift; | 
 | 3824 |  | 
 | 3825 | 	shift = 0; | 
 | 3826 | 	while (!(alloc & 1)) { | 
 | 3827 | 		shift++; | 
 | 3828 | 		alloc >>= 1; | 
 | 3829 | 	} | 
 | 3830 | 	if (alloc != 1 || shift < MIN_DESC_SHIFT) { | 
| Joe Perches | 0dc7d2b | 2010-02-27 14:43:51 +0000 | [diff] [blame] | 3831 | 		pr_alert("Hardware descriptor numbers not right!\n"); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 3832 | 		while (alloc) { | 
 | 3833 | 			shift++; | 
 | 3834 | 			alloc >>= 1; | 
 | 3835 | 		} | 
 | 3836 | 		if (shift < MIN_DESC_SHIFT) | 
 | 3837 | 			shift = MIN_DESC_SHIFT; | 
 | 3838 | 		alloc = 1 << shift; | 
 | 3839 | 		info->alloc = alloc; | 
 | 3840 | 	} | 
 | 3841 | 	info->mask = info->alloc - 1; | 
 | 3842 | } | 
 | 3843 |  | 
 | 3844 | static void hw_init_desc(struct ksz_desc_info *desc_info, int transmit) | 
 | 3845 | { | 
 | 3846 | 	int i; | 
 | 3847 | 	u32 phys = desc_info->ring_phys; | 
 | 3848 | 	struct ksz_hw_desc *desc = desc_info->ring_virt; | 
 | 3849 | 	struct ksz_desc *cur = desc_info->ring; | 
 | 3850 | 	struct ksz_desc *previous = NULL; | 
 | 3851 |  | 
 | 3852 | 	for (i = 0; i < desc_info->alloc; i++) { | 
 | 3853 | 		cur->phw = desc++; | 
 | 3854 | 		phys += desc_info->size; | 
 | 3855 | 		previous = cur++; | 
 | 3856 | 		previous->phw->next = cpu_to_le32(phys); | 
 | 3857 | 	} | 
 | 3858 | 	previous->phw->next = cpu_to_le32(desc_info->ring_phys); | 
 | 3859 | 	previous->sw.buf.rx.end_of_ring = 1; | 
 | 3860 | 	previous->phw->buf.data = cpu_to_le32(previous->sw.buf.data); | 
 | 3861 |  | 
 | 3862 | 	desc_info->avail = desc_info->alloc; | 
 | 3863 | 	desc_info->last = desc_info->next = 0; | 
 | 3864 |  | 
 | 3865 | 	desc_info->cur = desc_info->ring; | 
 | 3866 | } | 
 | 3867 |  | 
 | 3868 | /** | 
 | 3869 |  * hw_set_desc_base - set descriptor base addresses | 
 | 3870 |  * @hw: 	The hardware instance. | 
 | 3871 |  * @tx_addr:	The transmit descriptor base. | 
 | 3872 |  * @rx_addr:	The receive descriptor base. | 
 | 3873 |  * | 
 | 3874 |  * This routine programs the descriptor base addresses after reset. | 
 | 3875 |  */ | 
 | 3876 | static void hw_set_desc_base(struct ksz_hw *hw, u32 tx_addr, u32 rx_addr) | 
 | 3877 | { | 
 | 3878 | 	/* Set base address of Tx/Rx descriptors. */ | 
 | 3879 | 	writel(tx_addr, hw->io + KS_DMA_TX_ADDR); | 
 | 3880 | 	writel(rx_addr, hw->io + KS_DMA_RX_ADDR); | 
 | 3881 | } | 
 | 3882 |  | 
 | 3883 | static void hw_reset_pkts(struct ksz_desc_info *info) | 
 | 3884 | { | 
 | 3885 | 	info->cur = info->ring; | 
 | 3886 | 	info->avail = info->alloc; | 
 | 3887 | 	info->last = info->next = 0; | 
 | 3888 | } | 
 | 3889 |  | 
 | 3890 | static inline void hw_resume_rx(struct ksz_hw *hw) | 
 | 3891 | { | 
 | 3892 | 	writel(DMA_START, hw->io + KS_DMA_RX_START); | 
 | 3893 | } | 
 | 3894 |  | 
 | 3895 | /** | 
 | 3896 |  * hw_start_rx - start receiving | 
 | 3897 |  * @hw: 	The hardware instance. | 
 | 3898 |  * | 
 | 3899 |  * This routine starts the receive function of the hardware. | 
 | 3900 |  */ | 
 | 3901 | static void hw_start_rx(struct ksz_hw *hw) | 
 | 3902 | { | 
 | 3903 | 	writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL); | 
 | 3904 |  | 
 | 3905 | 	/* Notify when the receive stops. */ | 
 | 3906 | 	hw->intr_mask |= KS884X_INT_RX_STOPPED; | 
 | 3907 |  | 
 | 3908 | 	writel(DMA_START, hw->io + KS_DMA_RX_START); | 
 | 3909 | 	hw_ack_intr(hw, KS884X_INT_RX_STOPPED); | 
 | 3910 | 	hw->rx_stop++; | 
 | 3911 |  | 
 | 3912 | 	/* Variable overflows. */ | 
 | 3913 | 	if (0 == hw->rx_stop) | 
 | 3914 | 		hw->rx_stop = 2; | 
 | 3915 | } | 
 | 3916 |  | 
 | 3917 | /* | 
 | 3918 |  * hw_stop_rx - stop receiving | 
 | 3919 |  * @hw: 	The hardware instance. | 
 | 3920 |  * | 
 | 3921 |  * This routine stops the receive function of the hardware. | 
 | 3922 |  */ | 
 | 3923 | static void hw_stop_rx(struct ksz_hw *hw) | 
 | 3924 | { | 
 | 3925 | 	hw->rx_stop = 0; | 
 | 3926 | 	hw_turn_off_intr(hw, KS884X_INT_RX_STOPPED); | 
 | 3927 | 	writel((hw->rx_cfg & ~DMA_RX_ENABLE), hw->io + KS_DMA_RX_CTRL); | 
 | 3928 | } | 
 | 3929 |  | 
 | 3930 | /** | 
 | 3931 |  * hw_start_tx - start transmitting | 
 | 3932 |  * @hw: 	The hardware instance. | 
 | 3933 |  * | 
 | 3934 |  * This routine starts the transmit function of the hardware. | 
 | 3935 |  */ | 
 | 3936 | static void hw_start_tx(struct ksz_hw *hw) | 
 | 3937 | { | 
 | 3938 | 	writel(hw->tx_cfg, hw->io + KS_DMA_TX_CTRL); | 
 | 3939 | } | 
 | 3940 |  | 
 | 3941 | /** | 
 | 3942 |  * hw_stop_tx - stop transmitting | 
 | 3943 |  * @hw: 	The hardware instance. | 
 | 3944 |  * | 
 | 3945 |  * This routine stops the transmit function of the hardware. | 
 | 3946 |  */ | 
 | 3947 | static void hw_stop_tx(struct ksz_hw *hw) | 
 | 3948 | { | 
 | 3949 | 	writel((hw->tx_cfg & ~DMA_TX_ENABLE), hw->io + KS_DMA_TX_CTRL); | 
 | 3950 | } | 
 | 3951 |  | 
 | 3952 | /** | 
 | 3953 |  * hw_disable - disable hardware | 
 | 3954 |  * @hw: 	The hardware instance. | 
 | 3955 |  * | 
 | 3956 |  * This routine disables the hardware. | 
 | 3957 |  */ | 
 | 3958 | static void hw_disable(struct ksz_hw *hw) | 
 | 3959 | { | 
 | 3960 | 	hw_stop_rx(hw); | 
 | 3961 | 	hw_stop_tx(hw); | 
 | 3962 | 	hw->enabled = 0; | 
 | 3963 | } | 
 | 3964 |  | 
 | 3965 | /** | 
 | 3966 |  * hw_enable - enable hardware | 
 | 3967 |  * @hw: 	The hardware instance. | 
 | 3968 |  * | 
 | 3969 |  * This routine enables the hardware. | 
 | 3970 |  */ | 
 | 3971 | static void hw_enable(struct ksz_hw *hw) | 
 | 3972 | { | 
 | 3973 | 	hw_start_tx(hw); | 
 | 3974 | 	hw_start_rx(hw); | 
 | 3975 | 	hw->enabled = 1; | 
 | 3976 | } | 
 | 3977 |  | 
 | 3978 | /** | 
 | 3979 |  * hw_alloc_pkt - allocate enough descriptors for transmission | 
 | 3980 |  * @hw: 	The hardware instance. | 
 | 3981 |  * @length:	The length of the packet. | 
 | 3982 |  * @physical:	Number of descriptors required. | 
 | 3983 |  * | 
 | 3984 |  * This function allocates descriptors for transmission. | 
 | 3985 |  * | 
 | 3986 |  * Return 0 if not successful; 1 for buffer copy; or number of descriptors. | 
 | 3987 |  */ | 
 | 3988 | static int hw_alloc_pkt(struct ksz_hw *hw, int length, int physical) | 
 | 3989 | { | 
 | 3990 | 	/* Always leave one descriptor free. */ | 
 | 3991 | 	if (hw->tx_desc_info.avail <= 1) | 
 | 3992 | 		return 0; | 
 | 3993 |  | 
 | 3994 | 	/* Allocate a descriptor for transmission and mark it current. */ | 
 | 3995 | 	get_tx_pkt(&hw->tx_desc_info, &hw->tx_desc_info.cur); | 
 | 3996 | 	hw->tx_desc_info.cur->sw.buf.tx.first_seg = 1; | 
 | 3997 |  | 
 | 3998 | 	/* Keep track of number of transmit descriptors used so far. */ | 
 | 3999 | 	++hw->tx_int_cnt; | 
 | 4000 | 	hw->tx_size += length; | 
 | 4001 |  | 
 | 4002 | 	/* Cannot hold on too much data. */ | 
 | 4003 | 	if (hw->tx_size >= MAX_TX_HELD_SIZE) | 
 | 4004 | 		hw->tx_int_cnt = hw->tx_int_mask + 1; | 
 | 4005 |  | 
 | 4006 | 	if (physical > hw->tx_desc_info.avail) | 
 | 4007 | 		return 1; | 
 | 4008 |  | 
 | 4009 | 	return hw->tx_desc_info.avail; | 
 | 4010 | } | 
 | 4011 |  | 
 | 4012 | /** | 
 | 4013 |  * hw_send_pkt - mark packet for transmission | 
 | 4014 |  * @hw: 	The hardware instance. | 
 | 4015 |  * | 
 | 4016 |  * This routine marks the packet for transmission in PCI version. | 
 | 4017 |  */ | 
 | 4018 | static void hw_send_pkt(struct ksz_hw *hw) | 
 | 4019 | { | 
 | 4020 | 	struct ksz_desc *cur = hw->tx_desc_info.cur; | 
 | 4021 |  | 
 | 4022 | 	cur->sw.buf.tx.last_seg = 1; | 
 | 4023 |  | 
 | 4024 | 	/* Interrupt only after specified number of descriptors used. */ | 
 | 4025 | 	if (hw->tx_int_cnt > hw->tx_int_mask) { | 
 | 4026 | 		cur->sw.buf.tx.intr = 1; | 
 | 4027 | 		hw->tx_int_cnt = 0; | 
 | 4028 | 		hw->tx_size = 0; | 
 | 4029 | 	} | 
 | 4030 |  | 
 | 4031 | 	/* KSZ8842 supports port directed transmission. */ | 
 | 4032 | 	cur->sw.buf.tx.dest_port = hw->dst_ports; | 
 | 4033 |  | 
 | 4034 | 	release_desc(cur); | 
 | 4035 |  | 
 | 4036 | 	writel(0, hw->io + KS_DMA_TX_START); | 
 | 4037 | } | 
 | 4038 |  | 
 | 4039 | static int empty_addr(u8 *addr) | 
 | 4040 | { | 
 | 4041 | 	u32 *addr1 = (u32 *) addr; | 
 | 4042 | 	u16 *addr2 = (u16 *) &addr[4]; | 
 | 4043 |  | 
 | 4044 | 	return 0 == *addr1 && 0 == *addr2; | 
 | 4045 | } | 
 | 4046 |  | 
 | 4047 | /** | 
 | 4048 |  * hw_set_addr - set MAC address | 
 | 4049 |  * @hw: 	The hardware instance. | 
 | 4050 |  * | 
 | 4051 |  * This routine programs the MAC address of the hardware when the address is | 
 | 4052 |  * overrided. | 
 | 4053 |  */ | 
 | 4054 | static void hw_set_addr(struct ksz_hw *hw) | 
 | 4055 | { | 
 | 4056 | 	int i; | 
 | 4057 |  | 
 | 4058 | 	for (i = 0; i < MAC_ADDR_LEN; i++) | 
 | 4059 | 		writeb(hw->override_addr[MAC_ADDR_ORDER(i)], | 
 | 4060 | 			hw->io + KS884X_ADDR_0_OFFSET + i); | 
 | 4061 |  | 
 | 4062 | 	sw_set_addr(hw, hw->override_addr); | 
 | 4063 | } | 
 | 4064 |  | 
 | 4065 | /** | 
 | 4066 |  * hw_read_addr - read MAC address | 
 | 4067 |  * @hw: 	The hardware instance. | 
 | 4068 |  * | 
 | 4069 |  * This routine retrieves the MAC address of the hardware. | 
 | 4070 |  */ | 
 | 4071 | static void hw_read_addr(struct ksz_hw *hw) | 
 | 4072 | { | 
 | 4073 | 	int i; | 
 | 4074 |  | 
 | 4075 | 	for (i = 0; i < MAC_ADDR_LEN; i++) | 
 | 4076 | 		hw->perm_addr[MAC_ADDR_ORDER(i)] = readb(hw->io + | 
 | 4077 | 			KS884X_ADDR_0_OFFSET + i); | 
 | 4078 |  | 
 | 4079 | 	if (!hw->mac_override) { | 
 | 4080 | 		memcpy(hw->override_addr, hw->perm_addr, MAC_ADDR_LEN); | 
 | 4081 | 		if (empty_addr(hw->override_addr)) { | 
 | 4082 | 			memcpy(hw->perm_addr, DEFAULT_MAC_ADDRESS, | 
 | 4083 | 				MAC_ADDR_LEN); | 
 | 4084 | 			memcpy(hw->override_addr, DEFAULT_MAC_ADDRESS, | 
 | 4085 | 				MAC_ADDR_LEN); | 
 | 4086 | 			hw->override_addr[5] += hw->id; | 
 | 4087 | 			hw_set_addr(hw); | 
 | 4088 | 		} | 
 | 4089 | 	} | 
 | 4090 | } | 
 | 4091 |  | 
 | 4092 | static void hw_ena_add_addr(struct ksz_hw *hw, int index, u8 *mac_addr) | 
 | 4093 | { | 
 | 4094 | 	int i; | 
 | 4095 | 	u32 mac_addr_lo; | 
 | 4096 | 	u32 mac_addr_hi; | 
 | 4097 |  | 
 | 4098 | 	mac_addr_hi = 0; | 
 | 4099 | 	for (i = 0; i < 2; i++) { | 
 | 4100 | 		mac_addr_hi <<= 8; | 
 | 4101 | 		mac_addr_hi |= mac_addr[i]; | 
 | 4102 | 	} | 
 | 4103 | 	mac_addr_hi |= ADD_ADDR_ENABLE; | 
 | 4104 | 	mac_addr_lo = 0; | 
 | 4105 | 	for (i = 2; i < 6; i++) { | 
 | 4106 | 		mac_addr_lo <<= 8; | 
 | 4107 | 		mac_addr_lo |= mac_addr[i]; | 
 | 4108 | 	} | 
 | 4109 | 	index *= ADD_ADDR_INCR; | 
 | 4110 |  | 
 | 4111 | 	writel(mac_addr_lo, hw->io + index + KS_ADD_ADDR_0_LO); | 
 | 4112 | 	writel(mac_addr_hi, hw->io + index + KS_ADD_ADDR_0_HI); | 
 | 4113 | } | 
 | 4114 |  | 
 | 4115 | static void hw_set_add_addr(struct ksz_hw *hw) | 
 | 4116 | { | 
 | 4117 | 	int i; | 
 | 4118 |  | 
 | 4119 | 	for (i = 0; i < ADDITIONAL_ENTRIES; i++) { | 
 | 4120 | 		if (empty_addr(hw->address[i])) | 
 | 4121 | 			writel(0, hw->io + ADD_ADDR_INCR * i + | 
 | 4122 | 				KS_ADD_ADDR_0_HI); | 
 | 4123 | 		else | 
 | 4124 | 			hw_ena_add_addr(hw, i, hw->address[i]); | 
 | 4125 | 	} | 
 | 4126 | } | 
 | 4127 |  | 
 | 4128 | static int hw_add_addr(struct ksz_hw *hw, u8 *mac_addr) | 
 | 4129 | { | 
 | 4130 | 	int i; | 
 | 4131 | 	int j = ADDITIONAL_ENTRIES; | 
 | 4132 |  | 
 | 4133 | 	if (!memcmp(hw->override_addr, mac_addr, MAC_ADDR_LEN)) | 
 | 4134 | 		return 0; | 
 | 4135 | 	for (i = 0; i < hw->addr_list_size; i++) { | 
 | 4136 | 		if (!memcmp(hw->address[i], mac_addr, MAC_ADDR_LEN)) | 
 | 4137 | 			return 0; | 
 | 4138 | 		if (ADDITIONAL_ENTRIES == j && empty_addr(hw->address[i])) | 
 | 4139 | 			j = i; | 
 | 4140 | 	} | 
 | 4141 | 	if (j < ADDITIONAL_ENTRIES) { | 
 | 4142 | 		memcpy(hw->address[j], mac_addr, MAC_ADDR_LEN); | 
 | 4143 | 		hw_ena_add_addr(hw, j, hw->address[j]); | 
 | 4144 | 		return 0; | 
 | 4145 | 	} | 
 | 4146 | 	return -1; | 
 | 4147 | } | 
 | 4148 |  | 
 | 4149 | static int hw_del_addr(struct ksz_hw *hw, u8 *mac_addr) | 
 | 4150 | { | 
 | 4151 | 	int i; | 
 | 4152 |  | 
 | 4153 | 	for (i = 0; i < hw->addr_list_size; i++) { | 
 | 4154 | 		if (!memcmp(hw->address[i], mac_addr, MAC_ADDR_LEN)) { | 
 | 4155 | 			memset(hw->address[i], 0, MAC_ADDR_LEN); | 
 | 4156 | 			writel(0, hw->io + ADD_ADDR_INCR * i + | 
 | 4157 | 				KS_ADD_ADDR_0_HI); | 
 | 4158 | 			return 0; | 
 | 4159 | 		} | 
 | 4160 | 	} | 
 | 4161 | 	return -1; | 
 | 4162 | } | 
 | 4163 |  | 
 | 4164 | /** | 
 | 4165 |  * hw_clr_multicast - clear multicast addresses | 
 | 4166 |  * @hw: 	The hardware instance. | 
 | 4167 |  * | 
 | 4168 |  * This routine removes all multicast addresses set in the hardware. | 
 | 4169 |  */ | 
 | 4170 | static void hw_clr_multicast(struct ksz_hw *hw) | 
 | 4171 | { | 
 | 4172 | 	int i; | 
 | 4173 |  | 
 | 4174 | 	for (i = 0; i < HW_MULTICAST_SIZE; i++) { | 
 | 4175 | 		hw->multi_bits[i] = 0; | 
 | 4176 |  | 
 | 4177 | 		writeb(0, hw->io + KS884X_MULTICAST_0_OFFSET + i); | 
 | 4178 | 	} | 
 | 4179 | } | 
 | 4180 |  | 
 | 4181 | /** | 
 | 4182 |  * hw_set_grp_addr - set multicast addresses | 
 | 4183 |  * @hw: 	The hardware instance. | 
 | 4184 |  * | 
 | 4185 |  * This routine programs multicast addresses for the hardware to accept those | 
 | 4186 |  * addresses. | 
 | 4187 |  */ | 
 | 4188 | static void hw_set_grp_addr(struct ksz_hw *hw) | 
 | 4189 | { | 
 | 4190 | 	int i; | 
 | 4191 | 	int index; | 
 | 4192 | 	int position; | 
 | 4193 | 	int value; | 
 | 4194 |  | 
 | 4195 | 	memset(hw->multi_bits, 0, sizeof(u8) * HW_MULTICAST_SIZE); | 
 | 4196 |  | 
 | 4197 | 	for (i = 0; i < hw->multi_list_size; i++) { | 
 | 4198 | 		position = (ether_crc(6, hw->multi_list[i]) >> 26) & 0x3f; | 
 | 4199 | 		index = position >> 3; | 
 | 4200 | 		value = 1 << (position & 7); | 
 | 4201 | 		hw->multi_bits[index] |= (u8) value; | 
 | 4202 | 	} | 
 | 4203 |  | 
 | 4204 | 	for (i = 0; i < HW_MULTICAST_SIZE; i++) | 
 | 4205 | 		writeb(hw->multi_bits[i], hw->io + KS884X_MULTICAST_0_OFFSET + | 
 | 4206 | 			i); | 
 | 4207 | } | 
 | 4208 |  | 
 | 4209 | /** | 
 | 4210 |  * hw_set_multicast - enable or disable all multicast receiving | 
 | 4211 |  * @hw: 	The hardware instance. | 
 | 4212 |  * @multicast:	To turn on or off the all multicast feature. | 
 | 4213 |  * | 
 | 4214 |  * This routine enables/disables the hardware to accept all multicast packets. | 
 | 4215 |  */ | 
 | 4216 | static void hw_set_multicast(struct ksz_hw *hw, u8 multicast) | 
 | 4217 | { | 
 | 4218 | 	/* Stop receiving for reconfiguration. */ | 
 | 4219 | 	hw_stop_rx(hw); | 
 | 4220 |  | 
 | 4221 | 	if (multicast) | 
 | 4222 | 		hw->rx_cfg |= DMA_RX_ALL_MULTICAST; | 
 | 4223 | 	else | 
 | 4224 | 		hw->rx_cfg &= ~DMA_RX_ALL_MULTICAST; | 
 | 4225 |  | 
 | 4226 | 	if (hw->enabled) | 
 | 4227 | 		hw_start_rx(hw); | 
 | 4228 | } | 
 | 4229 |  | 
 | 4230 | /** | 
 | 4231 |  * hw_set_promiscuous - enable or disable promiscuous receiving | 
 | 4232 |  * @hw: 	The hardware instance. | 
 | 4233 |  * @prom:	To turn on or off the promiscuous feature. | 
 | 4234 |  * | 
 | 4235 |  * This routine enables/disables the hardware to accept all packets. | 
 | 4236 |  */ | 
 | 4237 | static void hw_set_promiscuous(struct ksz_hw *hw, u8 prom) | 
 | 4238 | { | 
 | 4239 | 	/* Stop receiving for reconfiguration. */ | 
 | 4240 | 	hw_stop_rx(hw); | 
 | 4241 |  | 
 | 4242 | 	if (prom) | 
 | 4243 | 		hw->rx_cfg |= DMA_RX_PROMISCUOUS; | 
 | 4244 | 	else | 
 | 4245 | 		hw->rx_cfg &= ~DMA_RX_PROMISCUOUS; | 
 | 4246 |  | 
 | 4247 | 	if (hw->enabled) | 
 | 4248 | 		hw_start_rx(hw); | 
 | 4249 | } | 
 | 4250 |  | 
 | 4251 | /** | 
 | 4252 |  * sw_enable - enable the switch | 
 | 4253 |  * @hw: 	The hardware instance. | 
 | 4254 |  * @enable:	The flag to enable or disable the switch | 
 | 4255 |  * | 
 | 4256 |  * This routine is used to enable/disable the switch in KSZ8842. | 
 | 4257 |  */ | 
 | 4258 | static void sw_enable(struct ksz_hw *hw, int enable) | 
 | 4259 | { | 
 | 4260 | 	int port; | 
 | 4261 |  | 
 | 4262 | 	for (port = 0; port < SWITCH_PORT_NUM; port++) { | 
 | 4263 | 		if (hw->dev_count > 1) { | 
 | 4264 | 			/* Set port-base vlan membership with host port. */ | 
 | 4265 | 			sw_cfg_port_base_vlan(hw, port, | 
 | 4266 | 				HOST_MASK | (1 << port)); | 
 | 4267 | 			port_set_stp_state(hw, port, STP_STATE_DISABLED); | 
 | 4268 | 		} else { | 
 | 4269 | 			sw_cfg_port_base_vlan(hw, port, PORT_MASK); | 
 | 4270 | 			port_set_stp_state(hw, port, STP_STATE_FORWARDING); | 
 | 4271 | 		} | 
 | 4272 | 	} | 
 | 4273 | 	if (hw->dev_count > 1) | 
 | 4274 | 		port_set_stp_state(hw, SWITCH_PORT_NUM, STP_STATE_SIMPLE); | 
 | 4275 | 	else | 
 | 4276 | 		port_set_stp_state(hw, SWITCH_PORT_NUM, STP_STATE_FORWARDING); | 
 | 4277 |  | 
 | 4278 | 	if (enable) | 
 | 4279 | 		enable = KS8842_START; | 
 | 4280 | 	writew(enable, hw->io + KS884X_CHIP_ID_OFFSET); | 
 | 4281 | } | 
 | 4282 |  | 
 | 4283 | /** | 
 | 4284 |  * sw_setup - setup the switch | 
 | 4285 |  * @hw: 	The hardware instance. | 
 | 4286 |  * | 
 | 4287 |  * This routine setup the hardware switch engine for default operation. | 
 | 4288 |  */ | 
 | 4289 | static void sw_setup(struct ksz_hw *hw) | 
 | 4290 | { | 
 | 4291 | 	int port; | 
 | 4292 |  | 
 | 4293 | 	sw_set_global_ctrl(hw); | 
 | 4294 |  | 
 | 4295 | 	/* Enable switch broadcast storm protection at 10% percent rate. */ | 
 | 4296 | 	sw_init_broad_storm(hw); | 
 | 4297 | 	hw_cfg_broad_storm(hw, BROADCAST_STORM_PROTECTION_RATE); | 
 | 4298 | 	for (port = 0; port < SWITCH_PORT_NUM; port++) | 
 | 4299 | 		sw_ena_broad_storm(hw, port); | 
 | 4300 |  | 
 | 4301 | 	sw_init_prio(hw); | 
 | 4302 |  | 
 | 4303 | 	sw_init_mirror(hw); | 
 | 4304 |  | 
 | 4305 | 	sw_init_prio_rate(hw); | 
 | 4306 |  | 
 | 4307 | 	sw_init_vlan(hw); | 
 | 4308 |  | 
 | 4309 | 	if (hw->features & STP_SUPPORT) | 
 | 4310 | 		sw_init_stp(hw); | 
 | 4311 | 	if (!sw_chk(hw, KS8842_SWITCH_CTRL_1_OFFSET, | 
 | 4312 | 			SWITCH_TX_FLOW_CTRL | SWITCH_RX_FLOW_CTRL)) | 
 | 4313 | 		hw->overrides |= PAUSE_FLOW_CTRL; | 
 | 4314 | 	sw_enable(hw, 1); | 
 | 4315 | } | 
 | 4316 |  | 
 | 4317 | /** | 
 | 4318 |  * ksz_start_timer - start kernel timer | 
 | 4319 |  * @info:	Kernel timer information. | 
 | 4320 |  * @time:	The time tick. | 
 | 4321 |  * | 
 | 4322 |  * This routine starts the kernel timer after the specified time tick. | 
 | 4323 |  */ | 
 | 4324 | static void ksz_start_timer(struct ksz_timer_info *info, int time) | 
 | 4325 | { | 
 | 4326 | 	info->cnt = 0; | 
 | 4327 | 	info->timer.expires = jiffies + time; | 
 | 4328 | 	add_timer(&info->timer); | 
 | 4329 |  | 
 | 4330 | 	/* infinity */ | 
 | 4331 | 	info->max = -1; | 
 | 4332 | } | 
 | 4333 |  | 
 | 4334 | /** | 
 | 4335 |  * ksz_stop_timer - stop kernel timer | 
 | 4336 |  * @info:	Kernel timer information. | 
 | 4337 |  * | 
 | 4338 |  * This routine stops the kernel timer. | 
 | 4339 |  */ | 
 | 4340 | static void ksz_stop_timer(struct ksz_timer_info *info) | 
 | 4341 | { | 
 | 4342 | 	if (info->max) { | 
 | 4343 | 		info->max = 0; | 
 | 4344 | 		del_timer_sync(&info->timer); | 
 | 4345 | 	} | 
 | 4346 | } | 
 | 4347 |  | 
 | 4348 | static void ksz_init_timer(struct ksz_timer_info *info, int period, | 
 | 4349 | 	void (*function)(unsigned long), void *data) | 
 | 4350 | { | 
 | 4351 | 	info->max = 0; | 
 | 4352 | 	info->period = period; | 
 | 4353 | 	init_timer(&info->timer); | 
 | 4354 | 	info->timer.function = function; | 
 | 4355 | 	info->timer.data = (unsigned long) data; | 
 | 4356 | } | 
 | 4357 |  | 
 | 4358 | static void ksz_update_timer(struct ksz_timer_info *info) | 
 | 4359 | { | 
 | 4360 | 	++info->cnt; | 
 | 4361 | 	if (info->max > 0) { | 
 | 4362 | 		if (info->cnt < info->max) { | 
 | 4363 | 			info->timer.expires = jiffies + info->period; | 
 | 4364 | 			add_timer(&info->timer); | 
 | 4365 | 		} else | 
 | 4366 | 			info->max = 0; | 
 | 4367 | 	} else if (info->max < 0) { | 
 | 4368 | 		info->timer.expires = jiffies + info->period; | 
 | 4369 | 		add_timer(&info->timer); | 
 | 4370 | 	} | 
 | 4371 | } | 
 | 4372 |  | 
 | 4373 | /** | 
 | 4374 |  * ksz_alloc_soft_desc - allocate software descriptors | 
 | 4375 |  * @desc_info:	Descriptor information structure. | 
 | 4376 |  * @transmit:	Indication that descriptors are for transmit. | 
 | 4377 |  * | 
 | 4378 |  * This local function allocates software descriptors for manipulation in | 
 | 4379 |  * memory. | 
 | 4380 |  * | 
 | 4381 |  * Return 0 if successful. | 
 | 4382 |  */ | 
 | 4383 | static int ksz_alloc_soft_desc(struct ksz_desc_info *desc_info, int transmit) | 
 | 4384 | { | 
 | 4385 | 	desc_info->ring = kmalloc(sizeof(struct ksz_desc) * desc_info->alloc, | 
 | 4386 | 		GFP_KERNEL); | 
 | 4387 | 	if (!desc_info->ring) | 
 | 4388 | 		return 1; | 
 | 4389 | 	memset((void *) desc_info->ring, 0, | 
 | 4390 | 		sizeof(struct ksz_desc) * desc_info->alloc); | 
 | 4391 | 	hw_init_desc(desc_info, transmit); | 
 | 4392 | 	return 0; | 
 | 4393 | } | 
 | 4394 |  | 
 | 4395 | /** | 
 | 4396 |  * ksz_alloc_desc - allocate hardware descriptors | 
 | 4397 |  * @adapter:	Adapter information structure. | 
 | 4398 |  * | 
 | 4399 |  * This local function allocates hardware descriptors for receiving and | 
 | 4400 |  * transmitting. | 
 | 4401 |  * | 
 | 4402 |  * Return 0 if successful. | 
 | 4403 |  */ | 
 | 4404 | static int ksz_alloc_desc(struct dev_info *adapter) | 
 | 4405 | { | 
 | 4406 | 	struct ksz_hw *hw = &adapter->hw; | 
 | 4407 | 	int offset; | 
 | 4408 |  | 
 | 4409 | 	/* Allocate memory for RX & TX descriptors. */ | 
 | 4410 | 	adapter->desc_pool.alloc_size = | 
 | 4411 | 		hw->rx_desc_info.size * hw->rx_desc_info.alloc + | 
 | 4412 | 		hw->tx_desc_info.size * hw->tx_desc_info.alloc + | 
 | 4413 | 		DESC_ALIGNMENT; | 
 | 4414 |  | 
 | 4415 | 	adapter->desc_pool.alloc_virt = | 
 | 4416 | 		pci_alloc_consistent( | 
 | 4417 | 			adapter->pdev, adapter->desc_pool.alloc_size, | 
 | 4418 | 			&adapter->desc_pool.dma_addr); | 
 | 4419 | 	if (adapter->desc_pool.alloc_virt == NULL) { | 
 | 4420 | 		adapter->desc_pool.alloc_size = 0; | 
 | 4421 | 		return 1; | 
 | 4422 | 	} | 
 | 4423 | 	memset(adapter->desc_pool.alloc_virt, 0, adapter->desc_pool.alloc_size); | 
 | 4424 |  | 
 | 4425 | 	/* Align to the next cache line boundary. */ | 
 | 4426 | 	offset = (((ulong) adapter->desc_pool.alloc_virt % DESC_ALIGNMENT) ? | 
 | 4427 | 		(DESC_ALIGNMENT - | 
 | 4428 | 		((ulong) adapter->desc_pool.alloc_virt % DESC_ALIGNMENT)) : 0); | 
 | 4429 | 	adapter->desc_pool.virt = adapter->desc_pool.alloc_virt + offset; | 
 | 4430 | 	adapter->desc_pool.phys = adapter->desc_pool.dma_addr + offset; | 
 | 4431 |  | 
 | 4432 | 	/* Allocate receive/transmit descriptors. */ | 
 | 4433 | 	hw->rx_desc_info.ring_virt = (struct ksz_hw_desc *) | 
 | 4434 | 		adapter->desc_pool.virt; | 
 | 4435 | 	hw->rx_desc_info.ring_phys = adapter->desc_pool.phys; | 
 | 4436 | 	offset = hw->rx_desc_info.alloc * hw->rx_desc_info.size; | 
 | 4437 | 	hw->tx_desc_info.ring_virt = (struct ksz_hw_desc *) | 
 | 4438 | 		(adapter->desc_pool.virt + offset); | 
 | 4439 | 	hw->tx_desc_info.ring_phys = adapter->desc_pool.phys + offset; | 
 | 4440 |  | 
 | 4441 | 	if (ksz_alloc_soft_desc(&hw->rx_desc_info, 0)) | 
 | 4442 | 		return 1; | 
 | 4443 | 	if (ksz_alloc_soft_desc(&hw->tx_desc_info, 1)) | 
 | 4444 | 		return 1; | 
 | 4445 |  | 
 | 4446 | 	return 0; | 
 | 4447 | } | 
 | 4448 |  | 
 | 4449 | /** | 
 | 4450 |  * free_dma_buf - release DMA buffer resources | 
 | 4451 |  * @adapter:	Adapter information structure. | 
 | 4452 |  * | 
 | 4453 |  * This routine is just a helper function to release the DMA buffer resources. | 
 | 4454 |  */ | 
 | 4455 | static void free_dma_buf(struct dev_info *adapter, struct ksz_dma_buf *dma_buf, | 
 | 4456 | 	int direction) | 
 | 4457 | { | 
 | 4458 | 	pci_unmap_single(adapter->pdev, dma_buf->dma, dma_buf->len, direction); | 
 | 4459 | 	dev_kfree_skb(dma_buf->skb); | 
 | 4460 | 	dma_buf->skb = NULL; | 
 | 4461 | 	dma_buf->dma = 0; | 
 | 4462 | } | 
 | 4463 |  | 
 | 4464 | /** | 
 | 4465 |  * ksz_init_rx_buffers - initialize receive descriptors | 
 | 4466 |  * @adapter:	Adapter information structure. | 
 | 4467 |  * | 
 | 4468 |  * This routine initializes DMA buffers for receiving. | 
 | 4469 |  */ | 
 | 4470 | static void ksz_init_rx_buffers(struct dev_info *adapter) | 
 | 4471 | { | 
 | 4472 | 	int i; | 
 | 4473 | 	struct ksz_desc *desc; | 
 | 4474 | 	struct ksz_dma_buf *dma_buf; | 
 | 4475 | 	struct ksz_hw *hw = &adapter->hw; | 
 | 4476 | 	struct ksz_desc_info *info = &hw->rx_desc_info; | 
 | 4477 |  | 
 | 4478 | 	for (i = 0; i < hw->rx_desc_info.alloc; i++) { | 
 | 4479 | 		get_rx_pkt(info, &desc); | 
 | 4480 |  | 
 | 4481 | 		dma_buf = DMA_BUFFER(desc); | 
 | 4482 | 		if (dma_buf->skb && dma_buf->len != adapter->mtu) | 
 | 4483 | 			free_dma_buf(adapter, dma_buf, PCI_DMA_FROMDEVICE); | 
 | 4484 | 		dma_buf->len = adapter->mtu; | 
 | 4485 | 		if (!dma_buf->skb) | 
 | 4486 | 			dma_buf->skb = alloc_skb(dma_buf->len, GFP_ATOMIC); | 
 | 4487 | 		if (dma_buf->skb && !dma_buf->dma) { | 
 | 4488 | 			dma_buf->skb->dev = adapter->dev; | 
 | 4489 | 			dma_buf->dma = pci_map_single( | 
 | 4490 | 				adapter->pdev, | 
 | 4491 | 				skb_tail_pointer(dma_buf->skb), | 
 | 4492 | 				dma_buf->len, | 
 | 4493 | 				PCI_DMA_FROMDEVICE); | 
 | 4494 | 		} | 
 | 4495 |  | 
 | 4496 | 		/* Set descriptor. */ | 
 | 4497 | 		set_rx_buf(desc, dma_buf->dma); | 
 | 4498 | 		set_rx_len(desc, dma_buf->len); | 
 | 4499 | 		release_desc(desc); | 
 | 4500 | 	} | 
 | 4501 | } | 
 | 4502 |  | 
 | 4503 | /** | 
 | 4504 |  * ksz_alloc_mem - allocate memory for hardware descriptors | 
 | 4505 |  * @adapter:	Adapter information structure. | 
 | 4506 |  * | 
 | 4507 |  * This function allocates memory for use by hardware descriptors for receiving | 
 | 4508 |  * and transmitting. | 
 | 4509 |  * | 
 | 4510 |  * Return 0 if successful. | 
 | 4511 |  */ | 
 | 4512 | static int ksz_alloc_mem(struct dev_info *adapter) | 
 | 4513 | { | 
 | 4514 | 	struct ksz_hw *hw = &adapter->hw; | 
 | 4515 |  | 
 | 4516 | 	/* Determine the number of receive and transmit descriptors. */ | 
 | 4517 | 	hw->rx_desc_info.alloc = NUM_OF_RX_DESC; | 
 | 4518 | 	hw->tx_desc_info.alloc = NUM_OF_TX_DESC; | 
 | 4519 |  | 
 | 4520 | 	/* Determine how many descriptors to skip transmit interrupt. */ | 
 | 4521 | 	hw->tx_int_cnt = 0; | 
 | 4522 | 	hw->tx_int_mask = NUM_OF_TX_DESC / 4; | 
 | 4523 | 	if (hw->tx_int_mask > 8) | 
 | 4524 | 		hw->tx_int_mask = 8; | 
 | 4525 | 	while (hw->tx_int_mask) { | 
 | 4526 | 		hw->tx_int_cnt++; | 
 | 4527 | 		hw->tx_int_mask >>= 1; | 
 | 4528 | 	} | 
 | 4529 | 	if (hw->tx_int_cnt) { | 
 | 4530 | 		hw->tx_int_mask = (1 << (hw->tx_int_cnt - 1)) - 1; | 
 | 4531 | 		hw->tx_int_cnt = 0; | 
 | 4532 | 	} | 
 | 4533 |  | 
 | 4534 | 	/* Determine the descriptor size. */ | 
 | 4535 | 	hw->rx_desc_info.size = | 
 | 4536 | 		(((sizeof(struct ksz_hw_desc) + DESC_ALIGNMENT - 1) / | 
 | 4537 | 		DESC_ALIGNMENT) * DESC_ALIGNMENT); | 
 | 4538 | 	hw->tx_desc_info.size = | 
 | 4539 | 		(((sizeof(struct ksz_hw_desc) + DESC_ALIGNMENT - 1) / | 
 | 4540 | 		DESC_ALIGNMENT) * DESC_ALIGNMENT); | 
 | 4541 | 	if (hw->rx_desc_info.size != sizeof(struct ksz_hw_desc)) | 
| Joe Perches | 0dc7d2b | 2010-02-27 14:43:51 +0000 | [diff] [blame] | 4542 | 		pr_alert("Hardware descriptor size not right!\n"); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 4543 | 	ksz_check_desc_num(&hw->rx_desc_info); | 
 | 4544 | 	ksz_check_desc_num(&hw->tx_desc_info); | 
 | 4545 |  | 
 | 4546 | 	/* Allocate descriptors. */ | 
 | 4547 | 	if (ksz_alloc_desc(adapter)) | 
 | 4548 | 		return 1; | 
 | 4549 |  | 
 | 4550 | 	return 0; | 
 | 4551 | } | 
 | 4552 |  | 
 | 4553 | /** | 
 | 4554 |  * ksz_free_desc - free software and hardware descriptors | 
 | 4555 |  * @adapter:	Adapter information structure. | 
 | 4556 |  * | 
 | 4557 |  * This local routine frees the software and hardware descriptors allocated by | 
 | 4558 |  * ksz_alloc_desc(). | 
 | 4559 |  */ | 
 | 4560 | static void ksz_free_desc(struct dev_info *adapter) | 
 | 4561 | { | 
 | 4562 | 	struct ksz_hw *hw = &adapter->hw; | 
 | 4563 |  | 
 | 4564 | 	/* Reset descriptor. */ | 
 | 4565 | 	hw->rx_desc_info.ring_virt = NULL; | 
 | 4566 | 	hw->tx_desc_info.ring_virt = NULL; | 
 | 4567 | 	hw->rx_desc_info.ring_phys = 0; | 
 | 4568 | 	hw->tx_desc_info.ring_phys = 0; | 
 | 4569 |  | 
 | 4570 | 	/* Free memory. */ | 
 | 4571 | 	if (adapter->desc_pool.alloc_virt) | 
 | 4572 | 		pci_free_consistent( | 
 | 4573 | 			adapter->pdev, | 
 | 4574 | 			adapter->desc_pool.alloc_size, | 
 | 4575 | 			adapter->desc_pool.alloc_virt, | 
 | 4576 | 			adapter->desc_pool.dma_addr); | 
 | 4577 |  | 
 | 4578 | 	/* Reset resource pool. */ | 
 | 4579 | 	adapter->desc_pool.alloc_size = 0; | 
 | 4580 | 	adapter->desc_pool.alloc_virt = NULL; | 
 | 4581 |  | 
 | 4582 | 	kfree(hw->rx_desc_info.ring); | 
 | 4583 | 	hw->rx_desc_info.ring = NULL; | 
 | 4584 | 	kfree(hw->tx_desc_info.ring); | 
 | 4585 | 	hw->tx_desc_info.ring = NULL; | 
 | 4586 | } | 
 | 4587 |  | 
 | 4588 | /** | 
 | 4589 |  * ksz_free_buffers - free buffers used in the descriptors | 
 | 4590 |  * @adapter:	Adapter information structure. | 
 | 4591 |  * @desc_info:	Descriptor information structure. | 
 | 4592 |  * | 
 | 4593 |  * This local routine frees buffers used in the DMA buffers. | 
 | 4594 |  */ | 
 | 4595 | static void ksz_free_buffers(struct dev_info *adapter, | 
 | 4596 | 	struct ksz_desc_info *desc_info, int direction) | 
 | 4597 | { | 
 | 4598 | 	int i; | 
 | 4599 | 	struct ksz_dma_buf *dma_buf; | 
 | 4600 | 	struct ksz_desc *desc = desc_info->ring; | 
 | 4601 |  | 
 | 4602 | 	for (i = 0; i < desc_info->alloc; i++) { | 
 | 4603 | 		dma_buf = DMA_BUFFER(desc); | 
 | 4604 | 		if (dma_buf->skb) | 
 | 4605 | 			free_dma_buf(adapter, dma_buf, direction); | 
 | 4606 | 		desc++; | 
 | 4607 | 	} | 
 | 4608 | } | 
 | 4609 |  | 
 | 4610 | /** | 
 | 4611 |  * ksz_free_mem - free all resources used by descriptors | 
 | 4612 |  * @adapter:	Adapter information structure. | 
 | 4613 |  * | 
 | 4614 |  * This local routine frees all the resources allocated by ksz_alloc_mem(). | 
 | 4615 |  */ | 
 | 4616 | static void ksz_free_mem(struct dev_info *adapter) | 
 | 4617 | { | 
 | 4618 | 	/* Free transmit buffers. */ | 
 | 4619 | 	ksz_free_buffers(adapter, &adapter->hw.tx_desc_info, | 
 | 4620 | 		PCI_DMA_TODEVICE); | 
 | 4621 |  | 
 | 4622 | 	/* Free receive buffers. */ | 
 | 4623 | 	ksz_free_buffers(adapter, &adapter->hw.rx_desc_info, | 
 | 4624 | 		PCI_DMA_FROMDEVICE); | 
 | 4625 |  | 
 | 4626 | 	/* Free descriptors. */ | 
 | 4627 | 	ksz_free_desc(adapter); | 
 | 4628 | } | 
 | 4629 |  | 
 | 4630 | static void get_mib_counters(struct ksz_hw *hw, int first, int cnt, | 
 | 4631 | 	u64 *counter) | 
 | 4632 | { | 
 | 4633 | 	int i; | 
 | 4634 | 	int mib; | 
 | 4635 | 	int port; | 
 | 4636 | 	struct ksz_port_mib *port_mib; | 
 | 4637 |  | 
 | 4638 | 	memset(counter, 0, sizeof(u64) * TOTAL_PORT_COUNTER_NUM); | 
 | 4639 | 	for (i = 0, port = first; i < cnt; i++, port++) { | 
 | 4640 | 		port_mib = &hw->port_mib[port]; | 
 | 4641 | 		for (mib = port_mib->mib_start; mib < hw->mib_cnt; mib++) | 
 | 4642 | 			counter[mib] += port_mib->counter[mib]; | 
 | 4643 | 	} | 
 | 4644 | } | 
 | 4645 |  | 
 | 4646 | /** | 
 | 4647 |  * send_packet - send packet | 
 | 4648 |  * @skb:	Socket buffer. | 
 | 4649 |  * @dev:	Network device. | 
 | 4650 |  * | 
 | 4651 |  * This routine is used to send a packet out to the network. | 
 | 4652 |  */ | 
 | 4653 | static void send_packet(struct sk_buff *skb, struct net_device *dev) | 
 | 4654 | { | 
 | 4655 | 	struct ksz_desc *desc; | 
 | 4656 | 	struct ksz_desc *first; | 
 | 4657 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 4658 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 4659 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 4660 | 	struct ksz_desc_info *info = &hw->tx_desc_info; | 
 | 4661 | 	struct ksz_dma_buf *dma_buf; | 
 | 4662 | 	int len; | 
 | 4663 | 	int last_frag = skb_shinfo(skb)->nr_frags; | 
 | 4664 |  | 
 | 4665 | 	/* | 
 | 4666 | 	 * KSZ8842 with multiple device interfaces needs to be told which port | 
 | 4667 | 	 * to send. | 
 | 4668 | 	 */ | 
 | 4669 | 	if (hw->dev_count > 1) | 
 | 4670 | 		hw->dst_ports = 1 << priv->port.first_port; | 
 | 4671 |  | 
 | 4672 | 	/* Hardware will pad the length to 60. */ | 
 | 4673 | 	len = skb->len; | 
 | 4674 |  | 
 | 4675 | 	/* Remember the very first descriptor. */ | 
 | 4676 | 	first = info->cur; | 
 | 4677 | 	desc = first; | 
 | 4678 |  | 
 | 4679 | 	dma_buf = DMA_BUFFER(desc); | 
 | 4680 | 	if (last_frag) { | 
 | 4681 | 		int frag; | 
 | 4682 | 		skb_frag_t *this_frag; | 
 | 4683 |  | 
| Eric Dumazet | e743d31 | 2010-04-14 15:59:40 -0700 | [diff] [blame] | 4684 | 		dma_buf->len = skb_headlen(skb); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 4685 |  | 
 | 4686 | 		dma_buf->dma = pci_map_single( | 
 | 4687 | 			hw_priv->pdev, skb->data, dma_buf->len, | 
 | 4688 | 			PCI_DMA_TODEVICE); | 
 | 4689 | 		set_tx_buf(desc, dma_buf->dma); | 
 | 4690 | 		set_tx_len(desc, dma_buf->len); | 
 | 4691 |  | 
 | 4692 | 		frag = 0; | 
 | 4693 | 		do { | 
 | 4694 | 			this_frag = &skb_shinfo(skb)->frags[frag]; | 
 | 4695 |  | 
 | 4696 | 			/* Get a new descriptor. */ | 
 | 4697 | 			get_tx_pkt(info, &desc); | 
 | 4698 |  | 
 | 4699 | 			/* Keep track of descriptors used so far. */ | 
 | 4700 | 			++hw->tx_int_cnt; | 
 | 4701 |  | 
 | 4702 | 			dma_buf = DMA_BUFFER(desc); | 
| Eric Dumazet | 9e903e0 | 2011-10-18 21:00:24 +0000 | [diff] [blame] | 4703 | 			dma_buf->len = skb_frag_size(this_frag); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 4704 |  | 
 | 4705 | 			dma_buf->dma = pci_map_single( | 
 | 4706 | 				hw_priv->pdev, | 
| Ian Campbell | 787343a | 2011-08-31 00:46:55 +0000 | [diff] [blame] | 4707 | 				skb_frag_address(this_frag), | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 4708 | 				dma_buf->len, | 
 | 4709 | 				PCI_DMA_TODEVICE); | 
 | 4710 | 			set_tx_buf(desc, dma_buf->dma); | 
 | 4711 | 			set_tx_len(desc, dma_buf->len); | 
 | 4712 |  | 
 | 4713 | 			frag++; | 
 | 4714 | 			if (frag == last_frag) | 
 | 4715 | 				break; | 
 | 4716 |  | 
 | 4717 | 			/* Do not release the last descriptor here. */ | 
 | 4718 | 			release_desc(desc); | 
 | 4719 | 		} while (1); | 
 | 4720 |  | 
 | 4721 | 		/* current points to the last descriptor. */ | 
 | 4722 | 		info->cur = desc; | 
 | 4723 |  | 
 | 4724 | 		/* Release the first descriptor. */ | 
 | 4725 | 		release_desc(first); | 
 | 4726 | 	} else { | 
 | 4727 | 		dma_buf->len = len; | 
 | 4728 |  | 
 | 4729 | 		dma_buf->dma = pci_map_single( | 
 | 4730 | 			hw_priv->pdev, skb->data, dma_buf->len, | 
 | 4731 | 			PCI_DMA_TODEVICE); | 
 | 4732 | 		set_tx_buf(desc, dma_buf->dma); | 
 | 4733 | 		set_tx_len(desc, dma_buf->len); | 
 | 4734 | 	} | 
 | 4735 |  | 
 | 4736 | 	if (skb->ip_summed == CHECKSUM_PARTIAL) { | 
 | 4737 | 		(desc)->sw.buf.tx.csum_gen_tcp = 1; | 
 | 4738 | 		(desc)->sw.buf.tx.csum_gen_udp = 1; | 
 | 4739 | 	} | 
 | 4740 |  | 
 | 4741 | 	/* | 
 | 4742 | 	 * The last descriptor holds the packet so that it can be returned to | 
 | 4743 | 	 * network subsystem after all descriptors are transmitted. | 
 | 4744 | 	 */ | 
 | 4745 | 	dma_buf->skb = skb; | 
 | 4746 |  | 
 | 4747 | 	hw_send_pkt(hw); | 
 | 4748 |  | 
 | 4749 | 	/* Update transmit statistics. */ | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 4750 | 	dev->stats.tx_packets++; | 
 | 4751 | 	dev->stats.tx_bytes += len; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 4752 | } | 
 | 4753 |  | 
 | 4754 | /** | 
 | 4755 |  * transmit_cleanup - clean up transmit descriptors | 
 | 4756 |  * @dev:	Network device. | 
 | 4757 |  * | 
 | 4758 |  * This routine is called to clean up the transmitted buffers. | 
 | 4759 |  */ | 
 | 4760 | static void transmit_cleanup(struct dev_info *hw_priv, int normal) | 
 | 4761 | { | 
 | 4762 | 	int last; | 
 | 4763 | 	union desc_stat status; | 
 | 4764 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 4765 | 	struct ksz_desc_info *info = &hw->tx_desc_info; | 
 | 4766 | 	struct ksz_desc *desc; | 
 | 4767 | 	struct ksz_dma_buf *dma_buf; | 
 | 4768 | 	struct net_device *dev = NULL; | 
 | 4769 |  | 
 | 4770 | 	spin_lock(&hw_priv->hwlock); | 
 | 4771 | 	last = info->last; | 
 | 4772 |  | 
 | 4773 | 	while (info->avail < info->alloc) { | 
 | 4774 | 		/* Get next descriptor which is not hardware owned. */ | 
 | 4775 | 		desc = &info->ring[last]; | 
 | 4776 | 		status.data = le32_to_cpu(desc->phw->ctrl.data); | 
 | 4777 | 		if (status.tx.hw_owned) { | 
 | 4778 | 			if (normal) | 
 | 4779 | 				break; | 
 | 4780 | 			else | 
 | 4781 | 				reset_desc(desc, status); | 
 | 4782 | 		} | 
 | 4783 |  | 
 | 4784 | 		dma_buf = DMA_BUFFER(desc); | 
 | 4785 | 		pci_unmap_single( | 
 | 4786 | 			hw_priv->pdev, dma_buf->dma, dma_buf->len, | 
 | 4787 | 			PCI_DMA_TODEVICE); | 
 | 4788 |  | 
 | 4789 | 		/* This descriptor contains the last buffer in the packet. */ | 
 | 4790 | 		if (dma_buf->skb) { | 
 | 4791 | 			dev = dma_buf->skb->dev; | 
 | 4792 |  | 
 | 4793 | 			/* Release the packet back to network subsystem. */ | 
 | 4794 | 			dev_kfree_skb_irq(dma_buf->skb); | 
 | 4795 | 			dma_buf->skb = NULL; | 
 | 4796 | 		} | 
 | 4797 |  | 
 | 4798 | 		/* Free the transmitted descriptor. */ | 
 | 4799 | 		last++; | 
 | 4800 | 		last &= info->mask; | 
 | 4801 | 		info->avail++; | 
 | 4802 | 	} | 
 | 4803 | 	info->last = last; | 
 | 4804 | 	spin_unlock(&hw_priv->hwlock); | 
 | 4805 |  | 
 | 4806 | 	/* Notify the network subsystem that the packet has been sent. */ | 
 | 4807 | 	if (dev) | 
 | 4808 | 		dev->trans_start = jiffies; | 
 | 4809 | } | 
 | 4810 |  | 
 | 4811 | /** | 
 | 4812 |  * transmit_done - transmit done processing | 
 | 4813 |  * @dev:	Network device. | 
 | 4814 |  * | 
 | 4815 |  * This routine is called when the transmit interrupt is triggered, indicating | 
 | 4816 |  * either a packet is sent successfully or there are transmit errors. | 
 | 4817 |  */ | 
 | 4818 | static void tx_done(struct dev_info *hw_priv) | 
 | 4819 | { | 
 | 4820 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 4821 | 	int port; | 
 | 4822 |  | 
 | 4823 | 	transmit_cleanup(hw_priv, 1); | 
 | 4824 |  | 
 | 4825 | 	for (port = 0; port < hw->dev_count; port++) { | 
 | 4826 | 		struct net_device *dev = hw->port_info[port].pdev; | 
 | 4827 |  | 
 | 4828 | 		if (netif_running(dev) && netif_queue_stopped(dev)) | 
 | 4829 | 			netif_wake_queue(dev); | 
 | 4830 | 	} | 
 | 4831 | } | 
 | 4832 |  | 
 | 4833 | static inline void copy_old_skb(struct sk_buff *old, struct sk_buff *skb) | 
 | 4834 | { | 
 | 4835 | 	skb->dev = old->dev; | 
 | 4836 | 	skb->protocol = old->protocol; | 
 | 4837 | 	skb->ip_summed = old->ip_summed; | 
 | 4838 | 	skb->csum = old->csum; | 
 | 4839 | 	skb_set_network_header(skb, ETH_HLEN); | 
 | 4840 |  | 
 | 4841 | 	dev_kfree_skb(old); | 
 | 4842 | } | 
 | 4843 |  | 
 | 4844 | /** | 
 | 4845 |  * netdev_tx - send out packet | 
 | 4846 |  * @skb:	Socket buffer. | 
 | 4847 |  * @dev:	Network device. | 
 | 4848 |  * | 
 | 4849 |  * This function is used by the upper network layer to send out a packet. | 
 | 4850 |  * | 
 | 4851 |  * Return 0 if successful; otherwise an error code indicating failure. | 
 | 4852 |  */ | 
| Denis Kirjanov | 5ed8366 | 2010-05-31 00:24:49 +0000 | [diff] [blame] | 4853 | static netdev_tx_t netdev_tx(struct sk_buff *skb, struct net_device *dev) | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 4854 | { | 
 | 4855 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 4856 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 4857 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 4858 | 	int left; | 
 | 4859 | 	int num = 1; | 
 | 4860 | 	int rc = 0; | 
 | 4861 |  | 
 | 4862 | 	if (hw->features & SMALL_PACKET_TX_BUG) { | 
 | 4863 | 		struct sk_buff *org_skb = skb; | 
 | 4864 |  | 
 | 4865 | 		if (skb->len <= 48) { | 
 | 4866 | 			if (skb_end_pointer(skb) - skb->data >= 50) { | 
 | 4867 | 				memset(&skb->data[skb->len], 0, 50 - skb->len); | 
 | 4868 | 				skb->len = 50; | 
 | 4869 | 			} else { | 
 | 4870 | 				skb = dev_alloc_skb(50); | 
 | 4871 | 				if (!skb) | 
 | 4872 | 					return NETDEV_TX_BUSY; | 
 | 4873 | 				memcpy(skb->data, org_skb->data, org_skb->len); | 
 | 4874 | 				memset(&skb->data[org_skb->len], 0, | 
 | 4875 | 					50 - org_skb->len); | 
 | 4876 | 				skb->len = 50; | 
 | 4877 | 				copy_old_skb(org_skb, skb); | 
 | 4878 | 			} | 
 | 4879 | 		} | 
 | 4880 | 	} | 
 | 4881 |  | 
 | 4882 | 	spin_lock_irq(&hw_priv->hwlock); | 
 | 4883 |  | 
 | 4884 | 	num = skb_shinfo(skb)->nr_frags + 1; | 
 | 4885 | 	left = hw_alloc_pkt(hw, skb->len, num); | 
 | 4886 | 	if (left) { | 
 | 4887 | 		if (left < num || | 
| Michał Mirosław | e6a4641 | 2011-04-10 03:13:21 +0000 | [diff] [blame] | 4888 | 				((CHECKSUM_PARTIAL == skb->ip_summed) && | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 4889 | 				(ETH_P_IPV6 == htons(skb->protocol)))) { | 
 | 4890 | 			struct sk_buff *org_skb = skb; | 
 | 4891 |  | 
 | 4892 | 			skb = dev_alloc_skb(org_skb->len); | 
| Jiri Slaby | edee393 | 2010-03-16 04:53:50 +0000 | [diff] [blame] | 4893 | 			if (!skb) { | 
 | 4894 | 				rc = NETDEV_TX_BUSY; | 
 | 4895 | 				goto unlock; | 
 | 4896 | 			} | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 4897 | 			skb_copy_and_csum_dev(org_skb, skb->data); | 
| Cesar Eduardo Barros | 3e49e6d | 2011-03-26 05:10:30 +0000 | [diff] [blame] | 4898 | 			org_skb->ip_summed = CHECKSUM_NONE; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 4899 | 			skb->len = org_skb->len; | 
 | 4900 | 			copy_old_skb(org_skb, skb); | 
 | 4901 | 		} | 
 | 4902 | 		send_packet(skb, dev); | 
 | 4903 | 		if (left <= num) | 
 | 4904 | 			netif_stop_queue(dev); | 
 | 4905 | 	} else { | 
 | 4906 | 		/* Stop the transmit queue until packet is allocated. */ | 
 | 4907 | 		netif_stop_queue(dev); | 
 | 4908 | 		rc = NETDEV_TX_BUSY; | 
 | 4909 | 	} | 
| Jiri Slaby | edee393 | 2010-03-16 04:53:50 +0000 | [diff] [blame] | 4910 | unlock: | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 4911 | 	spin_unlock_irq(&hw_priv->hwlock); | 
 | 4912 |  | 
 | 4913 | 	return rc; | 
 | 4914 | } | 
 | 4915 |  | 
 | 4916 | /** | 
 | 4917 |  * netdev_tx_timeout - transmit timeout processing | 
 | 4918 |  * @dev:	Network device. | 
 | 4919 |  * | 
 | 4920 |  * This routine is called when the transmit timer expires.  That indicates the | 
 | 4921 |  * hardware is not running correctly because transmit interrupts are not | 
 | 4922 |  * triggered to free up resources so that the transmit routine can continue | 
 | 4923 |  * sending out packets.  The hardware is reset to correct the problem. | 
 | 4924 |  */ | 
 | 4925 | static void netdev_tx_timeout(struct net_device *dev) | 
 | 4926 | { | 
 | 4927 | 	static unsigned long last_reset; | 
 | 4928 |  | 
 | 4929 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 4930 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 4931 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 4932 | 	int port; | 
 | 4933 |  | 
 | 4934 | 	if (hw->dev_count > 1) { | 
 | 4935 | 		/* | 
 | 4936 | 		 * Only reset the hardware if time between calls is long | 
 | 4937 | 		 * enough. | 
 | 4938 | 		 */ | 
 | 4939 | 		if (jiffies - last_reset <= dev->watchdog_timeo) | 
 | 4940 | 			hw_priv = NULL; | 
 | 4941 | 	} | 
 | 4942 |  | 
 | 4943 | 	last_reset = jiffies; | 
 | 4944 | 	if (hw_priv) { | 
 | 4945 | 		hw_dis_intr(hw); | 
 | 4946 | 		hw_disable(hw); | 
 | 4947 |  | 
 | 4948 | 		transmit_cleanup(hw_priv, 0); | 
 | 4949 | 		hw_reset_pkts(&hw->rx_desc_info); | 
 | 4950 | 		hw_reset_pkts(&hw->tx_desc_info); | 
 | 4951 | 		ksz_init_rx_buffers(hw_priv); | 
 | 4952 |  | 
 | 4953 | 		hw_reset(hw); | 
 | 4954 |  | 
 | 4955 | 		hw_set_desc_base(hw, | 
 | 4956 | 			hw->tx_desc_info.ring_phys, | 
 | 4957 | 			hw->rx_desc_info.ring_phys); | 
 | 4958 | 		hw_set_addr(hw); | 
 | 4959 | 		if (hw->all_multi) | 
 | 4960 | 			hw_set_multicast(hw, hw->all_multi); | 
 | 4961 | 		else if (hw->multi_list_size) | 
 | 4962 | 			hw_set_grp_addr(hw); | 
 | 4963 |  | 
 | 4964 | 		if (hw->dev_count > 1) { | 
 | 4965 | 			hw_set_add_addr(hw); | 
 | 4966 | 			for (port = 0; port < SWITCH_PORT_NUM; port++) { | 
 | 4967 | 				struct net_device *port_dev; | 
 | 4968 |  | 
 | 4969 | 				port_set_stp_state(hw, port, | 
 | 4970 | 					STP_STATE_DISABLED); | 
 | 4971 |  | 
 | 4972 | 				port_dev = hw->port_info[port].pdev; | 
 | 4973 | 				if (netif_running(port_dev)) | 
 | 4974 | 					port_set_stp_state(hw, port, | 
 | 4975 | 						STP_STATE_SIMPLE); | 
 | 4976 | 			} | 
 | 4977 | 		} | 
 | 4978 |  | 
 | 4979 | 		hw_enable(hw); | 
 | 4980 | 		hw_ena_intr(hw); | 
 | 4981 | 	} | 
 | 4982 |  | 
 | 4983 | 	dev->trans_start = jiffies; | 
 | 4984 | 	netif_wake_queue(dev); | 
 | 4985 | } | 
 | 4986 |  | 
 | 4987 | static inline void csum_verified(struct sk_buff *skb) | 
 | 4988 | { | 
 | 4989 | 	unsigned short protocol; | 
 | 4990 | 	struct iphdr *iph; | 
 | 4991 |  | 
 | 4992 | 	protocol = skb->protocol; | 
 | 4993 | 	skb_reset_network_header(skb); | 
 | 4994 | 	iph = (struct iphdr *) skb_network_header(skb); | 
 | 4995 | 	if (protocol == htons(ETH_P_8021Q)) { | 
 | 4996 | 		protocol = iph->tot_len; | 
 | 4997 | 		skb_set_network_header(skb, VLAN_HLEN); | 
 | 4998 | 		iph = (struct iphdr *) skb_network_header(skb); | 
 | 4999 | 	} | 
 | 5000 | 	if (protocol == htons(ETH_P_IP)) { | 
 | 5001 | 		if (iph->protocol == IPPROTO_TCP) | 
 | 5002 | 			skb->ip_summed = CHECKSUM_UNNECESSARY; | 
 | 5003 | 	} | 
 | 5004 | } | 
 | 5005 |  | 
 | 5006 | static inline int rx_proc(struct net_device *dev, struct ksz_hw* hw, | 
 | 5007 | 	struct ksz_desc *desc, union desc_stat status) | 
 | 5008 | { | 
 | 5009 | 	int packet_len; | 
 | 5010 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5011 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 5012 | 	struct ksz_dma_buf *dma_buf; | 
 | 5013 | 	struct sk_buff *skb; | 
 | 5014 | 	int rx_status; | 
 | 5015 |  | 
 | 5016 | 	/* Received length includes 4-byte CRC. */ | 
 | 5017 | 	packet_len = status.rx.frame_len - 4; | 
 | 5018 |  | 
 | 5019 | 	dma_buf = DMA_BUFFER(desc); | 
 | 5020 | 	pci_dma_sync_single_for_cpu( | 
 | 5021 | 		hw_priv->pdev, dma_buf->dma, packet_len + 4, | 
 | 5022 | 		PCI_DMA_FROMDEVICE); | 
 | 5023 |  | 
 | 5024 | 	do { | 
 | 5025 | 		/* skb->data != skb->head */ | 
 | 5026 | 		skb = dev_alloc_skb(packet_len + 2); | 
 | 5027 | 		if (!skb) { | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5028 | 			dev->stats.rx_dropped++; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5029 | 			return -ENOMEM; | 
 | 5030 | 		} | 
 | 5031 |  | 
 | 5032 | 		/* | 
 | 5033 | 		 * Align socket buffer in 4-byte boundary for better | 
 | 5034 | 		 * performance. | 
 | 5035 | 		 */ | 
 | 5036 | 		skb_reserve(skb, 2); | 
 | 5037 |  | 
 | 5038 | 		memcpy(skb_put(skb, packet_len), | 
 | 5039 | 			dma_buf->skb->data, packet_len); | 
 | 5040 | 	} while (0); | 
 | 5041 |  | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5042 | 	skb->protocol = eth_type_trans(skb, dev); | 
 | 5043 |  | 
 | 5044 | 	if (hw->rx_cfg & (DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP)) | 
 | 5045 | 		csum_verified(skb); | 
 | 5046 |  | 
 | 5047 | 	/* Update receive statistics. */ | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5048 | 	dev->stats.rx_packets++; | 
 | 5049 | 	dev->stats.rx_bytes += packet_len; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5050 |  | 
 | 5051 | 	/* Notify upper layer for received packet. */ | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5052 | 	rx_status = netif_rx(skb); | 
 | 5053 |  | 
 | 5054 | 	return 0; | 
 | 5055 | } | 
 | 5056 |  | 
 | 5057 | static int dev_rcv_packets(struct dev_info *hw_priv) | 
 | 5058 | { | 
 | 5059 | 	int next; | 
 | 5060 | 	union desc_stat status; | 
 | 5061 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 5062 | 	struct net_device *dev = hw->port_info[0].pdev; | 
 | 5063 | 	struct ksz_desc_info *info = &hw->rx_desc_info; | 
 | 5064 | 	int left = info->alloc; | 
 | 5065 | 	struct ksz_desc *desc; | 
 | 5066 | 	int received = 0; | 
 | 5067 |  | 
 | 5068 | 	next = info->next; | 
 | 5069 | 	while (left--) { | 
 | 5070 | 		/* Get next descriptor which is not hardware owned. */ | 
 | 5071 | 		desc = &info->ring[next]; | 
 | 5072 | 		status.data = le32_to_cpu(desc->phw->ctrl.data); | 
 | 5073 | 		if (status.rx.hw_owned) | 
 | 5074 | 			break; | 
 | 5075 |  | 
 | 5076 | 		/* Status valid only when last descriptor bit is set. */ | 
 | 5077 | 		if (status.rx.last_desc && status.rx.first_desc) { | 
 | 5078 | 			if (rx_proc(dev, hw, desc, status)) | 
 | 5079 | 				goto release_packet; | 
 | 5080 | 			received++; | 
 | 5081 | 		} | 
 | 5082 |  | 
 | 5083 | release_packet: | 
 | 5084 | 		release_desc(desc); | 
 | 5085 | 		next++; | 
 | 5086 | 		next &= info->mask; | 
 | 5087 | 	} | 
 | 5088 | 	info->next = next; | 
 | 5089 |  | 
 | 5090 | 	return received; | 
 | 5091 | } | 
 | 5092 |  | 
 | 5093 | static int port_rcv_packets(struct dev_info *hw_priv) | 
 | 5094 | { | 
 | 5095 | 	int next; | 
 | 5096 | 	union desc_stat status; | 
 | 5097 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 5098 | 	struct net_device *dev = hw->port_info[0].pdev; | 
 | 5099 | 	struct ksz_desc_info *info = &hw->rx_desc_info; | 
 | 5100 | 	int left = info->alloc; | 
 | 5101 | 	struct ksz_desc *desc; | 
 | 5102 | 	int received = 0; | 
 | 5103 |  | 
 | 5104 | 	next = info->next; | 
 | 5105 | 	while (left--) { | 
 | 5106 | 		/* Get next descriptor which is not hardware owned. */ | 
 | 5107 | 		desc = &info->ring[next]; | 
 | 5108 | 		status.data = le32_to_cpu(desc->phw->ctrl.data); | 
 | 5109 | 		if (status.rx.hw_owned) | 
 | 5110 | 			break; | 
 | 5111 |  | 
 | 5112 | 		if (hw->dev_count > 1) { | 
 | 5113 | 			/* Get received port number. */ | 
 | 5114 | 			int p = HW_TO_DEV_PORT(status.rx.src_port); | 
 | 5115 |  | 
 | 5116 | 			dev = hw->port_info[p].pdev; | 
 | 5117 | 			if (!netif_running(dev)) | 
 | 5118 | 				goto release_packet; | 
 | 5119 | 		} | 
 | 5120 |  | 
 | 5121 | 		/* Status valid only when last descriptor bit is set. */ | 
 | 5122 | 		if (status.rx.last_desc && status.rx.first_desc) { | 
 | 5123 | 			if (rx_proc(dev, hw, desc, status)) | 
 | 5124 | 				goto release_packet; | 
 | 5125 | 			received++; | 
 | 5126 | 		} | 
 | 5127 |  | 
 | 5128 | release_packet: | 
 | 5129 | 		release_desc(desc); | 
 | 5130 | 		next++; | 
 | 5131 | 		next &= info->mask; | 
 | 5132 | 	} | 
 | 5133 | 	info->next = next; | 
 | 5134 |  | 
 | 5135 | 	return received; | 
 | 5136 | } | 
 | 5137 |  | 
 | 5138 | static int dev_rcv_special(struct dev_info *hw_priv) | 
 | 5139 | { | 
 | 5140 | 	int next; | 
 | 5141 | 	union desc_stat status; | 
 | 5142 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 5143 | 	struct net_device *dev = hw->port_info[0].pdev; | 
 | 5144 | 	struct ksz_desc_info *info = &hw->rx_desc_info; | 
 | 5145 | 	int left = info->alloc; | 
 | 5146 | 	struct ksz_desc *desc; | 
 | 5147 | 	int received = 0; | 
 | 5148 |  | 
 | 5149 | 	next = info->next; | 
 | 5150 | 	while (left--) { | 
 | 5151 | 		/* Get next descriptor which is not hardware owned. */ | 
 | 5152 | 		desc = &info->ring[next]; | 
 | 5153 | 		status.data = le32_to_cpu(desc->phw->ctrl.data); | 
 | 5154 | 		if (status.rx.hw_owned) | 
 | 5155 | 			break; | 
 | 5156 |  | 
 | 5157 | 		if (hw->dev_count > 1) { | 
 | 5158 | 			/* Get received port number. */ | 
 | 5159 | 			int p = HW_TO_DEV_PORT(status.rx.src_port); | 
 | 5160 |  | 
 | 5161 | 			dev = hw->port_info[p].pdev; | 
 | 5162 | 			if (!netif_running(dev)) | 
 | 5163 | 				goto release_packet; | 
 | 5164 | 		} | 
 | 5165 |  | 
 | 5166 | 		/* Status valid only when last descriptor bit is set. */ | 
 | 5167 | 		if (status.rx.last_desc && status.rx.first_desc) { | 
 | 5168 | 			/* | 
 | 5169 | 			 * Receive without error.  With receive errors | 
 | 5170 | 			 * disabled, packets with receive errors will be | 
 | 5171 | 			 * dropped, so no need to check the error bit. | 
 | 5172 | 			 */ | 
 | 5173 | 			if (!status.rx.error || (status.data & | 
 | 5174 | 					KS_DESC_RX_ERROR_COND) == | 
 | 5175 | 					KS_DESC_RX_ERROR_TOO_LONG) { | 
 | 5176 | 				if (rx_proc(dev, hw, desc, status)) | 
 | 5177 | 					goto release_packet; | 
 | 5178 | 				received++; | 
 | 5179 | 			} else { | 
 | 5180 | 				struct dev_priv *priv = netdev_priv(dev); | 
 | 5181 |  | 
 | 5182 | 				/* Update receive error statistics. */ | 
 | 5183 | 				priv->port.counter[OID_COUNTER_RCV_ERROR]++; | 
 | 5184 | 			} | 
 | 5185 | 		} | 
 | 5186 |  | 
 | 5187 | release_packet: | 
 | 5188 | 		release_desc(desc); | 
 | 5189 | 		next++; | 
 | 5190 | 		next &= info->mask; | 
 | 5191 | 	} | 
 | 5192 | 	info->next = next; | 
 | 5193 |  | 
 | 5194 | 	return received; | 
 | 5195 | } | 
 | 5196 |  | 
 | 5197 | static void rx_proc_task(unsigned long data) | 
 | 5198 | { | 
 | 5199 | 	struct dev_info *hw_priv = (struct dev_info *) data; | 
 | 5200 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 5201 |  | 
 | 5202 | 	if (!hw->enabled) | 
 | 5203 | 		return; | 
 | 5204 | 	if (unlikely(!hw_priv->dev_rcv(hw_priv))) { | 
 | 5205 |  | 
 | 5206 | 		/* In case receive process is suspended because of overrun. */ | 
 | 5207 | 		hw_resume_rx(hw); | 
 | 5208 |  | 
 | 5209 | 		/* tasklets are interruptible. */ | 
 | 5210 | 		spin_lock_irq(&hw_priv->hwlock); | 
 | 5211 | 		hw_turn_on_intr(hw, KS884X_INT_RX_MASK); | 
 | 5212 | 		spin_unlock_irq(&hw_priv->hwlock); | 
 | 5213 | 	} else { | 
 | 5214 | 		hw_ack_intr(hw, KS884X_INT_RX); | 
 | 5215 | 		tasklet_schedule(&hw_priv->rx_tasklet); | 
 | 5216 | 	} | 
 | 5217 | } | 
 | 5218 |  | 
 | 5219 | static void tx_proc_task(unsigned long data) | 
 | 5220 | { | 
 | 5221 | 	struct dev_info *hw_priv = (struct dev_info *) data; | 
 | 5222 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 5223 |  | 
 | 5224 | 	hw_ack_intr(hw, KS884X_INT_TX_MASK); | 
 | 5225 |  | 
 | 5226 | 	tx_done(hw_priv); | 
 | 5227 |  | 
 | 5228 | 	/* tasklets are interruptible. */ | 
 | 5229 | 	spin_lock_irq(&hw_priv->hwlock); | 
 | 5230 | 	hw_turn_on_intr(hw, KS884X_INT_TX); | 
 | 5231 | 	spin_unlock_irq(&hw_priv->hwlock); | 
 | 5232 | } | 
 | 5233 |  | 
 | 5234 | static inline void handle_rx_stop(struct ksz_hw *hw) | 
 | 5235 | { | 
 | 5236 | 	/* Receive just has been stopped. */ | 
 | 5237 | 	if (0 == hw->rx_stop) | 
 | 5238 | 		hw->intr_mask &= ~KS884X_INT_RX_STOPPED; | 
 | 5239 | 	else if (hw->rx_stop > 1) { | 
 | 5240 | 		if (hw->enabled && (hw->rx_cfg & DMA_RX_ENABLE)) { | 
 | 5241 | 			hw_start_rx(hw); | 
 | 5242 | 		} else { | 
 | 5243 | 			hw->intr_mask &= ~KS884X_INT_RX_STOPPED; | 
 | 5244 | 			hw->rx_stop = 0; | 
 | 5245 | 		} | 
 | 5246 | 	} else | 
 | 5247 | 		/* Receive just has been started. */ | 
 | 5248 | 		hw->rx_stop++; | 
 | 5249 | } | 
 | 5250 |  | 
 | 5251 | /** | 
 | 5252 |  * netdev_intr - interrupt handling | 
 | 5253 |  * @irq:	Interrupt number. | 
 | 5254 |  * @dev_id:	Network device. | 
 | 5255 |  * | 
 | 5256 |  * This function is called by upper network layer to signal interrupt. | 
 | 5257 |  * | 
 | 5258 |  * Return IRQ_HANDLED if interrupt is handled. | 
 | 5259 |  */ | 
 | 5260 | static irqreturn_t netdev_intr(int irq, void *dev_id) | 
 | 5261 | { | 
 | 5262 | 	uint int_enable = 0; | 
 | 5263 | 	struct net_device *dev = (struct net_device *) dev_id; | 
 | 5264 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5265 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 5266 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 5267 |  | 
 | 5268 | 	hw_read_intr(hw, &int_enable); | 
 | 5269 |  | 
 | 5270 | 	/* Not our interrupt! */ | 
 | 5271 | 	if (!int_enable) | 
 | 5272 | 		return IRQ_NONE; | 
 | 5273 |  | 
 | 5274 | 	do { | 
 | 5275 | 		hw_ack_intr(hw, int_enable); | 
 | 5276 | 		int_enable &= hw->intr_mask; | 
 | 5277 |  | 
 | 5278 | 		if (unlikely(int_enable & KS884X_INT_TX_MASK)) { | 
 | 5279 | 			hw_dis_intr_bit(hw, KS884X_INT_TX_MASK); | 
 | 5280 | 			tasklet_schedule(&hw_priv->tx_tasklet); | 
 | 5281 | 		} | 
 | 5282 |  | 
 | 5283 | 		if (likely(int_enable & KS884X_INT_RX)) { | 
 | 5284 | 			hw_dis_intr_bit(hw, KS884X_INT_RX); | 
 | 5285 | 			tasklet_schedule(&hw_priv->rx_tasklet); | 
 | 5286 | 		} | 
 | 5287 |  | 
 | 5288 | 		if (unlikely(int_enable & KS884X_INT_RX_OVERRUN)) { | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5289 | 			dev->stats.rx_fifo_errors++; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5290 | 			hw_resume_rx(hw); | 
 | 5291 | 		} | 
 | 5292 |  | 
 | 5293 | 		if (unlikely(int_enable & KS884X_INT_PHY)) { | 
 | 5294 | 			struct ksz_port *port = &priv->port; | 
 | 5295 |  | 
 | 5296 | 			hw->features |= LINK_INT_WORKING; | 
 | 5297 | 			port_get_link_speed(port); | 
 | 5298 | 		} | 
 | 5299 |  | 
 | 5300 | 		if (unlikely(int_enable & KS884X_INT_RX_STOPPED)) { | 
 | 5301 | 			handle_rx_stop(hw); | 
 | 5302 | 			break; | 
 | 5303 | 		} | 
 | 5304 |  | 
 | 5305 | 		if (unlikely(int_enable & KS884X_INT_TX_STOPPED)) { | 
 | 5306 | 			u32 data; | 
 | 5307 |  | 
 | 5308 | 			hw->intr_mask &= ~KS884X_INT_TX_STOPPED; | 
| Joe Perches | 0dc7d2b | 2010-02-27 14:43:51 +0000 | [diff] [blame] | 5309 | 			pr_info("Tx stopped\n"); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5310 | 			data = readl(hw->io + KS_DMA_TX_CTRL); | 
 | 5311 | 			if (!(data & DMA_TX_ENABLE)) | 
| Joe Perches | 0dc7d2b | 2010-02-27 14:43:51 +0000 | [diff] [blame] | 5312 | 				pr_info("Tx disabled\n"); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5313 | 			break; | 
 | 5314 | 		} | 
 | 5315 | 	} while (0); | 
 | 5316 |  | 
 | 5317 | 	hw_ena_intr(hw); | 
 | 5318 |  | 
 | 5319 | 	return IRQ_HANDLED; | 
 | 5320 | } | 
 | 5321 |  | 
 | 5322 | /* | 
 | 5323 |  * Linux network device functions | 
 | 5324 |  */ | 
 | 5325 |  | 
 | 5326 | static unsigned long next_jiffies; | 
 | 5327 |  | 
 | 5328 | #ifdef CONFIG_NET_POLL_CONTROLLER | 
 | 5329 | static void netdev_netpoll(struct net_device *dev) | 
 | 5330 | { | 
 | 5331 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5332 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 5333 |  | 
 | 5334 | 	hw_dis_intr(&hw_priv->hw); | 
 | 5335 | 	netdev_intr(dev->irq, dev); | 
 | 5336 | } | 
 | 5337 | #endif | 
 | 5338 |  | 
 | 5339 | static void bridge_change(struct ksz_hw *hw) | 
 | 5340 | { | 
 | 5341 | 	int port; | 
 | 5342 | 	u8  member; | 
 | 5343 | 	struct ksz_switch *sw = hw->ksz_switch; | 
 | 5344 |  | 
 | 5345 | 	/* No ports in forwarding state. */ | 
 | 5346 | 	if (!sw->member) { | 
 | 5347 | 		port_set_stp_state(hw, SWITCH_PORT_NUM, STP_STATE_SIMPLE); | 
 | 5348 | 		sw_block_addr(hw); | 
 | 5349 | 	} | 
 | 5350 | 	for (port = 0; port < SWITCH_PORT_NUM; port++) { | 
 | 5351 | 		if (STP_STATE_FORWARDING == sw->port_cfg[port].stp_state) | 
 | 5352 | 			member = HOST_MASK | sw->member; | 
 | 5353 | 		else | 
 | 5354 | 			member = HOST_MASK | (1 << port); | 
 | 5355 | 		if (member != sw->port_cfg[port].member) | 
 | 5356 | 			sw_cfg_port_base_vlan(hw, port, member); | 
 | 5357 | 	} | 
 | 5358 | } | 
 | 5359 |  | 
 | 5360 | /** | 
 | 5361 |  * netdev_close - close network device | 
 | 5362 |  * @dev:	Network device. | 
 | 5363 |  * | 
 | 5364 |  * This function process the close operation of network device.  This is caused | 
 | 5365 |  * by the user command "ifconfig ethX down." | 
 | 5366 |  * | 
 | 5367 |  * Return 0 if successful; otherwise an error code indicating failure. | 
 | 5368 |  */ | 
 | 5369 | static int netdev_close(struct net_device *dev) | 
 | 5370 | { | 
 | 5371 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5372 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 5373 | 	struct ksz_port *port = &priv->port; | 
 | 5374 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 5375 | 	int pi; | 
 | 5376 |  | 
 | 5377 | 	netif_stop_queue(dev); | 
 | 5378 |  | 
 | 5379 | 	ksz_stop_timer(&priv->monitor_timer_info); | 
 | 5380 |  | 
 | 5381 | 	/* Need to shut the port manually in multiple device interfaces mode. */ | 
 | 5382 | 	if (hw->dev_count > 1) { | 
 | 5383 | 		port_set_stp_state(hw, port->first_port, STP_STATE_DISABLED); | 
 | 5384 |  | 
 | 5385 | 		/* Port is closed.  Need to change bridge setting. */ | 
 | 5386 | 		if (hw->features & STP_SUPPORT) { | 
 | 5387 | 			pi = 1 << port->first_port; | 
 | 5388 | 			if (hw->ksz_switch->member & pi) { | 
 | 5389 | 				hw->ksz_switch->member &= ~pi; | 
 | 5390 | 				bridge_change(hw); | 
 | 5391 | 			} | 
 | 5392 | 		} | 
 | 5393 | 	} | 
 | 5394 | 	if (port->first_port > 0) | 
 | 5395 | 		hw_del_addr(hw, dev->dev_addr); | 
 | 5396 | 	if (!hw_priv->wol_enable) | 
 | 5397 | 		port_set_power_saving(port, true); | 
 | 5398 |  | 
 | 5399 | 	if (priv->multicast) | 
 | 5400 | 		--hw->all_multi; | 
 | 5401 | 	if (priv->promiscuous) | 
 | 5402 | 		--hw->promiscuous; | 
 | 5403 |  | 
 | 5404 | 	hw_priv->opened--; | 
 | 5405 | 	if (!(hw_priv->opened)) { | 
 | 5406 | 		ksz_stop_timer(&hw_priv->mib_timer_info); | 
 | 5407 | 		flush_work(&hw_priv->mib_read); | 
 | 5408 |  | 
 | 5409 | 		hw_dis_intr(hw); | 
 | 5410 | 		hw_disable(hw); | 
 | 5411 | 		hw_clr_multicast(hw); | 
 | 5412 |  | 
 | 5413 | 		/* Delay for receive task to stop scheduling itself. */ | 
 | 5414 | 		msleep(2000 / HZ); | 
 | 5415 |  | 
 | 5416 | 		tasklet_disable(&hw_priv->rx_tasklet); | 
 | 5417 | 		tasklet_disable(&hw_priv->tx_tasklet); | 
 | 5418 | 		free_irq(dev->irq, hw_priv->dev); | 
 | 5419 |  | 
 | 5420 | 		transmit_cleanup(hw_priv, 0); | 
 | 5421 | 		hw_reset_pkts(&hw->rx_desc_info); | 
 | 5422 | 		hw_reset_pkts(&hw->tx_desc_info); | 
 | 5423 |  | 
 | 5424 | 		/* Clean out static MAC table when the switch is shutdown. */ | 
 | 5425 | 		if (hw->features & STP_SUPPORT) | 
 | 5426 | 			sw_clr_sta_mac_table(hw); | 
 | 5427 | 	} | 
 | 5428 |  | 
 | 5429 | 	return 0; | 
 | 5430 | } | 
 | 5431 |  | 
 | 5432 | static void hw_cfg_huge_frame(struct dev_info *hw_priv, struct ksz_hw *hw) | 
 | 5433 | { | 
 | 5434 | 	if (hw->ksz_switch) { | 
 | 5435 | 		u32 data; | 
 | 5436 |  | 
 | 5437 | 		data = readw(hw->io + KS8842_SWITCH_CTRL_2_OFFSET); | 
 | 5438 | 		if (hw->features & RX_HUGE_FRAME) | 
 | 5439 | 			data |= SWITCH_HUGE_PACKET; | 
 | 5440 | 		else | 
 | 5441 | 			data &= ~SWITCH_HUGE_PACKET; | 
 | 5442 | 		writew(data, hw->io + KS8842_SWITCH_CTRL_2_OFFSET); | 
 | 5443 | 	} | 
 | 5444 | 	if (hw->features & RX_HUGE_FRAME) { | 
 | 5445 | 		hw->rx_cfg |= DMA_RX_ERROR; | 
 | 5446 | 		hw_priv->dev_rcv = dev_rcv_special; | 
 | 5447 | 	} else { | 
 | 5448 | 		hw->rx_cfg &= ~DMA_RX_ERROR; | 
 | 5449 | 		if (hw->dev_count > 1) | 
 | 5450 | 			hw_priv->dev_rcv = port_rcv_packets; | 
 | 5451 | 		else | 
 | 5452 | 			hw_priv->dev_rcv = dev_rcv_packets; | 
 | 5453 | 	} | 
 | 5454 | } | 
 | 5455 |  | 
 | 5456 | static int prepare_hardware(struct net_device *dev) | 
 | 5457 | { | 
 | 5458 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5459 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 5460 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 5461 | 	int rc = 0; | 
 | 5462 |  | 
 | 5463 | 	/* Remember the network device that requests interrupts. */ | 
 | 5464 | 	hw_priv->dev = dev; | 
 | 5465 | 	rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev); | 
 | 5466 | 	if (rc) | 
 | 5467 | 		return rc; | 
 | 5468 | 	tasklet_enable(&hw_priv->rx_tasklet); | 
 | 5469 | 	tasklet_enable(&hw_priv->tx_tasklet); | 
 | 5470 |  | 
 | 5471 | 	hw->promiscuous = 0; | 
 | 5472 | 	hw->all_multi = 0; | 
 | 5473 | 	hw->multi_list_size = 0; | 
 | 5474 |  | 
 | 5475 | 	hw_reset(hw); | 
 | 5476 |  | 
 | 5477 | 	hw_set_desc_base(hw, | 
 | 5478 | 		hw->tx_desc_info.ring_phys, hw->rx_desc_info.ring_phys); | 
 | 5479 | 	hw_set_addr(hw); | 
 | 5480 | 	hw_cfg_huge_frame(hw_priv, hw); | 
 | 5481 | 	ksz_init_rx_buffers(hw_priv); | 
 | 5482 | 	return 0; | 
 | 5483 | } | 
 | 5484 |  | 
| Joe Perches | 0dc7d2b | 2010-02-27 14:43:51 +0000 | [diff] [blame] | 5485 | static void set_media_state(struct net_device *dev, int media_state) | 
 | 5486 | { | 
 | 5487 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5488 |  | 
 | 5489 | 	if (media_state == priv->media_state) | 
 | 5490 | 		netif_carrier_on(dev); | 
 | 5491 | 	else | 
 | 5492 | 		netif_carrier_off(dev); | 
 | 5493 | 	netif_info(priv, link, dev, "link %s\n", | 
 | 5494 | 		   media_state == priv->media_state ? "on" : "off"); | 
 | 5495 | } | 
 | 5496 |  | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5497 | /** | 
 | 5498 |  * netdev_open - open network device | 
 | 5499 |  * @dev:	Network device. | 
 | 5500 |  * | 
 | 5501 |  * This function process the open operation of network device.  This is caused | 
 | 5502 |  * by the user command "ifconfig ethX up." | 
 | 5503 |  * | 
 | 5504 |  * Return 0 if successful; otherwise an error code indicating failure. | 
 | 5505 |  */ | 
 | 5506 | static int netdev_open(struct net_device *dev) | 
 | 5507 | { | 
 | 5508 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5509 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 5510 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 5511 | 	struct ksz_port *port = &priv->port; | 
 | 5512 | 	int i; | 
 | 5513 | 	int p; | 
 | 5514 | 	int rc = 0; | 
 | 5515 |  | 
 | 5516 | 	priv->multicast = 0; | 
 | 5517 | 	priv->promiscuous = 0; | 
 | 5518 |  | 
 | 5519 | 	/* Reset device statistics. */ | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5520 | 	memset(&dev->stats, 0, sizeof(struct net_device_stats)); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5521 | 	memset((void *) port->counter, 0, | 
 | 5522 | 		(sizeof(u64) * OID_COUNTER_LAST)); | 
 | 5523 |  | 
 | 5524 | 	if (!(hw_priv->opened)) { | 
 | 5525 | 		rc = prepare_hardware(dev); | 
 | 5526 | 		if (rc) | 
 | 5527 | 			return rc; | 
 | 5528 | 		for (i = 0; i < hw->mib_port_cnt; i++) { | 
 | 5529 | 			if (next_jiffies < jiffies) | 
 | 5530 | 				next_jiffies = jiffies + HZ * 2; | 
 | 5531 | 			else | 
 | 5532 | 				next_jiffies += HZ * 1; | 
 | 5533 | 			hw_priv->counter[i].time = next_jiffies; | 
 | 5534 | 			hw->port_mib[i].state = media_disconnected; | 
 | 5535 | 			port_init_cnt(hw, i); | 
 | 5536 | 		} | 
 | 5537 | 		if (hw->ksz_switch) | 
 | 5538 | 			hw->port_mib[HOST_PORT].state = media_connected; | 
 | 5539 | 		else { | 
 | 5540 | 			hw_add_wol_bcast(hw); | 
 | 5541 | 			hw_cfg_wol_pme(hw, 0); | 
 | 5542 | 			hw_clr_wol_pme_status(&hw_priv->hw); | 
 | 5543 | 		} | 
 | 5544 | 	} | 
 | 5545 | 	port_set_power_saving(port, false); | 
 | 5546 |  | 
 | 5547 | 	for (i = 0, p = port->first_port; i < port->port_cnt; i++, p++) { | 
 | 5548 | 		/* | 
 | 5549 | 		 * Initialize to invalid value so that link detection | 
 | 5550 | 		 * is done. | 
 | 5551 | 		 */ | 
 | 5552 | 		hw->port_info[p].partner = 0xFF; | 
 | 5553 | 		hw->port_info[p].state = media_disconnected; | 
 | 5554 | 	} | 
 | 5555 |  | 
 | 5556 | 	/* Need to open the port in multiple device interfaces mode. */ | 
 | 5557 | 	if (hw->dev_count > 1) { | 
 | 5558 | 		port_set_stp_state(hw, port->first_port, STP_STATE_SIMPLE); | 
 | 5559 | 		if (port->first_port > 0) | 
 | 5560 | 			hw_add_addr(hw, dev->dev_addr); | 
 | 5561 | 	} | 
 | 5562 |  | 
 | 5563 | 	port_get_link_speed(port); | 
 | 5564 | 	if (port->force_link) | 
 | 5565 | 		port_force_link_speed(port); | 
 | 5566 | 	else | 
 | 5567 | 		port_set_link_speed(port); | 
 | 5568 |  | 
 | 5569 | 	if (!(hw_priv->opened)) { | 
 | 5570 | 		hw_setup_intr(hw); | 
 | 5571 | 		hw_enable(hw); | 
 | 5572 | 		hw_ena_intr(hw); | 
 | 5573 |  | 
 | 5574 | 		if (hw->mib_port_cnt) | 
 | 5575 | 			ksz_start_timer(&hw_priv->mib_timer_info, | 
 | 5576 | 				hw_priv->mib_timer_info.period); | 
 | 5577 | 	} | 
 | 5578 |  | 
 | 5579 | 	hw_priv->opened++; | 
 | 5580 |  | 
 | 5581 | 	ksz_start_timer(&priv->monitor_timer_info, | 
 | 5582 | 		priv->monitor_timer_info.period); | 
 | 5583 |  | 
 | 5584 | 	priv->media_state = port->linked->state; | 
 | 5585 |  | 
| Joe Perches | 0dc7d2b | 2010-02-27 14:43:51 +0000 | [diff] [blame] | 5586 | 	set_media_state(dev, media_connected); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5587 | 	netif_start_queue(dev); | 
 | 5588 |  | 
 | 5589 | 	return 0; | 
 | 5590 | } | 
 | 5591 |  | 
 | 5592 | /* RX errors = rx_errors */ | 
 | 5593 | /* RX dropped = rx_dropped */ | 
 | 5594 | /* RX overruns = rx_fifo_errors */ | 
 | 5595 | /* RX frame = rx_crc_errors + rx_frame_errors + rx_length_errors */ | 
 | 5596 | /* TX errors = tx_errors */ | 
 | 5597 | /* TX dropped = tx_dropped */ | 
 | 5598 | /* TX overruns = tx_fifo_errors */ | 
 | 5599 | /* TX carrier = tx_aborted_errors + tx_carrier_errors + tx_window_errors */ | 
 | 5600 | /* collisions = collisions */ | 
 | 5601 |  | 
 | 5602 | /** | 
 | 5603 |  * netdev_query_statistics - query network device statistics | 
 | 5604 |  * @dev:	Network device. | 
 | 5605 |  * | 
 | 5606 |  * This function returns the statistics of the network device.  The device | 
 | 5607 |  * needs not be opened. | 
 | 5608 |  * | 
 | 5609 |  * Return network device statistics. | 
 | 5610 |  */ | 
 | 5611 | static struct net_device_stats *netdev_query_statistics(struct net_device *dev) | 
 | 5612 | { | 
 | 5613 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5614 | 	struct ksz_port *port = &priv->port; | 
 | 5615 | 	struct ksz_hw *hw = &priv->adapter->hw; | 
 | 5616 | 	struct ksz_port_mib *mib; | 
 | 5617 | 	int i; | 
 | 5618 | 	int p; | 
 | 5619 |  | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5620 | 	dev->stats.rx_errors = port->counter[OID_COUNTER_RCV_ERROR]; | 
 | 5621 | 	dev->stats.tx_errors = port->counter[OID_COUNTER_XMIT_ERROR]; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5622 |  | 
 | 5623 | 	/* Reset to zero to add count later. */ | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5624 | 	dev->stats.multicast = 0; | 
 | 5625 | 	dev->stats.collisions = 0; | 
 | 5626 | 	dev->stats.rx_length_errors = 0; | 
 | 5627 | 	dev->stats.rx_crc_errors = 0; | 
 | 5628 | 	dev->stats.rx_frame_errors = 0; | 
 | 5629 | 	dev->stats.tx_window_errors = 0; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5630 |  | 
 | 5631 | 	for (i = 0, p = port->first_port; i < port->mib_port_cnt; i++, p++) { | 
 | 5632 | 		mib = &hw->port_mib[p]; | 
 | 5633 |  | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5634 | 		dev->stats.multicast += (unsigned long) | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5635 | 			mib->counter[MIB_COUNTER_RX_MULTICAST]; | 
 | 5636 |  | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5637 | 		dev->stats.collisions += (unsigned long) | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5638 | 			mib->counter[MIB_COUNTER_TX_TOTAL_COLLISION]; | 
 | 5639 |  | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5640 | 		dev->stats.rx_length_errors += (unsigned long)( | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5641 | 			mib->counter[MIB_COUNTER_RX_UNDERSIZE] + | 
 | 5642 | 			mib->counter[MIB_COUNTER_RX_FRAGMENT] + | 
 | 5643 | 			mib->counter[MIB_COUNTER_RX_OVERSIZE] + | 
 | 5644 | 			mib->counter[MIB_COUNTER_RX_JABBER]); | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5645 | 		dev->stats.rx_crc_errors += (unsigned long) | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5646 | 			mib->counter[MIB_COUNTER_RX_CRC_ERR]; | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5647 | 		dev->stats.rx_frame_errors += (unsigned long)( | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5648 | 			mib->counter[MIB_COUNTER_RX_ALIGNMENT_ERR] + | 
 | 5649 | 			mib->counter[MIB_COUNTER_RX_SYMBOL_ERR]); | 
 | 5650 |  | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5651 | 		dev->stats.tx_window_errors += (unsigned long) | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5652 | 			mib->counter[MIB_COUNTER_TX_LATE_COLLISION]; | 
 | 5653 | 	} | 
 | 5654 |  | 
| Kulikov Vasiliy | 897dd41 | 2010-07-05 02:13:58 +0000 | [diff] [blame] | 5655 | 	return &dev->stats; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5656 | } | 
 | 5657 |  | 
 | 5658 | /** | 
 | 5659 |  * netdev_set_mac_address - set network device MAC address | 
 | 5660 |  * @dev:	Network device. | 
 | 5661 |  * @addr:	Buffer of MAC address. | 
 | 5662 |  * | 
 | 5663 |  * This function is used to set the MAC address of the network device. | 
 | 5664 |  * | 
 | 5665 |  * Return 0 to indicate success. | 
 | 5666 |  */ | 
 | 5667 | static int netdev_set_mac_address(struct net_device *dev, void *addr) | 
 | 5668 | { | 
 | 5669 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5670 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 5671 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 5672 | 	struct sockaddr *mac = addr; | 
 | 5673 | 	uint interrupt; | 
 | 5674 |  | 
 | 5675 | 	if (priv->port.first_port > 0) | 
 | 5676 | 		hw_del_addr(hw, dev->dev_addr); | 
 | 5677 | 	else { | 
 | 5678 | 		hw->mac_override = 1; | 
 | 5679 | 		memcpy(hw->override_addr, mac->sa_data, MAC_ADDR_LEN); | 
 | 5680 | 	} | 
 | 5681 |  | 
 | 5682 | 	memcpy(dev->dev_addr, mac->sa_data, MAX_ADDR_LEN); | 
 | 5683 |  | 
 | 5684 | 	interrupt = hw_block_intr(hw); | 
 | 5685 |  | 
 | 5686 | 	if (priv->port.first_port > 0) | 
 | 5687 | 		hw_add_addr(hw, dev->dev_addr); | 
 | 5688 | 	else | 
 | 5689 | 		hw_set_addr(hw); | 
 | 5690 | 	hw_restore_intr(hw, interrupt); | 
 | 5691 |  | 
 | 5692 | 	return 0; | 
 | 5693 | } | 
 | 5694 |  | 
 | 5695 | static void dev_set_promiscuous(struct net_device *dev, struct dev_priv *priv, | 
 | 5696 | 	struct ksz_hw *hw, int promiscuous) | 
 | 5697 | { | 
 | 5698 | 	if (promiscuous != priv->promiscuous) { | 
 | 5699 | 		u8 prev_state = hw->promiscuous; | 
 | 5700 |  | 
 | 5701 | 		if (promiscuous) | 
 | 5702 | 			++hw->promiscuous; | 
 | 5703 | 		else | 
 | 5704 | 			--hw->promiscuous; | 
 | 5705 | 		priv->promiscuous = promiscuous; | 
 | 5706 |  | 
 | 5707 | 		/* Turn on/off promiscuous mode. */ | 
 | 5708 | 		if (hw->promiscuous <= 1 && prev_state <= 1) | 
 | 5709 | 			hw_set_promiscuous(hw, hw->promiscuous); | 
 | 5710 |  | 
 | 5711 | 		/* | 
 | 5712 | 		 * Port is not in promiscuous mode, meaning it is released | 
 | 5713 | 		 * from the bridge. | 
 | 5714 | 		 */ | 
 | 5715 | 		if ((hw->features & STP_SUPPORT) && !promiscuous && | 
| Jiri Pirko | f350a0a | 2010-06-15 06:50:45 +0000 | [diff] [blame] | 5716 | 		    (dev->priv_flags & IFF_BRIDGE_PORT)) { | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5717 | 			struct ksz_switch *sw = hw->ksz_switch; | 
 | 5718 | 			int port = priv->port.first_port; | 
 | 5719 |  | 
 | 5720 | 			port_set_stp_state(hw, port, STP_STATE_DISABLED); | 
 | 5721 | 			port = 1 << port; | 
 | 5722 | 			if (sw->member & port) { | 
 | 5723 | 				sw->member &= ~port; | 
 | 5724 | 				bridge_change(hw); | 
 | 5725 | 			} | 
 | 5726 | 		} | 
 | 5727 | 	} | 
 | 5728 | } | 
 | 5729 |  | 
 | 5730 | static void dev_set_multicast(struct dev_priv *priv, struct ksz_hw *hw, | 
 | 5731 | 	int multicast) | 
 | 5732 | { | 
 | 5733 | 	if (multicast != priv->multicast) { | 
 | 5734 | 		u8 all_multi = hw->all_multi; | 
 | 5735 |  | 
 | 5736 | 		if (multicast) | 
 | 5737 | 			++hw->all_multi; | 
 | 5738 | 		else | 
 | 5739 | 			--hw->all_multi; | 
 | 5740 | 		priv->multicast = multicast; | 
 | 5741 |  | 
 | 5742 | 		/* Turn on/off all multicast mode. */ | 
 | 5743 | 		if (hw->all_multi <= 1 && all_multi <= 1) | 
 | 5744 | 			hw_set_multicast(hw, hw->all_multi); | 
 | 5745 | 	} | 
 | 5746 | } | 
 | 5747 |  | 
 | 5748 | /** | 
 | 5749 |  * netdev_set_rx_mode | 
 | 5750 |  * @dev:	Network device. | 
 | 5751 |  * | 
 | 5752 |  * This routine is used to set multicast addresses or put the network device | 
 | 5753 |  * into promiscuous mode. | 
 | 5754 |  */ | 
 | 5755 | static void netdev_set_rx_mode(struct net_device *dev) | 
 | 5756 | { | 
 | 5757 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5758 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 5759 | 	struct ksz_hw *hw = &hw_priv->hw; | 
| Jiri Pirko | 22bedad | 2010-04-01 21:22:57 +0000 | [diff] [blame] | 5760 | 	struct netdev_hw_addr *ha; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5761 | 	int multicast = (dev->flags & IFF_ALLMULTI); | 
 | 5762 |  | 
 | 5763 | 	dev_set_promiscuous(dev, priv, hw, (dev->flags & IFF_PROMISC)); | 
 | 5764 |  | 
 | 5765 | 	if (hw_priv->hw.dev_count > 1) | 
 | 5766 | 		multicast |= (dev->flags & IFF_MULTICAST); | 
 | 5767 | 	dev_set_multicast(priv, hw, multicast); | 
 | 5768 |  | 
 | 5769 | 	/* Cannot use different hashes in multiple device interfaces mode. */ | 
 | 5770 | 	if (hw_priv->hw.dev_count > 1) | 
 | 5771 | 		return; | 
 | 5772 |  | 
| Jiri Pirko | f9dcbcc | 2010-02-23 09:19:49 +0000 | [diff] [blame] | 5773 | 	if ((dev->flags & IFF_MULTICAST) && !netdev_mc_empty(dev)) { | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5774 | 		int i = 0; | 
 | 5775 |  | 
 | 5776 | 		/* List too big to support so turn on all multicast mode. */ | 
| Jiri Pirko | 22bedad | 2010-04-01 21:22:57 +0000 | [diff] [blame] | 5777 | 		if (netdev_mc_count(dev) > MAX_MULTICAST_LIST) { | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5778 | 			if (MAX_MULTICAST_LIST != hw->multi_list_size) { | 
 | 5779 | 				hw->multi_list_size = MAX_MULTICAST_LIST; | 
 | 5780 | 				++hw->all_multi; | 
 | 5781 | 				hw_set_multicast(hw, hw->all_multi); | 
 | 5782 | 			} | 
 | 5783 | 			return; | 
 | 5784 | 		} | 
 | 5785 |  | 
| Jiri Pirko | 22bedad | 2010-04-01 21:22:57 +0000 | [diff] [blame] | 5786 | 		netdev_for_each_mc_addr(ha, dev) { | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5787 | 			if (i >= MAX_MULTICAST_LIST) | 
 | 5788 | 				break; | 
| Jiri Pirko | 22bedad | 2010-04-01 21:22:57 +0000 | [diff] [blame] | 5789 | 			memcpy(hw->multi_list[i++], ha->addr, MAC_ADDR_LEN); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 5790 | 		} | 
 | 5791 | 		hw->multi_list_size = (u8) i; | 
 | 5792 | 		hw_set_grp_addr(hw); | 
 | 5793 | 	} else { | 
 | 5794 | 		if (MAX_MULTICAST_LIST == hw->multi_list_size) { | 
 | 5795 | 			--hw->all_multi; | 
 | 5796 | 			hw_set_multicast(hw, hw->all_multi); | 
 | 5797 | 		} | 
 | 5798 | 		hw->multi_list_size = 0; | 
 | 5799 | 		hw_clr_multicast(hw); | 
 | 5800 | 	} | 
 | 5801 | } | 
 | 5802 |  | 
 | 5803 | static int netdev_change_mtu(struct net_device *dev, int new_mtu) | 
 | 5804 | { | 
 | 5805 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5806 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 5807 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 5808 | 	int hw_mtu; | 
 | 5809 |  | 
 | 5810 | 	if (netif_running(dev)) | 
 | 5811 | 		return -EBUSY; | 
 | 5812 |  | 
 | 5813 | 	/* Cannot use different MTU in multiple device interfaces mode. */ | 
 | 5814 | 	if (hw->dev_count > 1) | 
 | 5815 | 		if (dev != hw_priv->dev) | 
 | 5816 | 			return 0; | 
 | 5817 | 	if (new_mtu < 60) | 
 | 5818 | 		return -EINVAL; | 
 | 5819 |  | 
 | 5820 | 	if (dev->mtu != new_mtu) { | 
 | 5821 | 		hw_mtu = new_mtu + ETHERNET_HEADER_SIZE + 4; | 
 | 5822 | 		if (hw_mtu > MAX_RX_BUF_SIZE) | 
 | 5823 | 			return -EINVAL; | 
 | 5824 | 		if (hw_mtu > REGULAR_RX_BUF_SIZE) { | 
 | 5825 | 			hw->features |= RX_HUGE_FRAME; | 
 | 5826 | 			hw_mtu = MAX_RX_BUF_SIZE; | 
 | 5827 | 		} else { | 
 | 5828 | 			hw->features &= ~RX_HUGE_FRAME; | 
 | 5829 | 			hw_mtu = REGULAR_RX_BUF_SIZE; | 
 | 5830 | 		} | 
 | 5831 | 		hw_mtu = (hw_mtu + 3) & ~3; | 
 | 5832 | 		hw_priv->mtu = hw_mtu; | 
 | 5833 | 		dev->mtu = new_mtu; | 
 | 5834 | 	} | 
 | 5835 | 	return 0; | 
 | 5836 | } | 
 | 5837 |  | 
 | 5838 | /** | 
 | 5839 |  * netdev_ioctl - I/O control processing | 
 | 5840 |  * @dev:	Network device. | 
 | 5841 |  * @ifr:	Interface request structure. | 
 | 5842 |  * @cmd:	I/O control code. | 
 | 5843 |  * | 
 | 5844 |  * This function is used to process I/O control calls. | 
 | 5845 |  * | 
 | 5846 |  * Return 0 to indicate success. | 
 | 5847 |  */ | 
 | 5848 | static int netdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 
 | 5849 | { | 
 | 5850 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5851 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 5852 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 5853 | 	struct ksz_port *port = &priv->port; | 
 | 5854 | 	int rc; | 
 | 5855 | 	int result = 0; | 
 | 5856 | 	struct mii_ioctl_data *data = if_mii(ifr); | 
 | 5857 |  | 
 | 5858 | 	if (down_interruptible(&priv->proc_sem)) | 
 | 5859 | 		return -ERESTARTSYS; | 
 | 5860 |  | 
 | 5861 | 	/* assume success */ | 
 | 5862 | 	rc = 0; | 
 | 5863 | 	switch (cmd) { | 
 | 5864 | 	/* Get address of MII PHY in use. */ | 
 | 5865 | 	case SIOCGMIIPHY: | 
 | 5866 | 		data->phy_id = priv->id; | 
 | 5867 |  | 
 | 5868 | 		/* Fallthrough... */ | 
 | 5869 |  | 
 | 5870 | 	/* Read MII PHY register. */ | 
 | 5871 | 	case SIOCGMIIREG: | 
 | 5872 | 		if (data->phy_id != priv->id || data->reg_num >= 6) | 
 | 5873 | 			result = -EIO; | 
 | 5874 | 		else | 
 | 5875 | 			hw_r_phy(hw, port->linked->port_id, data->reg_num, | 
 | 5876 | 				&data->val_out); | 
 | 5877 | 		break; | 
 | 5878 |  | 
 | 5879 | 	/* Write MII PHY register. */ | 
 | 5880 | 	case SIOCSMIIREG: | 
 | 5881 | 		if (!capable(CAP_NET_ADMIN)) | 
 | 5882 | 			result = -EPERM; | 
 | 5883 | 		else if (data->phy_id != priv->id || data->reg_num >= 6) | 
 | 5884 | 			result = -EIO; | 
 | 5885 | 		else | 
 | 5886 | 			hw_w_phy(hw, port->linked->port_id, data->reg_num, | 
 | 5887 | 				data->val_in); | 
 | 5888 | 		break; | 
 | 5889 |  | 
 | 5890 | 	default: | 
 | 5891 | 		result = -EOPNOTSUPP; | 
 | 5892 | 	} | 
 | 5893 |  | 
 | 5894 | 	up(&priv->proc_sem); | 
 | 5895 |  | 
 | 5896 | 	return result; | 
 | 5897 | } | 
 | 5898 |  | 
 | 5899 | /* | 
 | 5900 |  * MII support | 
 | 5901 |  */ | 
 | 5902 |  | 
 | 5903 | /** | 
 | 5904 |  * mdio_read - read PHY register | 
 | 5905 |  * @dev:	Network device. | 
 | 5906 |  * @phy_id:	The PHY id. | 
 | 5907 |  * @reg_num:	The register number. | 
 | 5908 |  * | 
 | 5909 |  * This function returns the PHY register value. | 
 | 5910 |  * | 
 | 5911 |  * Return the register value. | 
 | 5912 |  */ | 
 | 5913 | static int mdio_read(struct net_device *dev, int phy_id, int reg_num) | 
 | 5914 | { | 
 | 5915 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5916 | 	struct ksz_port *port = &priv->port; | 
 | 5917 | 	struct ksz_hw *hw = port->hw; | 
 | 5918 | 	u16 val_out; | 
 | 5919 |  | 
 | 5920 | 	hw_r_phy(hw, port->linked->port_id, reg_num << 1, &val_out); | 
 | 5921 | 	return val_out; | 
 | 5922 | } | 
 | 5923 |  | 
 | 5924 | /** | 
 | 5925 |  * mdio_write - set PHY register | 
 | 5926 |  * @dev:	Network device. | 
 | 5927 |  * @phy_id:	The PHY id. | 
 | 5928 |  * @reg_num:	The register number. | 
 | 5929 |  * @val:	The register value. | 
 | 5930 |  * | 
 | 5931 |  * This procedure sets the PHY register value. | 
 | 5932 |  */ | 
 | 5933 | static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val) | 
 | 5934 | { | 
 | 5935 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5936 | 	struct ksz_port *port = &priv->port; | 
 | 5937 | 	struct ksz_hw *hw = port->hw; | 
 | 5938 | 	int i; | 
 | 5939 | 	int pi; | 
 | 5940 |  | 
 | 5941 | 	for (i = 0, pi = port->first_port; i < port->port_cnt; i++, pi++) | 
 | 5942 | 		hw_w_phy(hw, pi, reg_num << 1, val); | 
 | 5943 | } | 
 | 5944 |  | 
 | 5945 | /* | 
 | 5946 |  * ethtool support | 
 | 5947 |  */ | 
 | 5948 |  | 
 | 5949 | #define EEPROM_SIZE			0x40 | 
 | 5950 |  | 
 | 5951 | static u16 eeprom_data[EEPROM_SIZE] = { 0 }; | 
 | 5952 |  | 
 | 5953 | #define ADVERTISED_ALL			\ | 
 | 5954 | 	(ADVERTISED_10baseT_Half |	\ | 
 | 5955 | 	ADVERTISED_10baseT_Full |	\ | 
 | 5956 | 	ADVERTISED_100baseT_Half |	\ | 
 | 5957 | 	ADVERTISED_100baseT_Full) | 
 | 5958 |  | 
 | 5959 | /* These functions use the MII functions in mii.c. */ | 
 | 5960 |  | 
 | 5961 | /** | 
 | 5962 |  * netdev_get_settings - get network device settings | 
 | 5963 |  * @dev:	Network device. | 
 | 5964 |  * @cmd:	Ethtool command. | 
 | 5965 |  * | 
 | 5966 |  * This function queries the PHY and returns its state in the ethtool command. | 
 | 5967 |  * | 
 | 5968 |  * Return 0 if successful; otherwise an error code. | 
 | 5969 |  */ | 
 | 5970 | static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 
 | 5971 | { | 
 | 5972 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5973 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 5974 |  | 
 | 5975 | 	mutex_lock(&hw_priv->lock); | 
 | 5976 | 	mii_ethtool_gset(&priv->mii_if, cmd); | 
 | 5977 | 	cmd->advertising |= SUPPORTED_TP; | 
 | 5978 | 	mutex_unlock(&hw_priv->lock); | 
 | 5979 |  | 
 | 5980 | 	/* Save advertised settings for workaround in next function. */ | 
 | 5981 | 	priv->advertising = cmd->advertising; | 
 | 5982 | 	return 0; | 
 | 5983 | } | 
 | 5984 |  | 
 | 5985 | /** | 
 | 5986 |  * netdev_set_settings - set network device settings | 
 | 5987 |  * @dev:	Network device. | 
 | 5988 |  * @cmd:	Ethtool command. | 
 | 5989 |  * | 
 | 5990 |  * This function sets the PHY according to the ethtool command. | 
 | 5991 |  * | 
 | 5992 |  * Return 0 if successful; otherwise an error code. | 
 | 5993 |  */ | 
 | 5994 | static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 
 | 5995 | { | 
 | 5996 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 5997 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 5998 | 	struct ksz_port *port = &priv->port; | 
| David Decotigny | 25db033 | 2011-04-27 18:32:39 +0000 | [diff] [blame] | 5999 | 	u32 speed = ethtool_cmd_speed(cmd); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6000 | 	int rc; | 
 | 6001 |  | 
 | 6002 | 	/* | 
 | 6003 | 	 * ethtool utility does not change advertised setting if auto | 
 | 6004 | 	 * negotiation is not specified explicitly. | 
 | 6005 | 	 */ | 
 | 6006 | 	if (cmd->autoneg && priv->advertising == cmd->advertising) { | 
 | 6007 | 		cmd->advertising |= ADVERTISED_ALL; | 
| David Decotigny | 25db033 | 2011-04-27 18:32:39 +0000 | [diff] [blame] | 6008 | 		if (10 == speed) | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6009 | 			cmd->advertising &= | 
 | 6010 | 				~(ADVERTISED_100baseT_Full | | 
 | 6011 | 				ADVERTISED_100baseT_Half); | 
| David Decotigny | 25db033 | 2011-04-27 18:32:39 +0000 | [diff] [blame] | 6012 | 		else if (100 == speed) | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6013 | 			cmd->advertising &= | 
 | 6014 | 				~(ADVERTISED_10baseT_Full | | 
 | 6015 | 				ADVERTISED_10baseT_Half); | 
 | 6016 | 		if (0 == cmd->duplex) | 
 | 6017 | 			cmd->advertising &= | 
 | 6018 | 				~(ADVERTISED_100baseT_Full | | 
 | 6019 | 				ADVERTISED_10baseT_Full); | 
 | 6020 | 		else if (1 == cmd->duplex) | 
 | 6021 | 			cmd->advertising &= | 
 | 6022 | 				~(ADVERTISED_100baseT_Half | | 
 | 6023 | 				ADVERTISED_10baseT_Half); | 
 | 6024 | 	} | 
 | 6025 | 	mutex_lock(&hw_priv->lock); | 
 | 6026 | 	if (cmd->autoneg && | 
 | 6027 | 			(cmd->advertising & ADVERTISED_ALL) == | 
 | 6028 | 			ADVERTISED_ALL) { | 
 | 6029 | 		port->duplex = 0; | 
 | 6030 | 		port->speed = 0; | 
 | 6031 | 		port->force_link = 0; | 
 | 6032 | 	} else { | 
 | 6033 | 		port->duplex = cmd->duplex + 1; | 
| David Decotigny | 25db033 | 2011-04-27 18:32:39 +0000 | [diff] [blame] | 6034 | 		if (1000 != speed) | 
 | 6035 | 			port->speed = speed; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6036 | 		if (cmd->autoneg) | 
 | 6037 | 			port->force_link = 0; | 
 | 6038 | 		else | 
 | 6039 | 			port->force_link = 1; | 
 | 6040 | 	} | 
 | 6041 | 	rc = mii_ethtool_sset(&priv->mii_if, cmd); | 
 | 6042 | 	mutex_unlock(&hw_priv->lock); | 
 | 6043 | 	return rc; | 
 | 6044 | } | 
 | 6045 |  | 
 | 6046 | /** | 
 | 6047 |  * netdev_nway_reset - restart auto-negotiation | 
 | 6048 |  * @dev:	Network device. | 
 | 6049 |  * | 
 | 6050 |  * This function restarts the PHY for auto-negotiation. | 
 | 6051 |  * | 
 | 6052 |  * Return 0 if successful; otherwise an error code. | 
 | 6053 |  */ | 
 | 6054 | static int netdev_nway_reset(struct net_device *dev) | 
 | 6055 | { | 
 | 6056 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6057 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6058 | 	int rc; | 
 | 6059 |  | 
 | 6060 | 	mutex_lock(&hw_priv->lock); | 
 | 6061 | 	rc = mii_nway_restart(&priv->mii_if); | 
 | 6062 | 	mutex_unlock(&hw_priv->lock); | 
 | 6063 | 	return rc; | 
 | 6064 | } | 
 | 6065 |  | 
 | 6066 | /** | 
 | 6067 |  * netdev_get_link - get network device link status | 
 | 6068 |  * @dev:	Network device. | 
 | 6069 |  * | 
 | 6070 |  * This function gets the link status from the PHY. | 
 | 6071 |  * | 
 | 6072 |  * Return true if PHY is linked and false otherwise. | 
 | 6073 |  */ | 
 | 6074 | static u32 netdev_get_link(struct net_device *dev) | 
 | 6075 | { | 
 | 6076 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6077 | 	int rc; | 
 | 6078 |  | 
 | 6079 | 	rc = mii_link_ok(&priv->mii_if); | 
 | 6080 | 	return rc; | 
 | 6081 | } | 
 | 6082 |  | 
 | 6083 | /** | 
 | 6084 |  * netdev_get_drvinfo - get network driver information | 
 | 6085 |  * @dev:	Network device. | 
 | 6086 |  * @info:	Ethtool driver info data structure. | 
 | 6087 |  * | 
 | 6088 |  * This procedure returns the driver information. | 
 | 6089 |  */ | 
 | 6090 | static void netdev_get_drvinfo(struct net_device *dev, | 
 | 6091 | 	struct ethtool_drvinfo *info) | 
 | 6092 | { | 
 | 6093 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6094 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6095 |  | 
 | 6096 | 	strcpy(info->driver, DRV_NAME); | 
 | 6097 | 	strcpy(info->version, DRV_VERSION); | 
 | 6098 | 	strcpy(info->bus_info, pci_name(hw_priv->pdev)); | 
 | 6099 | } | 
 | 6100 |  | 
 | 6101 | /** | 
 | 6102 |  * netdev_get_regs_len - get length of register dump | 
 | 6103 |  * @dev:	Network device. | 
 | 6104 |  * | 
 | 6105 |  * This function returns the length of the register dump. | 
 | 6106 |  * | 
 | 6107 |  * Return length of the register dump. | 
 | 6108 |  */ | 
 | 6109 | static struct hw_regs { | 
 | 6110 | 	int start; | 
 | 6111 | 	int end; | 
 | 6112 | } hw_regs_range[] = { | 
 | 6113 | 	{ KS_DMA_TX_CTRL,	KS884X_INTERRUPTS_STATUS }, | 
 | 6114 | 	{ KS_ADD_ADDR_0_LO,	KS_ADD_ADDR_F_HI }, | 
 | 6115 | 	{ KS884X_ADDR_0_OFFSET,	KS8841_WOL_FRAME_BYTE2_OFFSET }, | 
 | 6116 | 	{ KS884X_SIDER_P,	KS8842_SGCR7_P }, | 
 | 6117 | 	{ KS8842_MACAR1_P,	KS8842_TOSR8_P }, | 
 | 6118 | 	{ KS884X_P1MBCR_P,	KS8842_P3ERCR_P }, | 
 | 6119 | 	{ 0, 0 } | 
 | 6120 | }; | 
 | 6121 |  | 
 | 6122 | static int netdev_get_regs_len(struct net_device *dev) | 
 | 6123 | { | 
 | 6124 | 	struct hw_regs *range = hw_regs_range; | 
 | 6125 | 	int regs_len = 0x10 * sizeof(u32); | 
 | 6126 |  | 
 | 6127 | 	while (range->end > range->start) { | 
 | 6128 | 		regs_len += (range->end - range->start + 3) / 4 * 4; | 
 | 6129 | 		range++; | 
 | 6130 | 	} | 
 | 6131 | 	return regs_len; | 
 | 6132 | } | 
 | 6133 |  | 
 | 6134 | /** | 
 | 6135 |  * netdev_get_regs - get register dump | 
 | 6136 |  * @dev:	Network device. | 
 | 6137 |  * @regs:	Ethtool registers data structure. | 
 | 6138 |  * @ptr:	Buffer to store the register values. | 
 | 6139 |  * | 
 | 6140 |  * This procedure dumps the register values in the provided buffer. | 
 | 6141 |  */ | 
 | 6142 | static void netdev_get_regs(struct net_device *dev, struct ethtool_regs *regs, | 
 | 6143 | 	void *ptr) | 
 | 6144 | { | 
 | 6145 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6146 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6147 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 6148 | 	int *buf = (int *) ptr; | 
 | 6149 | 	struct hw_regs *range = hw_regs_range; | 
 | 6150 | 	int len; | 
 | 6151 |  | 
 | 6152 | 	mutex_lock(&hw_priv->lock); | 
 | 6153 | 	regs->version = 0; | 
 | 6154 | 	for (len = 0; len < 0x40; len += 4) { | 
 | 6155 | 		pci_read_config_dword(hw_priv->pdev, len, buf); | 
 | 6156 | 		buf++; | 
 | 6157 | 	} | 
 | 6158 | 	while (range->end > range->start) { | 
 | 6159 | 		for (len = range->start; len < range->end; len += 4) { | 
 | 6160 | 			*buf = readl(hw->io + len); | 
 | 6161 | 			buf++; | 
 | 6162 | 		} | 
 | 6163 | 		range++; | 
 | 6164 | 	} | 
 | 6165 | 	mutex_unlock(&hw_priv->lock); | 
 | 6166 | } | 
 | 6167 |  | 
 | 6168 | #define WOL_SUPPORT			\ | 
 | 6169 | 	(WAKE_PHY | WAKE_MAGIC |	\ | 
 | 6170 | 	WAKE_UCAST | WAKE_MCAST |	\ | 
 | 6171 | 	WAKE_BCAST | WAKE_ARP) | 
 | 6172 |  | 
 | 6173 | /** | 
 | 6174 |  * netdev_get_wol - get Wake-on-LAN support | 
 | 6175 |  * @dev:	Network device. | 
 | 6176 |  * @wol:	Ethtool Wake-on-LAN data structure. | 
 | 6177 |  * | 
 | 6178 |  * This procedure returns Wake-on-LAN support. | 
 | 6179 |  */ | 
 | 6180 | static void netdev_get_wol(struct net_device *dev, | 
 | 6181 | 	struct ethtool_wolinfo *wol) | 
 | 6182 | { | 
 | 6183 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6184 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6185 |  | 
 | 6186 | 	wol->supported = hw_priv->wol_support; | 
 | 6187 | 	wol->wolopts = hw_priv->wol_enable; | 
 | 6188 | 	memset(&wol->sopass, 0, sizeof(wol->sopass)); | 
 | 6189 | } | 
 | 6190 |  | 
 | 6191 | /** | 
 | 6192 |  * netdev_set_wol - set Wake-on-LAN support | 
 | 6193 |  * @dev:	Network device. | 
 | 6194 |  * @wol:	Ethtool Wake-on-LAN data structure. | 
 | 6195 |  * | 
 | 6196 |  * This function sets Wake-on-LAN support. | 
 | 6197 |  * | 
 | 6198 |  * Return 0 if successful; otherwise an error code. | 
 | 6199 |  */ | 
 | 6200 | static int netdev_set_wol(struct net_device *dev, | 
 | 6201 | 	struct ethtool_wolinfo *wol) | 
 | 6202 | { | 
 | 6203 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6204 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6205 |  | 
 | 6206 | 	/* Need to find a way to retrieve the device IP address. */ | 
| Joe Perches | b6bc765 | 2010-12-21 02:16:08 -0800 | [diff] [blame] | 6207 | 	static const u8 net_addr[] = { 192, 168, 1, 1 }; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6208 |  | 
 | 6209 | 	if (wol->wolopts & ~hw_priv->wol_support) | 
 | 6210 | 		return -EINVAL; | 
 | 6211 |  | 
 | 6212 | 	hw_priv->wol_enable = wol->wolopts; | 
 | 6213 |  | 
 | 6214 | 	/* Link wakeup cannot really be disabled. */ | 
 | 6215 | 	if (wol->wolopts) | 
 | 6216 | 		hw_priv->wol_enable |= WAKE_PHY; | 
 | 6217 | 	hw_enable_wol(&hw_priv->hw, hw_priv->wol_enable, net_addr); | 
 | 6218 | 	return 0; | 
 | 6219 | } | 
 | 6220 |  | 
 | 6221 | /** | 
 | 6222 |  * netdev_get_msglevel - get debug message level | 
 | 6223 |  * @dev:	Network device. | 
 | 6224 |  * | 
 | 6225 |  * This function returns current debug message level. | 
 | 6226 |  * | 
 | 6227 |  * Return current debug message flags. | 
 | 6228 |  */ | 
 | 6229 | static u32 netdev_get_msglevel(struct net_device *dev) | 
 | 6230 | { | 
 | 6231 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6232 |  | 
 | 6233 | 	return priv->msg_enable; | 
 | 6234 | } | 
 | 6235 |  | 
 | 6236 | /** | 
 | 6237 |  * netdev_set_msglevel - set debug message level | 
 | 6238 |  * @dev:	Network device. | 
 | 6239 |  * @value:	Debug message flags. | 
 | 6240 |  * | 
 | 6241 |  * This procedure sets debug message level. | 
 | 6242 |  */ | 
 | 6243 | static void netdev_set_msglevel(struct net_device *dev, u32 value) | 
 | 6244 | { | 
 | 6245 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6246 |  | 
 | 6247 | 	priv->msg_enable = value; | 
 | 6248 | } | 
 | 6249 |  | 
 | 6250 | /** | 
 | 6251 |  * netdev_get_eeprom_len - get EEPROM length | 
 | 6252 |  * @dev:	Network device. | 
 | 6253 |  * | 
 | 6254 |  * This function returns the length of the EEPROM. | 
 | 6255 |  * | 
 | 6256 |  * Return length of the EEPROM. | 
 | 6257 |  */ | 
 | 6258 | static int netdev_get_eeprom_len(struct net_device *dev) | 
 | 6259 | { | 
 | 6260 | 	return EEPROM_SIZE * 2; | 
 | 6261 | } | 
 | 6262 |  | 
 | 6263 | /** | 
 | 6264 |  * netdev_get_eeprom - get EEPROM data | 
 | 6265 |  * @dev:	Network device. | 
 | 6266 |  * @eeprom:	Ethtool EEPROM data structure. | 
 | 6267 |  * @data:	Buffer to store the EEPROM data. | 
 | 6268 |  * | 
 | 6269 |  * This function dumps the EEPROM data in the provided buffer. | 
 | 6270 |  * | 
 | 6271 |  * Return 0 if successful; otherwise an error code. | 
 | 6272 |  */ | 
 | 6273 | #define EEPROM_MAGIC			0x10A18842 | 
 | 6274 |  | 
 | 6275 | static int netdev_get_eeprom(struct net_device *dev, | 
 | 6276 | 	struct ethtool_eeprom *eeprom, u8 *data) | 
 | 6277 | { | 
 | 6278 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6279 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6280 | 	u8 *eeprom_byte = (u8 *) eeprom_data; | 
 | 6281 | 	int i; | 
 | 6282 | 	int len; | 
 | 6283 |  | 
 | 6284 | 	len = (eeprom->offset + eeprom->len + 1) / 2; | 
 | 6285 | 	for (i = eeprom->offset / 2; i < len; i++) | 
 | 6286 | 		eeprom_data[i] = eeprom_read(&hw_priv->hw, i); | 
 | 6287 | 	eeprom->magic = EEPROM_MAGIC; | 
 | 6288 | 	memcpy(data, &eeprom_byte[eeprom->offset], eeprom->len); | 
 | 6289 |  | 
 | 6290 | 	return 0; | 
 | 6291 | } | 
 | 6292 |  | 
 | 6293 | /** | 
 | 6294 |  * netdev_set_eeprom - write EEPROM data | 
 | 6295 |  * @dev:	Network device. | 
 | 6296 |  * @eeprom:	Ethtool EEPROM data structure. | 
 | 6297 |  * @data:	Data buffer. | 
 | 6298 |  * | 
 | 6299 |  * This function modifies the EEPROM data one byte at a time. | 
 | 6300 |  * | 
 | 6301 |  * Return 0 if successful; otherwise an error code. | 
 | 6302 |  */ | 
 | 6303 | static int netdev_set_eeprom(struct net_device *dev, | 
 | 6304 | 	struct ethtool_eeprom *eeprom, u8 *data) | 
 | 6305 | { | 
 | 6306 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6307 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6308 | 	u16 eeprom_word[EEPROM_SIZE]; | 
 | 6309 | 	u8 *eeprom_byte = (u8 *) eeprom_word; | 
 | 6310 | 	int i; | 
 | 6311 | 	int len; | 
 | 6312 |  | 
 | 6313 | 	if (eeprom->magic != EEPROM_MAGIC) | 
| Jens Rottmann | 4881a4f | 2010-03-23 04:23:50 +0000 | [diff] [blame] | 6314 | 		return -EINVAL; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6315 |  | 
 | 6316 | 	len = (eeprom->offset + eeprom->len + 1) / 2; | 
 | 6317 | 	for (i = eeprom->offset / 2; i < len; i++) | 
 | 6318 | 		eeprom_data[i] = eeprom_read(&hw_priv->hw, i); | 
 | 6319 | 	memcpy(eeprom_word, eeprom_data, EEPROM_SIZE * 2); | 
 | 6320 | 	memcpy(&eeprom_byte[eeprom->offset], data, eeprom->len); | 
 | 6321 | 	for (i = 0; i < EEPROM_SIZE; i++) | 
 | 6322 | 		if (eeprom_word[i] != eeprom_data[i]) { | 
 | 6323 | 			eeprom_data[i] = eeprom_word[i]; | 
 | 6324 | 			eeprom_write(&hw_priv->hw, i, eeprom_data[i]); | 
 | 6325 | 	} | 
 | 6326 |  | 
 | 6327 | 	return 0; | 
 | 6328 | } | 
 | 6329 |  | 
 | 6330 | /** | 
 | 6331 |  * netdev_get_pauseparam - get flow control parameters | 
 | 6332 |  * @dev:	Network device. | 
 | 6333 |  * @pause:	Ethtool PAUSE settings data structure. | 
 | 6334 |  * | 
 | 6335 |  * This procedure returns the PAUSE control flow settings. | 
 | 6336 |  */ | 
 | 6337 | static void netdev_get_pauseparam(struct net_device *dev, | 
 | 6338 | 	struct ethtool_pauseparam *pause) | 
 | 6339 | { | 
 | 6340 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6341 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6342 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 6343 |  | 
 | 6344 | 	pause->autoneg = (hw->overrides & PAUSE_FLOW_CTRL) ? 0 : 1; | 
 | 6345 | 	if (!hw->ksz_switch) { | 
 | 6346 | 		pause->rx_pause = | 
 | 6347 | 			(hw->rx_cfg & DMA_RX_FLOW_ENABLE) ? 1 : 0; | 
 | 6348 | 		pause->tx_pause = | 
 | 6349 | 			(hw->tx_cfg & DMA_TX_FLOW_ENABLE) ? 1 : 0; | 
 | 6350 | 	} else { | 
 | 6351 | 		pause->rx_pause = | 
 | 6352 | 			(sw_chk(hw, KS8842_SWITCH_CTRL_1_OFFSET, | 
 | 6353 | 				SWITCH_RX_FLOW_CTRL)) ? 1 : 0; | 
 | 6354 | 		pause->tx_pause = | 
 | 6355 | 			(sw_chk(hw, KS8842_SWITCH_CTRL_1_OFFSET, | 
 | 6356 | 				SWITCH_TX_FLOW_CTRL)) ? 1 : 0; | 
 | 6357 | 	} | 
 | 6358 | } | 
 | 6359 |  | 
 | 6360 | /** | 
 | 6361 |  * netdev_set_pauseparam - set flow control parameters | 
 | 6362 |  * @dev:	Network device. | 
 | 6363 |  * @pause:	Ethtool PAUSE settings data structure. | 
 | 6364 |  * | 
 | 6365 |  * This function sets the PAUSE control flow settings. | 
 | 6366 |  * Not implemented yet. | 
 | 6367 |  * | 
 | 6368 |  * Return 0 if successful; otherwise an error code. | 
 | 6369 |  */ | 
 | 6370 | static int netdev_set_pauseparam(struct net_device *dev, | 
 | 6371 | 	struct ethtool_pauseparam *pause) | 
 | 6372 | { | 
 | 6373 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6374 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6375 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 6376 | 	struct ksz_port *port = &priv->port; | 
 | 6377 |  | 
 | 6378 | 	mutex_lock(&hw_priv->lock); | 
 | 6379 | 	if (pause->autoneg) { | 
 | 6380 | 		if (!pause->rx_pause && !pause->tx_pause) | 
 | 6381 | 			port->flow_ctrl = PHY_NO_FLOW_CTRL; | 
 | 6382 | 		else | 
 | 6383 | 			port->flow_ctrl = PHY_FLOW_CTRL; | 
 | 6384 | 		hw->overrides &= ~PAUSE_FLOW_CTRL; | 
 | 6385 | 		port->force_link = 0; | 
 | 6386 | 		if (hw->ksz_switch) { | 
 | 6387 | 			sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET, | 
 | 6388 | 				SWITCH_RX_FLOW_CTRL, 1); | 
 | 6389 | 			sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET, | 
 | 6390 | 				SWITCH_TX_FLOW_CTRL, 1); | 
 | 6391 | 		} | 
 | 6392 | 		port_set_link_speed(port); | 
 | 6393 | 	} else { | 
 | 6394 | 		hw->overrides |= PAUSE_FLOW_CTRL; | 
 | 6395 | 		if (hw->ksz_switch) { | 
 | 6396 | 			sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET, | 
 | 6397 | 				SWITCH_RX_FLOW_CTRL, pause->rx_pause); | 
 | 6398 | 			sw_cfg(hw, KS8842_SWITCH_CTRL_1_OFFSET, | 
 | 6399 | 				SWITCH_TX_FLOW_CTRL, pause->tx_pause); | 
 | 6400 | 		} else | 
 | 6401 | 			set_flow_ctrl(hw, pause->rx_pause, pause->tx_pause); | 
 | 6402 | 	} | 
 | 6403 | 	mutex_unlock(&hw_priv->lock); | 
 | 6404 |  | 
 | 6405 | 	return 0; | 
 | 6406 | } | 
 | 6407 |  | 
 | 6408 | /** | 
 | 6409 |  * netdev_get_ringparam - get tx/rx ring parameters | 
 | 6410 |  * @dev:	Network device. | 
 | 6411 |  * @pause:	Ethtool RING settings data structure. | 
 | 6412 |  * | 
 | 6413 |  * This procedure returns the TX/RX ring settings. | 
 | 6414 |  */ | 
 | 6415 | static void netdev_get_ringparam(struct net_device *dev, | 
 | 6416 | 	struct ethtool_ringparam *ring) | 
 | 6417 | { | 
 | 6418 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6419 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6420 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 6421 |  | 
 | 6422 | 	ring->tx_max_pending = (1 << 9); | 
 | 6423 | 	ring->tx_pending = hw->tx_desc_info.alloc; | 
 | 6424 | 	ring->rx_max_pending = (1 << 9); | 
 | 6425 | 	ring->rx_pending = hw->rx_desc_info.alloc; | 
 | 6426 | } | 
 | 6427 |  | 
 | 6428 | #define STATS_LEN			(TOTAL_PORT_COUNTER_NUM) | 
 | 6429 |  | 
 | 6430 | static struct { | 
 | 6431 | 	char string[ETH_GSTRING_LEN]; | 
 | 6432 | } ethtool_stats_keys[STATS_LEN] = { | 
 | 6433 | 	{ "rx_lo_priority_octets" }, | 
 | 6434 | 	{ "rx_hi_priority_octets" }, | 
 | 6435 | 	{ "rx_undersize_packets" }, | 
 | 6436 | 	{ "rx_fragments" }, | 
 | 6437 | 	{ "rx_oversize_packets" }, | 
 | 6438 | 	{ "rx_jabbers" }, | 
 | 6439 | 	{ "rx_symbol_errors" }, | 
 | 6440 | 	{ "rx_crc_errors" }, | 
 | 6441 | 	{ "rx_align_errors" }, | 
 | 6442 | 	{ "rx_mac_ctrl_packets" }, | 
 | 6443 | 	{ "rx_pause_packets" }, | 
 | 6444 | 	{ "rx_bcast_packets" }, | 
 | 6445 | 	{ "rx_mcast_packets" }, | 
 | 6446 | 	{ "rx_ucast_packets" }, | 
 | 6447 | 	{ "rx_64_or_less_octet_packets" }, | 
 | 6448 | 	{ "rx_65_to_127_octet_packets" }, | 
 | 6449 | 	{ "rx_128_to_255_octet_packets" }, | 
 | 6450 | 	{ "rx_256_to_511_octet_packets" }, | 
 | 6451 | 	{ "rx_512_to_1023_octet_packets" }, | 
 | 6452 | 	{ "rx_1024_to_1522_octet_packets" }, | 
 | 6453 |  | 
 | 6454 | 	{ "tx_lo_priority_octets" }, | 
 | 6455 | 	{ "tx_hi_priority_octets" }, | 
 | 6456 | 	{ "tx_late_collisions" }, | 
 | 6457 | 	{ "tx_pause_packets" }, | 
 | 6458 | 	{ "tx_bcast_packets" }, | 
 | 6459 | 	{ "tx_mcast_packets" }, | 
 | 6460 | 	{ "tx_ucast_packets" }, | 
 | 6461 | 	{ "tx_deferred" }, | 
 | 6462 | 	{ "tx_total_collisions" }, | 
 | 6463 | 	{ "tx_excessive_collisions" }, | 
 | 6464 | 	{ "tx_single_collisions" }, | 
 | 6465 | 	{ "tx_mult_collisions" }, | 
 | 6466 |  | 
 | 6467 | 	{ "rx_discards" }, | 
 | 6468 | 	{ "tx_discards" }, | 
 | 6469 | }; | 
 | 6470 |  | 
 | 6471 | /** | 
 | 6472 |  * netdev_get_strings - get statistics identity strings | 
 | 6473 |  * @dev:	Network device. | 
 | 6474 |  * @stringset:	String set identifier. | 
 | 6475 |  * @buf:	Buffer to store the strings. | 
 | 6476 |  * | 
 | 6477 |  * This procedure returns the strings used to identify the statistics. | 
 | 6478 |  */ | 
 | 6479 | static void netdev_get_strings(struct net_device *dev, u32 stringset, u8 *buf) | 
 | 6480 | { | 
 | 6481 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6482 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6483 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 6484 |  | 
 | 6485 | 	if (ETH_SS_STATS == stringset) | 
 | 6486 | 		memcpy(buf, ðtool_stats_keys, | 
 | 6487 | 			ETH_GSTRING_LEN * hw->mib_cnt); | 
 | 6488 | } | 
 | 6489 |  | 
 | 6490 | /** | 
 | 6491 |  * netdev_get_sset_count - get statistics size | 
 | 6492 |  * @dev:	Network device. | 
 | 6493 |  * @sset:	The statistics set number. | 
 | 6494 |  * | 
 | 6495 |  * This function returns the size of the statistics to be reported. | 
 | 6496 |  * | 
 | 6497 |  * Return size of the statistics to be reported. | 
 | 6498 |  */ | 
 | 6499 | static int netdev_get_sset_count(struct net_device *dev, int sset) | 
 | 6500 | { | 
 | 6501 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6502 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6503 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 6504 |  | 
 | 6505 | 	switch (sset) { | 
 | 6506 | 	case ETH_SS_STATS: | 
 | 6507 | 		return hw->mib_cnt; | 
 | 6508 | 	default: | 
 | 6509 | 		return -EOPNOTSUPP; | 
 | 6510 | 	} | 
 | 6511 | } | 
 | 6512 |  | 
 | 6513 | /** | 
 | 6514 |  * netdev_get_ethtool_stats - get network device statistics | 
 | 6515 |  * @dev:	Network device. | 
 | 6516 |  * @stats:	Ethtool statistics data structure. | 
 | 6517 |  * @data:	Buffer to store the statistics. | 
 | 6518 |  * | 
 | 6519 |  * This procedure returns the statistics. | 
 | 6520 |  */ | 
 | 6521 | static void netdev_get_ethtool_stats(struct net_device *dev, | 
 | 6522 | 	struct ethtool_stats *stats, u64 *data) | 
 | 6523 | { | 
 | 6524 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6525 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6526 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 6527 | 	struct ksz_port *port = &priv->port; | 
 | 6528 | 	int n_stats = stats->n_stats; | 
 | 6529 | 	int i; | 
 | 6530 | 	int n; | 
 | 6531 | 	int p; | 
 | 6532 | 	int rc; | 
 | 6533 | 	u64 counter[TOTAL_PORT_COUNTER_NUM]; | 
 | 6534 |  | 
 | 6535 | 	mutex_lock(&hw_priv->lock); | 
 | 6536 | 	n = SWITCH_PORT_NUM; | 
 | 6537 | 	for (i = 0, p = port->first_port; i < port->mib_port_cnt; i++, p++) { | 
 | 6538 | 		if (media_connected == hw->port_mib[p].state) { | 
 | 6539 | 			hw_priv->counter[p].read = 1; | 
 | 6540 |  | 
 | 6541 | 			/* Remember first port that requests read. */ | 
 | 6542 | 			if (n == SWITCH_PORT_NUM) | 
 | 6543 | 				n = p; | 
 | 6544 | 		} | 
 | 6545 | 	} | 
 | 6546 | 	mutex_unlock(&hw_priv->lock); | 
 | 6547 |  | 
 | 6548 | 	if (n < SWITCH_PORT_NUM) | 
 | 6549 | 		schedule_work(&hw_priv->mib_read); | 
 | 6550 |  | 
 | 6551 | 	if (1 == port->mib_port_cnt && n < SWITCH_PORT_NUM) { | 
 | 6552 | 		p = n; | 
 | 6553 | 		rc = wait_event_interruptible_timeout( | 
 | 6554 | 			hw_priv->counter[p].counter, | 
 | 6555 | 			2 == hw_priv->counter[p].read, | 
 | 6556 | 			HZ * 1); | 
 | 6557 | 	} else | 
 | 6558 | 		for (i = 0, p = n; i < port->mib_port_cnt - n; i++, p++) { | 
 | 6559 | 			if (0 == i) { | 
 | 6560 | 				rc = wait_event_interruptible_timeout( | 
 | 6561 | 					hw_priv->counter[p].counter, | 
 | 6562 | 					2 == hw_priv->counter[p].read, | 
 | 6563 | 					HZ * 2); | 
 | 6564 | 			} else if (hw->port_mib[p].cnt_ptr) { | 
 | 6565 | 				rc = wait_event_interruptible_timeout( | 
 | 6566 | 					hw_priv->counter[p].counter, | 
 | 6567 | 					2 == hw_priv->counter[p].read, | 
 | 6568 | 					HZ * 1); | 
 | 6569 | 			} | 
 | 6570 | 		} | 
 | 6571 |  | 
 | 6572 | 	get_mib_counters(hw, port->first_port, port->mib_port_cnt, counter); | 
 | 6573 | 	n = hw->mib_cnt; | 
 | 6574 | 	if (n > n_stats) | 
 | 6575 | 		n = n_stats; | 
 | 6576 | 	n_stats -= n; | 
 | 6577 | 	for (i = 0; i < n; i++) | 
 | 6578 | 		*data++ = counter[i]; | 
 | 6579 | } | 
 | 6580 |  | 
 | 6581 | /** | 
| Michał Mirosław | e6a4641 | 2011-04-10 03:13:21 +0000 | [diff] [blame] | 6582 |  * netdev_set_features - set receive checksum support | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6583 |  * @dev:	Network device. | 
| Michał Mirosław | e6a4641 | 2011-04-10 03:13:21 +0000 | [diff] [blame] | 6584 |  * @features:	New device features (offloads). | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6585 |  * | 
 | 6586 |  * This function sets receive checksum support setting. | 
 | 6587 |  * | 
 | 6588 |  * Return 0 if successful; otherwise an error code. | 
 | 6589 |  */ | 
| Michał Mirosław | e6a4641 | 2011-04-10 03:13:21 +0000 | [diff] [blame] | 6590 | static int netdev_set_features(struct net_device *dev, u32 features) | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6591 | { | 
 | 6592 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6593 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6594 | 	struct ksz_hw *hw = &hw_priv->hw; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6595 |  | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6596 | 	mutex_lock(&hw_priv->lock); | 
| Michał Mirosław | e6a4641 | 2011-04-10 03:13:21 +0000 | [diff] [blame] | 6597 |  | 
 | 6598 | 	/* see note in hw_setup() */ | 
 | 6599 | 	if (features & NETIF_F_RXCSUM) | 
 | 6600 | 		hw->rx_cfg |= DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP; | 
 | 6601 | 	else | 
 | 6602 | 		hw->rx_cfg &= ~(DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP); | 
 | 6603 |  | 
 | 6604 | 	if (hw->enabled) | 
 | 6605 | 		writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL); | 
 | 6606 |  | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6607 | 	mutex_unlock(&hw_priv->lock); | 
| Michał Mirosław | e6a4641 | 2011-04-10 03:13:21 +0000 | [diff] [blame] | 6608 |  | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6609 | 	return 0; | 
 | 6610 | } | 
 | 6611 |  | 
 | 6612 | static struct ethtool_ops netdev_ethtool_ops = { | 
 | 6613 | 	.get_settings		= netdev_get_settings, | 
 | 6614 | 	.set_settings		= netdev_set_settings, | 
 | 6615 | 	.nway_reset		= netdev_nway_reset, | 
 | 6616 | 	.get_link		= netdev_get_link, | 
 | 6617 | 	.get_drvinfo		= netdev_get_drvinfo, | 
 | 6618 | 	.get_regs_len		= netdev_get_regs_len, | 
 | 6619 | 	.get_regs		= netdev_get_regs, | 
 | 6620 | 	.get_wol		= netdev_get_wol, | 
 | 6621 | 	.set_wol		= netdev_set_wol, | 
 | 6622 | 	.get_msglevel		= netdev_get_msglevel, | 
 | 6623 | 	.set_msglevel		= netdev_set_msglevel, | 
 | 6624 | 	.get_eeprom_len		= netdev_get_eeprom_len, | 
 | 6625 | 	.get_eeprom		= netdev_get_eeprom, | 
 | 6626 | 	.set_eeprom		= netdev_set_eeprom, | 
 | 6627 | 	.get_pauseparam		= netdev_get_pauseparam, | 
 | 6628 | 	.set_pauseparam		= netdev_set_pauseparam, | 
 | 6629 | 	.get_ringparam		= netdev_get_ringparam, | 
 | 6630 | 	.get_strings		= netdev_get_strings, | 
 | 6631 | 	.get_sset_count		= netdev_get_sset_count, | 
 | 6632 | 	.get_ethtool_stats	= netdev_get_ethtool_stats, | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6633 | }; | 
 | 6634 |  | 
 | 6635 | /* | 
 | 6636 |  * Hardware monitoring | 
 | 6637 |  */ | 
 | 6638 |  | 
 | 6639 | static void update_link(struct net_device *dev, struct dev_priv *priv, | 
 | 6640 | 	struct ksz_port *port) | 
 | 6641 | { | 
 | 6642 | 	if (priv->media_state != port->linked->state) { | 
 | 6643 | 		priv->media_state = port->linked->state; | 
| Joe Perches | 0dc7d2b | 2010-02-27 14:43:51 +0000 | [diff] [blame] | 6644 | 		if (netif_running(dev)) | 
 | 6645 | 			set_media_state(dev, media_connected); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6646 | 	} | 
 | 6647 | } | 
 | 6648 |  | 
 | 6649 | static void mib_read_work(struct work_struct *work) | 
 | 6650 | { | 
 | 6651 | 	struct dev_info *hw_priv = | 
 | 6652 | 		container_of(work, struct dev_info, mib_read); | 
 | 6653 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 6654 | 	struct ksz_port_mib *mib; | 
 | 6655 | 	int i; | 
 | 6656 |  | 
 | 6657 | 	next_jiffies = jiffies; | 
 | 6658 | 	for (i = 0; i < hw->mib_port_cnt; i++) { | 
 | 6659 | 		mib = &hw->port_mib[i]; | 
 | 6660 |  | 
 | 6661 | 		/* Reading MIB counters or requested to read. */ | 
 | 6662 | 		if (mib->cnt_ptr || 1 == hw_priv->counter[i].read) { | 
 | 6663 |  | 
 | 6664 | 			/* Need to process receive interrupt. */ | 
 | 6665 | 			if (port_r_cnt(hw, i)) | 
 | 6666 | 				break; | 
 | 6667 | 			hw_priv->counter[i].read = 0; | 
 | 6668 |  | 
 | 6669 | 			/* Finish reading counters. */ | 
 | 6670 | 			if (0 == mib->cnt_ptr) { | 
 | 6671 | 				hw_priv->counter[i].read = 2; | 
 | 6672 | 				wake_up_interruptible( | 
 | 6673 | 					&hw_priv->counter[i].counter); | 
 | 6674 | 			} | 
 | 6675 | 		} else if (jiffies >= hw_priv->counter[i].time) { | 
 | 6676 | 			/* Only read MIB counters when the port is connected. */ | 
 | 6677 | 			if (media_connected == mib->state) | 
 | 6678 | 				hw_priv->counter[i].read = 1; | 
 | 6679 | 			next_jiffies += HZ * 1 * hw->mib_port_cnt; | 
 | 6680 | 			hw_priv->counter[i].time = next_jiffies; | 
 | 6681 |  | 
 | 6682 | 		/* Port is just disconnected. */ | 
 | 6683 | 		} else if (mib->link_down) { | 
 | 6684 | 			mib->link_down = 0; | 
 | 6685 |  | 
 | 6686 | 			/* Read counters one last time after link is lost. */ | 
 | 6687 | 			hw_priv->counter[i].read = 1; | 
 | 6688 | 		} | 
 | 6689 | 	} | 
 | 6690 | } | 
 | 6691 |  | 
 | 6692 | static void mib_monitor(unsigned long ptr) | 
 | 6693 | { | 
 | 6694 | 	struct dev_info *hw_priv = (struct dev_info *) ptr; | 
 | 6695 |  | 
 | 6696 | 	mib_read_work(&hw_priv->mib_read); | 
 | 6697 |  | 
 | 6698 | 	/* This is used to verify Wake-on-LAN is working. */ | 
 | 6699 | 	if (hw_priv->pme_wait) { | 
 | 6700 | 		if (hw_priv->pme_wait <= jiffies) { | 
 | 6701 | 			hw_clr_wol_pme_status(&hw_priv->hw); | 
 | 6702 | 			hw_priv->pme_wait = 0; | 
 | 6703 | 		} | 
 | 6704 | 	} else if (hw_chk_wol_pme_status(&hw_priv->hw)) { | 
 | 6705 |  | 
 | 6706 | 		/* PME is asserted.  Wait 2 seconds to clear it. */ | 
 | 6707 | 		hw_priv->pme_wait = jiffies + HZ * 2; | 
 | 6708 | 	} | 
 | 6709 |  | 
 | 6710 | 	ksz_update_timer(&hw_priv->mib_timer_info); | 
 | 6711 | } | 
 | 6712 |  | 
 | 6713 | /** | 
 | 6714 |  * dev_monitor - periodic monitoring | 
 | 6715 |  * @ptr:	Network device pointer. | 
 | 6716 |  * | 
 | 6717 |  * This routine is run in a kernel timer to monitor the network device. | 
 | 6718 |  */ | 
 | 6719 | static void dev_monitor(unsigned long ptr) | 
 | 6720 | { | 
 | 6721 | 	struct net_device *dev = (struct net_device *) ptr; | 
 | 6722 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6723 | 	struct dev_info *hw_priv = priv->adapter; | 
 | 6724 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 6725 | 	struct ksz_port *port = &priv->port; | 
 | 6726 |  | 
 | 6727 | 	if (!(hw->features & LINK_INT_WORKING)) | 
 | 6728 | 		port_get_link_speed(port); | 
 | 6729 | 	update_link(dev, priv, port); | 
 | 6730 |  | 
 | 6731 | 	ksz_update_timer(&priv->monitor_timer_info); | 
 | 6732 | } | 
 | 6733 |  | 
 | 6734 | /* | 
 | 6735 |  * Linux network device interface functions | 
 | 6736 |  */ | 
 | 6737 |  | 
 | 6738 | /* Driver exported variables */ | 
 | 6739 |  | 
 | 6740 | static int msg_enable; | 
 | 6741 |  | 
 | 6742 | static char *macaddr = ":"; | 
 | 6743 | static char *mac1addr = ":"; | 
 | 6744 |  | 
 | 6745 | /* | 
 | 6746 |  * This enables multiple network device mode for KSZ8842, which contains a | 
 | 6747 |  * switch with two physical ports.  Some users like to take control of the | 
 | 6748 |  * ports for running Spanning Tree Protocol.  The driver will create an | 
 | 6749 |  * additional eth? device for the other port. | 
 | 6750 |  * | 
 | 6751 |  * Some limitations are the network devices cannot have different MTU and | 
 | 6752 |  * multicast hash tables. | 
 | 6753 |  */ | 
 | 6754 | static int multi_dev; | 
 | 6755 |  | 
 | 6756 | /* | 
 | 6757 |  * As most users select multiple network device mode to use Spanning Tree | 
 | 6758 |  * Protocol, this enables a feature in which most unicast and multicast packets | 
 | 6759 |  * are forwarded inside the switch and not passed to the host.  Only packets | 
 | 6760 |  * that need the host's attention are passed to it.  This prevents the host | 
 | 6761 |  * wasting CPU time to examine each and every incoming packets and do the | 
 | 6762 |  * forwarding itself. | 
 | 6763 |  * | 
 | 6764 |  * As the hack requires the private bridge header, the driver cannot compile | 
 | 6765 |  * with just the kernel headers. | 
 | 6766 |  * | 
 | 6767 |  * Enabling STP support also turns on multiple network device mode. | 
 | 6768 |  */ | 
 | 6769 | static int stp; | 
 | 6770 |  | 
 | 6771 | /* | 
 | 6772 |  * This enables fast aging in the KSZ8842 switch.  Not sure what situation | 
 | 6773 |  * needs that.  However, fast aging is used to flush the dynamic MAC table when | 
 | 6774 |  * STP suport is enabled. | 
 | 6775 |  */ | 
 | 6776 | static int fast_aging; | 
 | 6777 |  | 
 | 6778 | /** | 
| Uwe Kleine-König | 421f91d | 2010-06-11 12:17:00 +0200 | [diff] [blame] | 6779 |  * netdev_init - initialize network device. | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6780 |  * @dev:	Network device. | 
 | 6781 |  * | 
 | 6782 |  * This function initializes the network device. | 
 | 6783 |  * | 
 | 6784 |  * Return 0 if successful; otherwise an error code indicating failure. | 
 | 6785 |  */ | 
 | 6786 | static int __init netdev_init(struct net_device *dev) | 
 | 6787 | { | 
 | 6788 | 	struct dev_priv *priv = netdev_priv(dev); | 
 | 6789 |  | 
 | 6790 | 	/* 500 ms timeout */ | 
 | 6791 | 	ksz_init_timer(&priv->monitor_timer_info, 500 * HZ / 1000, | 
 | 6792 | 		dev_monitor, dev); | 
 | 6793 |  | 
 | 6794 | 	/* 500 ms timeout */ | 
 | 6795 | 	dev->watchdog_timeo = HZ / 2; | 
 | 6796 |  | 
| Michał Mirosław | e6a4641 | 2011-04-10 03:13:21 +0000 | [diff] [blame] | 6797 | 	dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_RXCSUM; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6798 |  | 
 | 6799 | 	/* | 
 | 6800 | 	 * Hardware does not really support IPv6 checksum generation, but | 
| Michał Mirosław | e6a4641 | 2011-04-10 03:13:21 +0000 | [diff] [blame] | 6801 | 	 * driver actually runs faster with this on. | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6802 | 	 */ | 
| Michał Mirosław | e6a4641 | 2011-04-10 03:13:21 +0000 | [diff] [blame] | 6803 | 	dev->hw_features |= NETIF_F_IPV6_CSUM; | 
 | 6804 |  | 
 | 6805 | 	dev->features |= dev->hw_features; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6806 |  | 
 | 6807 | 	sema_init(&priv->proc_sem, 1); | 
 | 6808 |  | 
 | 6809 | 	priv->mii_if.phy_id_mask = 0x1; | 
 | 6810 | 	priv->mii_if.reg_num_mask = 0x7; | 
 | 6811 | 	priv->mii_if.dev = dev; | 
 | 6812 | 	priv->mii_if.mdio_read = mdio_read; | 
 | 6813 | 	priv->mii_if.mdio_write = mdio_write; | 
 | 6814 | 	priv->mii_if.phy_id = priv->port.first_port + 1; | 
 | 6815 |  | 
 | 6816 | 	priv->msg_enable = netif_msg_init(msg_enable, | 
 | 6817 | 		(NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)); | 
 | 6818 |  | 
 | 6819 | 	return 0; | 
 | 6820 | } | 
 | 6821 |  | 
 | 6822 | static const struct net_device_ops netdev_ops = { | 
 | 6823 | 	.ndo_init		= netdev_init, | 
 | 6824 | 	.ndo_open		= netdev_open, | 
 | 6825 | 	.ndo_stop		= netdev_close, | 
 | 6826 | 	.ndo_get_stats		= netdev_query_statistics, | 
 | 6827 | 	.ndo_start_xmit		= netdev_tx, | 
 | 6828 | 	.ndo_tx_timeout		= netdev_tx_timeout, | 
 | 6829 | 	.ndo_change_mtu		= netdev_change_mtu, | 
| Michał Mirosław | e6a4641 | 2011-04-10 03:13:21 +0000 | [diff] [blame] | 6830 | 	.ndo_set_features	= netdev_set_features, | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6831 | 	.ndo_set_mac_address	= netdev_set_mac_address, | 
| Denis Kirjanov | 96ed741 | 2010-05-31 00:26:21 +0000 | [diff] [blame] | 6832 | 	.ndo_validate_addr	= eth_validate_addr, | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6833 | 	.ndo_do_ioctl		= netdev_ioctl, | 
 | 6834 | 	.ndo_set_rx_mode	= netdev_set_rx_mode, | 
 | 6835 | #ifdef CONFIG_NET_POLL_CONTROLLER | 
 | 6836 | 	.ndo_poll_controller	= netdev_netpoll, | 
 | 6837 | #endif | 
 | 6838 | }; | 
 | 6839 |  | 
 | 6840 | static void netdev_free(struct net_device *dev) | 
 | 6841 | { | 
 | 6842 | 	if (dev->watchdog_timeo) | 
 | 6843 | 		unregister_netdev(dev); | 
 | 6844 |  | 
 | 6845 | 	free_netdev(dev); | 
 | 6846 | } | 
 | 6847 |  | 
 | 6848 | struct platform_info { | 
 | 6849 | 	struct dev_info dev_info; | 
 | 6850 | 	struct net_device *netdev[SWITCH_PORT_NUM]; | 
 | 6851 | }; | 
 | 6852 |  | 
 | 6853 | static int net_device_present; | 
 | 6854 |  | 
 | 6855 | static void get_mac_addr(struct dev_info *hw_priv, u8 *macaddr, int port) | 
 | 6856 | { | 
 | 6857 | 	int i; | 
 | 6858 | 	int j; | 
 | 6859 | 	int got_num; | 
 | 6860 | 	int num; | 
 | 6861 |  | 
 | 6862 | 	i = j = num = got_num = 0; | 
 | 6863 | 	while (j < MAC_ADDR_LEN) { | 
 | 6864 | 		if (macaddr[i]) { | 
| Andy Shevchenko | 5c4ac8c | 2010-07-23 03:18:07 +0000 | [diff] [blame] | 6865 | 			int digit; | 
 | 6866 |  | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6867 | 			got_num = 1; | 
| Andy Shevchenko | 5c4ac8c | 2010-07-23 03:18:07 +0000 | [diff] [blame] | 6868 | 			digit = hex_to_bin(macaddr[i]); | 
 | 6869 | 			if (digit >= 0) | 
 | 6870 | 				num = num * 16 + digit; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6871 | 			else if (':' == macaddr[i]) | 
 | 6872 | 				got_num = 2; | 
 | 6873 | 			else | 
 | 6874 | 				break; | 
 | 6875 | 		} else if (got_num) | 
 | 6876 | 			got_num = 2; | 
 | 6877 | 		else | 
 | 6878 | 			break; | 
 | 6879 | 		if (2 == got_num) { | 
 | 6880 | 			if (MAIN_PORT == port) { | 
 | 6881 | 				hw_priv->hw.override_addr[j++] = (u8) num; | 
 | 6882 | 				hw_priv->hw.override_addr[5] += | 
 | 6883 | 					hw_priv->hw.id; | 
 | 6884 | 			} else { | 
 | 6885 | 				hw_priv->hw.ksz_switch->other_addr[j++] = | 
 | 6886 | 					(u8) num; | 
 | 6887 | 				hw_priv->hw.ksz_switch->other_addr[5] += | 
 | 6888 | 					hw_priv->hw.id; | 
 | 6889 | 			} | 
 | 6890 | 			num = got_num = 0; | 
 | 6891 | 		} | 
 | 6892 | 		i++; | 
 | 6893 | 	} | 
 | 6894 | 	if (MAC_ADDR_LEN == j) { | 
 | 6895 | 		if (MAIN_PORT == port) | 
 | 6896 | 			hw_priv->hw.mac_override = 1; | 
 | 6897 | 	} | 
 | 6898 | } | 
 | 6899 |  | 
 | 6900 | #define KS884X_DMA_MASK			(~0x0UL) | 
 | 6901 |  | 
 | 6902 | static void read_other_addr(struct ksz_hw *hw) | 
 | 6903 | { | 
 | 6904 | 	int i; | 
 | 6905 | 	u16 data[3]; | 
 | 6906 | 	struct ksz_switch *sw = hw->ksz_switch; | 
 | 6907 |  | 
 | 6908 | 	for (i = 0; i < 3; i++) | 
 | 6909 | 		data[i] = eeprom_read(hw, i + EEPROM_DATA_OTHER_MAC_ADDR); | 
 | 6910 | 	if ((data[0] || data[1] || data[2]) && data[0] != 0xffff) { | 
 | 6911 | 		sw->other_addr[5] = (u8) data[0]; | 
 | 6912 | 		sw->other_addr[4] = (u8)(data[0] >> 8); | 
 | 6913 | 		sw->other_addr[3] = (u8) data[1]; | 
 | 6914 | 		sw->other_addr[2] = (u8)(data[1] >> 8); | 
 | 6915 | 		sw->other_addr[1] = (u8) data[2]; | 
 | 6916 | 		sw->other_addr[0] = (u8)(data[2] >> 8); | 
 | 6917 | 	} | 
 | 6918 | } | 
 | 6919 |  | 
 | 6920 | #ifndef PCI_VENDOR_ID_MICREL_KS | 
 | 6921 | #define PCI_VENDOR_ID_MICREL_KS		0x16c6 | 
 | 6922 | #endif | 
 | 6923 |  | 
| Sedat Dilek | cbad832 | 2011-01-03 11:06:58 +0000 | [diff] [blame] | 6924 | static int __devinit pcidev_init(struct pci_dev *pdev, | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6925 | 	const struct pci_device_id *id) | 
 | 6926 | { | 
 | 6927 | 	struct net_device *dev; | 
 | 6928 | 	struct dev_priv *priv; | 
 | 6929 | 	struct dev_info *hw_priv; | 
 | 6930 | 	struct ksz_hw *hw; | 
 | 6931 | 	struct platform_info *info; | 
 | 6932 | 	struct ksz_port *port; | 
 | 6933 | 	unsigned long reg_base; | 
 | 6934 | 	unsigned long reg_len; | 
 | 6935 | 	int cnt; | 
 | 6936 | 	int i; | 
 | 6937 | 	int mib_port_count; | 
 | 6938 | 	int pi; | 
 | 6939 | 	int port_count; | 
 | 6940 | 	int result; | 
| Joe Perches | 0dc7d2b | 2010-02-27 14:43:51 +0000 | [diff] [blame] | 6941 | 	char banner[sizeof(version)]; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6942 | 	struct ksz_switch *sw = NULL; | 
 | 6943 |  | 
 | 6944 | 	result = pci_enable_device(pdev); | 
 | 6945 | 	if (result) | 
 | 6946 | 		return result; | 
 | 6947 |  | 
 | 6948 | 	result = -ENODEV; | 
 | 6949 |  | 
 | 6950 | 	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) || | 
 | 6951 | 			pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) | 
 | 6952 | 		return result; | 
 | 6953 |  | 
 | 6954 | 	reg_base = pci_resource_start(pdev, 0); | 
 | 6955 | 	reg_len = pci_resource_len(pdev, 0); | 
 | 6956 | 	if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) | 
 | 6957 | 		return result; | 
 | 6958 |  | 
 | 6959 | 	if (!request_mem_region(reg_base, reg_len, DRV_NAME)) | 
 | 6960 | 		return result; | 
 | 6961 | 	pci_set_master(pdev); | 
 | 6962 |  | 
 | 6963 | 	result = -ENOMEM; | 
 | 6964 |  | 
| Joe Perches | 0dc7d2b | 2010-02-27 14:43:51 +0000 | [diff] [blame] | 6965 | 	info = kzalloc(sizeof(struct platform_info), GFP_KERNEL); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6966 | 	if (!info) | 
 | 6967 | 		goto pcidev_init_dev_err; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6968 |  | 
 | 6969 | 	hw_priv = &info->dev_info; | 
 | 6970 | 	hw_priv->pdev = pdev; | 
 | 6971 |  | 
 | 6972 | 	hw = &hw_priv->hw; | 
 | 6973 |  | 
 | 6974 | 	hw->io = ioremap(reg_base, reg_len); | 
 | 6975 | 	if (!hw->io) | 
 | 6976 | 		goto pcidev_init_io_err; | 
 | 6977 |  | 
 | 6978 | 	cnt = hw_init(hw); | 
 | 6979 | 	if (!cnt) { | 
 | 6980 | 		if (msg_enable & NETIF_MSG_PROBE) | 
| Joe Perches | 0dc7d2b | 2010-02-27 14:43:51 +0000 | [diff] [blame] | 6981 | 			pr_alert("chip not detected\n"); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6982 | 		result = -ENODEV; | 
 | 6983 | 		goto pcidev_init_alloc_err; | 
 | 6984 | 	} | 
 | 6985 |  | 
| Joe Perches | 0dc7d2b | 2010-02-27 14:43:51 +0000 | [diff] [blame] | 6986 | 	snprintf(banner, sizeof(banner), "%s", version); | 
 | 6987 | 	banner[13] = cnt + '0';		/* Replace x in "Micrel KSZ884x" */ | 
 | 6988 | 	dev_info(&hw_priv->pdev->dev, "%s\n", banner); | 
 | 6989 | 	dev_dbg(&hw_priv->pdev->dev, "Mem = %p; IRQ = %d\n", hw->io, pdev->irq); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 6990 |  | 
 | 6991 | 	/* Assume device is KSZ8841. */ | 
 | 6992 | 	hw->dev_count = 1; | 
 | 6993 | 	port_count = 1; | 
 | 6994 | 	mib_port_count = 1; | 
 | 6995 | 	hw->addr_list_size = 0; | 
 | 6996 | 	hw->mib_cnt = PORT_COUNTER_NUM; | 
 | 6997 | 	hw->mib_port_cnt = 1; | 
 | 6998 |  | 
 | 6999 | 	/* KSZ8842 has a switch with multiple ports. */ | 
 | 7000 | 	if (2 == cnt) { | 
 | 7001 | 		if (fast_aging) | 
 | 7002 | 			hw->overrides |= FAST_AGING; | 
 | 7003 |  | 
 | 7004 | 		hw->mib_cnt = TOTAL_PORT_COUNTER_NUM; | 
 | 7005 |  | 
 | 7006 | 		/* Multiple network device interfaces are required. */ | 
 | 7007 | 		if (multi_dev) { | 
 | 7008 | 			hw->dev_count = SWITCH_PORT_NUM; | 
 | 7009 | 			hw->addr_list_size = SWITCH_PORT_NUM - 1; | 
 | 7010 | 		} | 
 | 7011 |  | 
 | 7012 | 		/* Single network device has multiple ports. */ | 
 | 7013 | 		if (1 == hw->dev_count) { | 
 | 7014 | 			port_count = SWITCH_PORT_NUM; | 
 | 7015 | 			mib_port_count = SWITCH_PORT_NUM; | 
 | 7016 | 		} | 
 | 7017 | 		hw->mib_port_cnt = TOTAL_PORT_NUM; | 
| Julia Lawall | a05abcb | 2010-05-13 10:06:01 +0000 | [diff] [blame] | 7018 | 		hw->ksz_switch = kzalloc(sizeof(struct ksz_switch), GFP_KERNEL); | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 7019 | 		if (!hw->ksz_switch) | 
 | 7020 | 			goto pcidev_init_alloc_err; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 7021 |  | 
 | 7022 | 		sw = hw->ksz_switch; | 
 | 7023 | 	} | 
 | 7024 | 	for (i = 0; i < hw->mib_port_cnt; i++) | 
 | 7025 | 		hw->port_mib[i].mib_start = 0; | 
 | 7026 |  | 
 | 7027 | 	hw->parent = hw_priv; | 
 | 7028 |  | 
 | 7029 | 	/* Default MTU is 1500. */ | 
 | 7030 | 	hw_priv->mtu = (REGULAR_RX_BUF_SIZE + 3) & ~3; | 
 | 7031 |  | 
 | 7032 | 	if (ksz_alloc_mem(hw_priv)) | 
 | 7033 | 		goto pcidev_init_mem_err; | 
 | 7034 |  | 
 | 7035 | 	hw_priv->hw.id = net_device_present; | 
 | 7036 |  | 
 | 7037 | 	spin_lock_init(&hw_priv->hwlock); | 
 | 7038 | 	mutex_init(&hw_priv->lock); | 
 | 7039 |  | 
 | 7040 | 	/* tasklet is enabled. */ | 
 | 7041 | 	tasklet_init(&hw_priv->rx_tasklet, rx_proc_task, | 
 | 7042 | 		(unsigned long) hw_priv); | 
 | 7043 | 	tasklet_init(&hw_priv->tx_tasklet, tx_proc_task, | 
 | 7044 | 		(unsigned long) hw_priv); | 
 | 7045 |  | 
 | 7046 | 	/* tasklet_enable will decrement the atomic counter. */ | 
 | 7047 | 	tasklet_disable(&hw_priv->rx_tasklet); | 
 | 7048 | 	tasklet_disable(&hw_priv->tx_tasklet); | 
 | 7049 |  | 
 | 7050 | 	for (i = 0; i < TOTAL_PORT_NUM; i++) | 
 | 7051 | 		init_waitqueue_head(&hw_priv->counter[i].counter); | 
 | 7052 |  | 
 | 7053 | 	if (macaddr[0] != ':') | 
 | 7054 | 		get_mac_addr(hw_priv, macaddr, MAIN_PORT); | 
 | 7055 |  | 
 | 7056 | 	/* Read MAC address and initialize override address if not overrided. */ | 
 | 7057 | 	hw_read_addr(hw); | 
 | 7058 |  | 
 | 7059 | 	/* Multiple device interfaces mode requires a second MAC address. */ | 
 | 7060 | 	if (hw->dev_count > 1) { | 
 | 7061 | 		memcpy(sw->other_addr, hw->override_addr, MAC_ADDR_LEN); | 
 | 7062 | 		read_other_addr(hw); | 
 | 7063 | 		if (mac1addr[0] != ':') | 
 | 7064 | 			get_mac_addr(hw_priv, mac1addr, OTHER_PORT); | 
 | 7065 | 	} | 
 | 7066 |  | 
 | 7067 | 	hw_setup(hw); | 
 | 7068 | 	if (hw->ksz_switch) | 
 | 7069 | 		sw_setup(hw); | 
 | 7070 | 	else { | 
 | 7071 | 		hw_priv->wol_support = WOL_SUPPORT; | 
 | 7072 | 		hw_priv->wol_enable = 0; | 
 | 7073 | 	} | 
 | 7074 |  | 
 | 7075 | 	INIT_WORK(&hw_priv->mib_read, mib_read_work); | 
 | 7076 |  | 
 | 7077 | 	/* 500 ms timeout */ | 
 | 7078 | 	ksz_init_timer(&hw_priv->mib_timer_info, 500 * HZ / 1000, | 
 | 7079 | 		mib_monitor, hw_priv); | 
 | 7080 |  | 
 | 7081 | 	for (i = 0; i < hw->dev_count; i++) { | 
 | 7082 | 		dev = alloc_etherdev(sizeof(struct dev_priv)); | 
 | 7083 | 		if (!dev) | 
 | 7084 | 			goto pcidev_init_reg_err; | 
 | 7085 | 		info->netdev[i] = dev; | 
 | 7086 |  | 
 | 7087 | 		priv = netdev_priv(dev); | 
 | 7088 | 		priv->adapter = hw_priv; | 
 | 7089 | 		priv->id = net_device_present++; | 
 | 7090 |  | 
 | 7091 | 		port = &priv->port; | 
 | 7092 | 		port->port_cnt = port_count; | 
 | 7093 | 		port->mib_port_cnt = mib_port_count; | 
 | 7094 | 		port->first_port = i; | 
 | 7095 | 		port->flow_ctrl = PHY_FLOW_CTRL; | 
 | 7096 |  | 
 | 7097 | 		port->hw = hw; | 
 | 7098 | 		port->linked = &hw->port_info[port->first_port]; | 
 | 7099 |  | 
 | 7100 | 		for (cnt = 0, pi = i; cnt < port_count; cnt++, pi++) { | 
 | 7101 | 			hw->port_info[pi].port_id = pi; | 
 | 7102 | 			hw->port_info[pi].pdev = dev; | 
 | 7103 | 			hw->port_info[pi].state = media_disconnected; | 
 | 7104 | 		} | 
 | 7105 |  | 
 | 7106 | 		dev->mem_start = (unsigned long) hw->io; | 
 | 7107 | 		dev->mem_end = dev->mem_start + reg_len - 1; | 
 | 7108 | 		dev->irq = pdev->irq; | 
 | 7109 | 		if (MAIN_PORT == i) | 
 | 7110 | 			memcpy(dev->dev_addr, hw_priv->hw.override_addr, | 
 | 7111 | 				MAC_ADDR_LEN); | 
 | 7112 | 		else { | 
 | 7113 | 			memcpy(dev->dev_addr, sw->other_addr, | 
 | 7114 | 				MAC_ADDR_LEN); | 
 | 7115 | 			if (!memcmp(sw->other_addr, hw->override_addr, | 
 | 7116 | 					MAC_ADDR_LEN)) | 
 | 7117 | 				dev->dev_addr[5] += port->first_port; | 
 | 7118 | 		} | 
 | 7119 |  | 
 | 7120 | 		dev->netdev_ops = &netdev_ops; | 
 | 7121 | 		SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); | 
 | 7122 | 		if (register_netdev(dev)) | 
 | 7123 | 			goto pcidev_init_reg_err; | 
 | 7124 | 		port_set_power_saving(port, true); | 
 | 7125 | 	} | 
 | 7126 |  | 
 | 7127 | 	pci_dev_get(hw_priv->pdev); | 
 | 7128 | 	pci_set_drvdata(pdev, info); | 
 | 7129 | 	return 0; | 
 | 7130 |  | 
 | 7131 | pcidev_init_reg_err: | 
 | 7132 | 	for (i = 0; i < hw->dev_count; i++) { | 
 | 7133 | 		if (info->netdev[i]) { | 
 | 7134 | 			netdev_free(info->netdev[i]); | 
 | 7135 | 			info->netdev[i] = NULL; | 
 | 7136 | 		} | 
 | 7137 | 	} | 
 | 7138 |  | 
 | 7139 | pcidev_init_mem_err: | 
 | 7140 | 	ksz_free_mem(hw_priv); | 
 | 7141 | 	kfree(hw->ksz_switch); | 
 | 7142 |  | 
 | 7143 | pcidev_init_alloc_err: | 
 | 7144 | 	iounmap(hw->io); | 
 | 7145 |  | 
 | 7146 | pcidev_init_io_err: | 
 | 7147 | 	kfree(info); | 
 | 7148 |  | 
 | 7149 | pcidev_init_dev_err: | 
 | 7150 | 	release_mem_region(reg_base, reg_len); | 
 | 7151 |  | 
 | 7152 | 	return result; | 
 | 7153 | } | 
 | 7154 |  | 
 | 7155 | static void pcidev_exit(struct pci_dev *pdev) | 
 | 7156 | { | 
 | 7157 | 	int i; | 
 | 7158 | 	struct platform_info *info = pci_get_drvdata(pdev); | 
 | 7159 | 	struct dev_info *hw_priv = &info->dev_info; | 
 | 7160 |  | 
 | 7161 | 	pci_set_drvdata(pdev, NULL); | 
 | 7162 |  | 
 | 7163 | 	release_mem_region(pci_resource_start(pdev, 0), | 
 | 7164 | 		pci_resource_len(pdev, 0)); | 
 | 7165 | 	for (i = 0; i < hw_priv->hw.dev_count; i++) { | 
 | 7166 | 		if (info->netdev[i]) | 
 | 7167 | 			netdev_free(info->netdev[i]); | 
 | 7168 | 	} | 
 | 7169 | 	if (hw_priv->hw.io) | 
 | 7170 | 		iounmap(hw_priv->hw.io); | 
 | 7171 | 	ksz_free_mem(hw_priv); | 
 | 7172 | 	kfree(hw_priv->hw.ksz_switch); | 
 | 7173 | 	pci_dev_put(hw_priv->pdev); | 
 | 7174 | 	kfree(info); | 
 | 7175 | } | 
 | 7176 |  | 
 | 7177 | #ifdef CONFIG_PM | 
 | 7178 | static int pcidev_resume(struct pci_dev *pdev) | 
 | 7179 | { | 
 | 7180 | 	int i; | 
 | 7181 | 	struct platform_info *info = pci_get_drvdata(pdev); | 
 | 7182 | 	struct dev_info *hw_priv = &info->dev_info; | 
 | 7183 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 7184 |  | 
 | 7185 | 	pci_set_power_state(pdev, PCI_D0); | 
 | 7186 | 	pci_restore_state(pdev); | 
 | 7187 | 	pci_enable_wake(pdev, PCI_D0, 0); | 
 | 7188 |  | 
 | 7189 | 	if (hw_priv->wol_enable) | 
 | 7190 | 		hw_cfg_wol_pme(hw, 0); | 
 | 7191 | 	for (i = 0; i < hw->dev_count; i++) { | 
 | 7192 | 		if (info->netdev[i]) { | 
 | 7193 | 			struct net_device *dev = info->netdev[i]; | 
 | 7194 |  | 
 | 7195 | 			if (netif_running(dev)) { | 
 | 7196 | 				netdev_open(dev); | 
 | 7197 | 				netif_device_attach(dev); | 
 | 7198 | 			} | 
 | 7199 | 		} | 
 | 7200 | 	} | 
 | 7201 | 	return 0; | 
 | 7202 | } | 
 | 7203 |  | 
 | 7204 | static int pcidev_suspend(struct pci_dev *pdev, pm_message_t state) | 
 | 7205 | { | 
 | 7206 | 	int i; | 
 | 7207 | 	struct platform_info *info = pci_get_drvdata(pdev); | 
 | 7208 | 	struct dev_info *hw_priv = &info->dev_info; | 
 | 7209 | 	struct ksz_hw *hw = &hw_priv->hw; | 
 | 7210 |  | 
 | 7211 | 	/* Need to find a way to retrieve the device IP address. */ | 
| Joe Perches | b6bc765 | 2010-12-21 02:16:08 -0800 | [diff] [blame] | 7212 | 	static const u8 net_addr[] = { 192, 168, 1, 1 }; | 
| Tristram Ha | 8ca86fd | 2010-02-08 11:36:53 +0000 | [diff] [blame] | 7213 |  | 
 | 7214 | 	for (i = 0; i < hw->dev_count; i++) { | 
 | 7215 | 		if (info->netdev[i]) { | 
 | 7216 | 			struct net_device *dev = info->netdev[i]; | 
 | 7217 |  | 
 | 7218 | 			if (netif_running(dev)) { | 
 | 7219 | 				netif_device_detach(dev); | 
 | 7220 | 				netdev_close(dev); | 
 | 7221 | 			} | 
 | 7222 | 		} | 
 | 7223 | 	} | 
 | 7224 | 	if (hw_priv->wol_enable) { | 
 | 7225 | 		hw_enable_wol(hw, hw_priv->wol_enable, net_addr); | 
 | 7226 | 		hw_cfg_wol_pme(hw, 1); | 
 | 7227 | 	} | 
 | 7228 |  | 
 | 7229 | 	pci_save_state(pdev); | 
 | 7230 | 	pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); | 
 | 7231 | 	pci_set_power_state(pdev, pci_choose_state(pdev, state)); | 
 | 7232 | 	return 0; | 
 | 7233 | } | 
 | 7234 | #endif | 
 | 7235 |  | 
 | 7236 | static char pcidev_name[] = "ksz884xp"; | 
 | 7237 |  | 
 | 7238 | static struct pci_device_id pcidev_table[] = { | 
 | 7239 | 	{ PCI_VENDOR_ID_MICREL_KS, 0x8841, | 
 | 7240 | 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | 
 | 7241 | 	{ PCI_VENDOR_ID_MICREL_KS, 0x8842, | 
 | 7242 | 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | 
 | 7243 | 	{ 0 } | 
 | 7244 | }; | 
 | 7245 |  | 
 | 7246 | MODULE_DEVICE_TABLE(pci, pcidev_table); | 
 | 7247 |  | 
 | 7248 | static struct pci_driver pci_device_driver = { | 
 | 7249 | #ifdef CONFIG_PM | 
 | 7250 | 	.suspend	= pcidev_suspend, | 
 | 7251 | 	.resume		= pcidev_resume, | 
 | 7252 | #endif | 
 | 7253 | 	.name		= pcidev_name, | 
 | 7254 | 	.id_table	= pcidev_table, | 
 | 7255 | 	.probe		= pcidev_init, | 
 | 7256 | 	.remove		= pcidev_exit | 
 | 7257 | }; | 
 | 7258 |  | 
 | 7259 | static int __init ksz884x_init_module(void) | 
 | 7260 | { | 
 | 7261 | 	return pci_register_driver(&pci_device_driver); | 
 | 7262 | } | 
 | 7263 |  | 
 | 7264 | static void __exit ksz884x_cleanup_module(void) | 
 | 7265 | { | 
 | 7266 | 	pci_unregister_driver(&pci_device_driver); | 
 | 7267 | } | 
 | 7268 |  | 
 | 7269 | module_init(ksz884x_init_module); | 
 | 7270 | module_exit(ksz884x_cleanup_module); | 
 | 7271 |  | 
 | 7272 | MODULE_DESCRIPTION("KSZ8841/2 PCI network driver"); | 
 | 7273 | MODULE_AUTHOR("Tristram Ha <Tristram.Ha@micrel.com>"); | 
 | 7274 | MODULE_LICENSE("GPL"); | 
 | 7275 |  | 
 | 7276 | module_param_named(message, msg_enable, int, 0); | 
 | 7277 | MODULE_PARM_DESC(message, "Message verbosity level (0=none, 31=all)"); | 
 | 7278 |  | 
 | 7279 | module_param(macaddr, charp, 0); | 
 | 7280 | module_param(mac1addr, charp, 0); | 
 | 7281 | module_param(fast_aging, int, 0); | 
 | 7282 | module_param(multi_dev, int, 0); | 
 | 7283 | module_param(stp, int, 0); | 
 | 7284 | MODULE_PARM_DESC(macaddr, "MAC address"); | 
 | 7285 | MODULE_PARM_DESC(mac1addr, "Second MAC address"); | 
 | 7286 | MODULE_PARM_DESC(fast_aging, "Fast aging"); | 
 | 7287 | MODULE_PARM_DESC(multi_dev, "Multiple device interfaces"); | 
 | 7288 | MODULE_PARM_DESC(stp, "STP support"); |