shpchp_hpc.c 37.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * Standard PCI Hot Plug Driver
 *
 * Copyright (C) 1995,2001 Compaq Computer Corporation
 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
 * Copyright (C) 2001 IBM Corp.
 * Copyright (C) 2003-2004 Intel Corporation
 *
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
 * NON INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
26
 * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com>
L
Linus Torvalds 已提交
27 28 29 30 31 32 33
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
A
Andrew Morton 已提交
34 35
#include <linux/interrupt.h>

L
Linus Torvalds 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
#include "shpchp.h"

#ifdef DEBUG
#define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)	/* On function entry */
#define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)	/* On function exit */
#define DBG_K_INFO             ((unsigned int)0x00000004)	/* Info messages */
#define DBG_K_ERROR            ((unsigned int)0x00000008)	/* Error messages */
#define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
#define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
/* Redefine this flagword to set debug level */
#define DEBUG_LEVEL            DBG_K_STANDARD

#define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];

#define DBG_PRINT( dbg_flags, args... )              \
	do {                                             \
	  if ( DEBUG_LEVEL & ( dbg_flags ) )             \
	  {                                              \
	    int len;                                     \
	    len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
		  __FILE__, __LINE__, __FUNCTION__ );    \
	    sprintf( __dbg_str_buf + len, args );        \
	    printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
	  }                                              \
	} while (0)

#define DBG_ENTER_ROUTINE	DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
#define DBG_LEAVE_ROUTINE	DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
#else
#define DEFINE_DBG_BUFFER
#define DBG_ENTER_ROUTINE
#define DBG_LEAVE_ROUTINE
#endif				/* DEBUG */

/* Slot Available Register I field definition */
#define SLOT_33MHZ		0x0000001f
#define SLOT_66MHZ_PCIX		0x00001f00
#define SLOT_100MHZ_PCIX	0x001f0000
#define SLOT_133MHZ_PCIX	0x1f000000

/* Slot Available Register II field definition */
#define SLOT_66MHZ		0x0000001f
#define SLOT_66MHZ_PCIX_266	0x00000f00
#define SLOT_100MHZ_PCIX_266	0x0000f000
#define SLOT_133MHZ_PCIX_266	0x000f0000
#define SLOT_66MHZ_PCIX_533	0x00f00000
#define SLOT_100MHZ_PCIX_533	0x0f000000
#define SLOT_133MHZ_PCIX_533	0xf0000000

/* Slot Configuration */
#define SLOT_NUM		0x0000001F
#define	FIRST_DEV_NUM		0x00001F00
#define PSN			0x07FF0000
#define	UPDOWN			0x20000000
#define	MRLSENSOR		0x40000000
#define ATTN_BUTTON		0x80000000

93 94 95 96 97 98 99 100 101 102 103
/*
 * Controller SERR-INT Register
 */
#define GLOBAL_INTR_MASK	(1 << 0)
#define GLOBAL_SERR_MASK	(1 << 1)
#define COMMAND_INTR_MASK	(1 << 2)
#define ARBITER_SERR_MASK	(1 << 3)
#define COMMAND_DETECTED	(1 << 16)
#define ARBITER_DETECTED	(1 << 17)
#define SERR_INTR_RSVDZ_MASK	0xfffc0000

104 105 106 107 108
/*
 * Logical Slot Register definitions
 */
#define SLOT_REG(i)		(SLOT1 + (4 * i))

109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
#define SLOT_STATE_SHIFT	(0)
#define SLOT_STATE_MASK		(3 << 0)
#define SLOT_STATE_PWRONLY	(1)
#define SLOT_STATE_ENABLED	(2)
#define SLOT_STATE_DISABLED	(3)
#define PWR_LED_STATE_SHIFT	(2)
#define PWR_LED_STATE_MASK	(3 << 2)
#define ATN_LED_STATE_SHIFT	(4)
#define ATN_LED_STATE_MASK	(3 << 4)
#define ATN_LED_STATE_ON	(1)
#define ATN_LED_STATE_BLINK	(2)
#define ATN_LED_STATE_OFF	(3)
#define POWER_FAULT		(1 << 6)
#define ATN_BUTTON		(1 << 7)
#define MRL_SENSOR		(1 << 8)
#define MHZ66_CAP		(1 << 9)
#define PRSNT_SHIFT		(10)
#define PRSNT_MASK		(3 << 10)
#define PCIX_CAP_SHIFT		(12)
#define PCIX_CAP_MASK_PI1	(3 << 12)
#define PCIX_CAP_MASK_PI2	(7 << 12)
#define PRSNT_CHANGE_DETECTED	(1 << 16)
#define ISO_PFAULT_DETECTED	(1 << 17)
#define BUTTON_PRESS_DETECTED	(1 << 18)
#define MRL_CHANGE_DETECTED	(1 << 19)
#define CON_PFAULT_DETECTED	(1 << 20)
#define PRSNT_CHANGE_INTR_MASK	(1 << 24)
#define ISO_PFAULT_INTR_MASK	(1 << 25)
#define BUTTON_PRESS_INTR_MASK	(1 << 26)
#define MRL_CHANGE_INTR_MASK	(1 << 27)
#define CON_PFAULT_INTR_MASK	(1 << 28)
#define MRL_CHANGE_SERR_MASK	(1 << 29)
#define CON_PFAULT_SERR_MASK	(1 << 30)
#define SLOT_REG_RSVDZ_MASK	(1 << 15) | (7 << 21)
L
Linus Torvalds 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221

/* SHPC 'write' operations/commands */

/* Slot operation - 0x00h to 0x3Fh */

#define NO_CHANGE		0x00

/* Slot state - Bits 0 & 1 of controller command register */
#define SET_SLOT_PWR		0x01	
#define SET_SLOT_ENABLE		0x02	
#define SET_SLOT_DISABLE	0x03	

/* Power indicator state - Bits 2 & 3 of controller command register*/
#define SET_PWR_ON		0x04	
#define SET_PWR_BLINK		0x08	
#define SET_PWR_OFF		0x0C	

/* Attention indicator state - Bits 4 & 5 of controller command register*/
#define SET_ATTN_ON		0x010	
#define SET_ATTN_BLINK		0x020
#define SET_ATTN_OFF		0x030	

/* Set bus speed/mode A - 0x40h to 0x47h */
#define SETA_PCI_33MHZ		0x40
#define SETA_PCI_66MHZ		0x41
#define SETA_PCIX_66MHZ		0x42
#define SETA_PCIX_100MHZ	0x43
#define SETA_PCIX_133MHZ	0x44
#define RESERV_1		0x45
#define RESERV_2		0x46
#define RESERV_3		0x47

/* Set bus speed/mode B - 0x50h to 0x5fh */
#define	SETB_PCI_33MHZ		0x50
#define SETB_PCI_66MHZ		0x51
#define SETB_PCIX_66MHZ_PM	0x52
#define SETB_PCIX_100MHZ_PM	0x53
#define SETB_PCIX_133MHZ_PM	0x54
#define SETB_PCIX_66MHZ_EM	0x55
#define SETB_PCIX_100MHZ_EM	0x56
#define SETB_PCIX_133MHZ_EM	0x57
#define SETB_PCIX_66MHZ_266	0x58
#define SETB_PCIX_100MHZ_266	0x59
#define SETB_PCIX_133MHZ_266	0x5a
#define SETB_PCIX_66MHZ_533	0x5b
#define SETB_PCIX_100MHZ_533	0x5c
#define SETB_PCIX_133MHZ_533	0x5d


/* Power-on all slots - 0x48h */
#define SET_PWR_ON_ALL		0x48

/* Enable all slots	- 0x49h */
#define SET_ENABLE_ALL		0x49

/*  SHPC controller command error code */
#define SWITCH_OPEN		0x1
#define INVALID_CMD		0x2
#define INVALID_SPEED_MODE	0x4

/* For accessing SHPC Working Register Set */
#define DWORD_SELECT		0x2
#define DWORD_DATA		0x4
#define BASE_OFFSET		0x0

/* Field Offset in Logical Slot Register - byte boundary */
#define SLOT_EVENT_LATCH	0x2
#define SLOT_SERR_INT_MASK	0x3

static spinlock_t hpc_event_lock;

DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
static struct php_ctlr_state_s *php_ctlr_list_head;	/* HPC state linked list */
static int ctlr_seq_num = 0;	/* Controller sequenc # */
static spinlock_t list_lock;

static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs);

static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
222
static int hpc_check_cmd_status(struct controller *ctrl);
L
Linus Torvalds 已提交
223

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
static inline u8 shpc_readb(struct controller *ctrl, int reg)
{
	return readb(ctrl->hpc_ctlr_handle->creg + reg);
}

static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val)
{
	writeb(val, ctrl->hpc_ctlr_handle->creg + reg);
}

static inline u16 shpc_readw(struct controller *ctrl, int reg)
{
	return readw(ctrl->hpc_ctlr_handle->creg + reg);
}

static inline void shpc_writew(struct controller *ctrl, int reg, u16 val)
{
	writew(val, ctrl->hpc_ctlr_handle->creg + reg);
}

static inline u32 shpc_readl(struct controller *ctrl, int reg)
{
	return readl(ctrl->hpc_ctlr_handle->creg + reg);
}

static inline void shpc_writel(struct controller *ctrl, int reg, u32 val)
{
	writel(val, ctrl->hpc_ctlr_handle->creg + reg);
}

static inline int shpc_indirect_read(struct controller *ctrl, int index,
				     u32 *value)
{
	int rc;
	u32 cap_offset = ctrl->cap_offset;
	struct pci_dev *pdev = ctrl->pci_dev;

	rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index);
	if (rc)
		return rc;
	return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value);
}

L
Linus Torvalds 已提交
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
/* This is the interrupt polling timeout function. */
static void int_poll_timeout(unsigned long lphp_ctlr)
{
    struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;

    DBG_ENTER_ROUTINE

    if ( !php_ctlr ) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return;
    }

    /* Poll for interrupt events.  regs == NULL => polling */
    shpc_isr( 0, (void *)php_ctlr, NULL );

    init_timer(&php_ctlr->int_poll_timer);
	if (!shpchp_poll_time)
		shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/

    start_int_poll_timer(php_ctlr, shpchp_poll_time);  
	
	return;
}

/* This function starts the interrupt polling timer. */
static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
{
    if (!php_ctlr) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return;
	}

    if ( ( seconds <= 0 ) || ( seconds > 60 ) )
        seconds = 2;            /* Clamp to sane value */

    php_ctlr->int_poll_timer.function = &int_poll_timeout;
    php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr;    /* Instance data */
    php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
    add_timer(&php_ctlr->int_poll_timer);

	return;
}

310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
static inline int shpc_wait_cmd(struct controller *ctrl)
{
	int retval = 0;
	unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000;
	unsigned long timeout = msecs_to_jiffies(timeout_msec);
	int rc = wait_event_interruptible_timeout(ctrl->queue,
						  !ctrl->cmd_busy, timeout);
	if (!rc) {
		retval = -EIO;
		err("Command not completed in %d msec\n", timeout_msec);
	} else if (rc < 0) {
		retval = -EINTR;
		info("Command was interrupted by a signal\n");
	}
	ctrl->cmd_busy = 0;

	return retval;
}

L
Linus Torvalds 已提交
329 330
static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
{
331
	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
332
	struct controller *ctrl = slot->ctrl;
L
Linus Torvalds 已提交
333 334 335 336 337 338
	u16 cmd_status;
	int retval = 0;
	u16 temp_word;
	int i;

	DBG_ENTER_ROUTINE 
339 340 341

	mutex_lock(&slot->ctrl->cmd_lock);

L
Linus Torvalds 已提交
342 343
	if (!php_ctlr) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
344 345
		retval = -EINVAL;
		goto out;
L
Linus Torvalds 已提交
346 347 348
	}

	for (i = 0; i < 10; i++) {
349
		cmd_status = shpc_readw(ctrl, CMD_STATUS);
L
Linus Torvalds 已提交
350 351 352 353 354 355 356
		
		if (!(cmd_status & 0x1))
			break;
		/*  Check every 0.1 sec for a total of 1 sec*/
		msleep(100);
	}

357
	cmd_status = shpc_readw(ctrl, CMD_STATUS);
L
Linus Torvalds 已提交
358 359 360 361
	
	if (cmd_status & 0x1) { 
		/* After 1 sec and and the controller is still busy */
		err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);
362 363
		retval = -EBUSY;
		goto out;
L
Linus Torvalds 已提交
364 365 366 367 368 369 370 371 372
	}

	++t_slot;
	temp_word =  (t_slot << 8) | (cmd & 0xFF);
	dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
	
	/* To make sure the Controller Busy bit is 0 before we send out the
	 * command. 
	 */
373
	slot->ctrl->cmd_busy = 1;
374
	shpc_writew(ctrl, CMD, temp_word);
L
Linus Torvalds 已提交
375

376 377 378 379
	/*
	 * Wait for command completion.
	 */
	retval = shpc_wait_cmd(slot->ctrl);
380 381 382 383 384 385 386 387 388 389 390
	if (retval)
		goto out;

	cmd_status = hpc_check_cmd_status(slot->ctrl);
	if (cmd_status) {
		err("%s: Failed to issued command 0x%x (error code = %d)\n",
		    __FUNCTION__, cmd, cmd_status);
		retval = -EIO;
	}
 out:
	mutex_unlock(&slot->ctrl->cmd_lock);
391

L
Linus Torvalds 已提交
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
	DBG_LEAVE_ROUTINE 
	return retval;
}

static int hpc_check_cmd_status(struct controller *ctrl)
{
	u16 cmd_status;
	int retval = 0;

	DBG_ENTER_ROUTINE 
	
	if (!ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

408
	cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
L
Linus Torvalds 已提交
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
	
	switch (cmd_status >> 1) {
	case 0:
		retval = 0;
		break;
	case 1:
		retval = SWITCH_OPEN;
		err("%s: Switch opened!\n", __FUNCTION__);
		break;
	case 2:
		retval = INVALID_CMD;
		err("%s: Invalid HPC command!\n", __FUNCTION__);
		break;
	case 4:
		retval = INVALID_SPEED_MODE;
		err("%s: Invalid bus speed/mode!\n", __FUNCTION__);
		break;
	default:
		retval = cmd_status;
	}

	DBG_LEAVE_ROUTINE 
	return retval;
}


static int hpc_get_attention_status(struct slot *slot, u8 *status)
{
437
	struct controller *ctrl = slot->ctrl;
L
Linus Torvalds 已提交
438
	u32 slot_reg;
439
	u8 state;
L
Linus Torvalds 已提交
440 441 442 443 444 445 446 447
	
	DBG_ENTER_ROUTINE 

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

448
	slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
449
	state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
L
Linus Torvalds 已提交
450

451 452
	switch (state) {
	case ATN_LED_STATE_ON:
L
Linus Torvalds 已提交
453 454
		*status = 1;	/* On */
		break;
455
	case ATN_LED_STATE_BLINK:
L
Linus Torvalds 已提交
456 457
		*status = 2;	/* Blink */
		break;
458
	case ATN_LED_STATE_OFF:
L
Linus Torvalds 已提交
459 460 461
		*status = 0;	/* Off */
		break;
	default:
462
		*status = 0xFF;	/* Reserved */
L
Linus Torvalds 已提交
463 464 465 466 467 468 469 470 471
		break;
	}

	DBG_LEAVE_ROUTINE 
	return 0;
}

static int hpc_get_power_status(struct slot * slot, u8 *status)
{
472
	struct controller *ctrl = slot->ctrl;
L
Linus Torvalds 已提交
473
	u32 slot_reg;
474
	u8 state;
L
Linus Torvalds 已提交
475 476 477 478 479 480 481 482
	
	DBG_ENTER_ROUTINE 

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

483
	slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
484
	state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
L
Linus Torvalds 已提交
485

486 487
	switch (state) {
	case SLOT_STATE_PWRONLY:
L
Linus Torvalds 已提交
488 489
		*status = 2;	/* Powered only */
		break;
490
	case SLOT_STATE_ENABLED:
L
Linus Torvalds 已提交
491 492
		*status = 1;	/* Enabled */
		break;
493
	case SLOT_STATE_DISABLED:
L
Linus Torvalds 已提交
494 495 496
		*status = 0;	/* Disabled */
		break;
	default:
497
		*status = 0xFF;	/* Reserved */
L
Linus Torvalds 已提交
498 499 500 501
		break;
	}

	DBG_LEAVE_ROUTINE 
502
	return 0;
L
Linus Torvalds 已提交
503 504 505 506 507
}


static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
508
	struct controller *ctrl = slot->ctrl;
L
Linus Torvalds 已提交
509 510 511 512 513 514 515 516 517
	u32 slot_reg;

	DBG_ENTER_ROUTINE 

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

518
	slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
519
	*status = !!(slot_reg & MRL_SENSOR);	/* 0 -> close; 1 -> open */
L
Linus Torvalds 已提交
520 521 522 523 524 525 526

	DBG_LEAVE_ROUTINE 
	return 0;
}

static int hpc_get_adapter_status(struct slot *slot, u8 *status)
{
527
	struct controller *ctrl = slot->ctrl;
L
Linus Torvalds 已提交
528
	u32 slot_reg;
529
	u8 state;
L
Linus Torvalds 已提交
530 531 532 533 534 535 536 537

	DBG_ENTER_ROUTINE 

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

538
	slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
539 540
	state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
	*status = (state != 0x3) ? 1 : 0;
L
Linus Torvalds 已提交
541 542 543 544 545 546 547

	DBG_LEAVE_ROUTINE 
	return 0;
}

static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
{
548
	struct controller *ctrl = slot->ctrl;
L
Linus Torvalds 已提交
549 550 551 552 553 554 555 556

	DBG_ENTER_ROUTINE 
	
	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

557
	*prog_int = shpc_readb(ctrl, PROG_INTERFACE);
L
Linus Torvalds 已提交
558 559 560 561 562 563 564 565

	DBG_LEAVE_ROUTINE 
	return 0;
}

static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
{
	int retval = 0;
566
	struct controller *ctrl = slot->ctrl;
567
	u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
568
	u8 m66_cap  = !!(slot_reg & MHZ66_CAP);
569
	u8 pi, pcix_cap;
L
Linus Torvalds 已提交
570 571 572

	DBG_ENTER_ROUTINE 

573 574 575 576 577 578 579 580 581 582 583 584 585 586
	if ((retval = hpc_get_prog_int(slot, &pi)))
		return retval;

	switch (pi) {
	case 1:
		pcix_cap = (slot_reg & PCIX_CAP_MASK_PI1) >> PCIX_CAP_SHIFT;
		break;
	case 2:
		pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT;
		break;
	default:
		return -ENODEV;
	}

587 588
	dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n",
	    __FUNCTION__, slot_reg, pcix_cap, m66_cap);
L
Linus Torvalds 已提交
589

590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
	switch (pcix_cap) {
	case 0x0:
		*value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
		break;
	case 0x1:
		*value = PCI_SPEED_66MHz_PCIX;
		break;
	case 0x3:
		*value = PCI_SPEED_133MHz_PCIX;
		break;
	case 0x4:
		*value = PCI_SPEED_133MHz_PCIX_266;
		break;
	case 0x5:
		*value = PCI_SPEED_133MHz_PCIX_533;
		break;
	case 0x2:
	default:
		*value = PCI_SPEED_UNKNOWN;
		retval = -ENODEV;
		break;
L
Linus Torvalds 已提交
611 612 613 614 615 616 617 618 619
	}

	dbg("Adapter speed = %d\n", *value);
	DBG_LEAVE_ROUTINE 
	return retval;
}

static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
{
620
	struct controller *ctrl = slot->ctrl;
L
Linus Torvalds 已提交
621 622 623 624 625 626 627 628 629 630 631
	u16 sec_bus_status;
	u8 pi;
	int retval = 0;

	DBG_ENTER_ROUTINE 

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

632 633
	pi = shpc_readb(ctrl, PROG_INTERFACE);
	sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
L
Linus Torvalds 已提交
634 635

	if (pi == 2) {
636
		*mode = (sec_bus_status & 0x0100) >> 8;
L
Linus Torvalds 已提交
637 638 639 640 641 642 643 644 645 646 647 648
	} else {
		retval = -1;
	}

	dbg("Mode 1 ECC cap = %d\n", *mode);
	
	DBG_LEAVE_ROUTINE 
	return retval;
}

static int hpc_query_power_fault(struct slot * slot)
{
649
	struct controller *ctrl = slot->ctrl;
L
Linus Torvalds 已提交
650 651 652 653 654 655 656 657 658
	u32 slot_reg;

	DBG_ENTER_ROUTINE 

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

659
	slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
L
Linus Torvalds 已提交
660 661 662

	DBG_LEAVE_ROUTINE
	/* Note: Logic 0 => fault */
663
	return !(slot_reg & POWER_FAULT);
L
Linus Torvalds 已提交
664 665 666 667
}

static int hpc_set_attention_status(struct slot *slot, u8 value)
{
668
	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
L
Linus Torvalds 已提交
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
	u8 slot_cmd = 0;
	int rc = 0;

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

	if (slot->hp_slot >= php_ctlr->num_slots) {
		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
		return -1;
	}

	switch (value) {
		case 0 :	
			slot_cmd = 0x30;	/* OFF */
			break;
		case 1:
			slot_cmd = 0x10;	/* ON */
			break;
		case 2:
			slot_cmd = 0x20;	/* BLINK */
			break;
		default:
			return -1;
	}

	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
	
	return rc;
}


static void hpc_set_green_led_on(struct slot *slot)
{
704
	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
L
Linus Torvalds 已提交
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
	u8 slot_cmd;

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return ;
	}

	if (slot->hp_slot >= php_ctlr->num_slots) {
		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
		return ;
	}

	slot_cmd = 0x04;

	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);

	return;
}

static void hpc_set_green_led_off(struct slot *slot)
{
726
	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
L
Linus Torvalds 已提交
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
	u8 slot_cmd;

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return ;
	}

	if (slot->hp_slot >= php_ctlr->num_slots) {
		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
		return ;
	}

	slot_cmd = 0x0C;

	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);

	return;
}

static void hpc_set_green_led_blink(struct slot *slot)
{
748
	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
L
Linus Torvalds 已提交
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
	u8 slot_cmd;

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return ;
	}

	if (slot->hp_slot >= php_ctlr->num_slots) {
		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
		return ;
	}

	slot_cmd = 0x08;

	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);

	return;
}

int shpc_get_ctlr_slot_config(struct controller *ctrl,
	int *num_ctlr_slots,	/* number of slots in this HPC			*/
	int *first_device_num,	/* PCI dev num of the first slot in this SHPC	*/
	int *physical_slot_num,	/* phy slot num of the first slot in this SHPC	*/
	int *updown,		/* physical_slot_num increament: 1 or -1	*/
	int *flags)
{
775
	u32 slot_config;
L
Linus Torvalds 已提交
776 777 778 779 780 781 782 783

	DBG_ENTER_ROUTINE 

	if (!ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

784 785 786 787 788
	slot_config = shpc_readl(ctrl, SLOT_CONFIG);
	*first_device_num = (slot_config & FIRST_DEV_NUM) >> 8;
	*num_ctlr_slots = slot_config & SLOT_NUM;
	*physical_slot_num = (slot_config & PSN) >> 16;
	*updown = ((slot_config & UPDOWN) >> 29) ? 1 : -1;
L
Linus Torvalds 已提交
789 790 791 792 793 794 795 796 797

	dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num);

	DBG_LEAVE_ROUTINE 
	return 0;
}

static void hpc_release_ctlr(struct controller *ctrl)
{
798
	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
L
Linus Torvalds 已提交
799
	struct php_ctlr_state_s *p, *p_prev;
800
	int i;
801
	u32 slot_reg;
L
Linus Torvalds 已提交
802 803 804 805 806 807 808 809

	DBG_ENTER_ROUTINE 

	if (!ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return ;
	}

810
	/*
811
	 * Mask event interrupts and SERRs of all slots
812
	 */
813 814 815 816 817 818 819 820 821
	for (i = 0; i < ctrl->num_slots; i++) {
		slot_reg = shpc_readl(ctrl, SLOT_REG(i));
		slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK |
			     BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK |
			     CON_PFAULT_INTR_MASK   | MRL_CHANGE_SERR_MASK |
			     CON_PFAULT_SERR_MASK);
		slot_reg &= ~SLOT_REG_RSVDZ_MASK;
		shpc_writel(ctrl, SLOT_REG(i), slot_reg);
	}
822 823 824

	cleanup_slots(ctrl);

L
Linus Torvalds 已提交
825 826 827 828 829 830 831 832 833
	if (shpchp_poll_mode) {
	    del_timer(&php_ctlr->int_poll_timer);
	} else {	
		if (php_ctlr->irq) {
			free_irq(php_ctlr->irq, ctrl);
			php_ctlr->irq = 0;
			pci_disable_msi(php_ctlr->pci_dev);
		}
	}
834

L
Linus Torvalds 已提交
835 836
	if (php_ctlr->pci_dev) {
		iounmap(php_ctlr->creg);
837
		release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
L
Linus Torvalds 已提交
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
		php_ctlr->pci_dev = NULL;
	}

	spin_lock(&list_lock);
	p = php_ctlr_list_head;
	p_prev = NULL;
	while (p) {
		if (p == php_ctlr) {
			if (p_prev)
				p_prev->pnext = p->pnext;
			else
				php_ctlr_list_head = p->pnext;
			break;
		} else {
			p_prev = p;
			p = p->pnext;
		}
	}
	spin_unlock(&list_lock);

	kfree(php_ctlr);

DBG_LEAVE_ROUTINE
			  
}

static int hpc_power_on_slot(struct slot * slot)
{
866
	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
L
Linus Torvalds 已提交
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
	u8 slot_cmd;
	int retval = 0;

	DBG_ENTER_ROUTINE 

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

	if (slot->hp_slot >= php_ctlr->num_slots) {
		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
		return -1;
	}
	slot_cmd = 0x01;

	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);

	if (retval) {
		err("%s: Write command failed!\n", __FUNCTION__);
		return -1;
	}

	DBG_LEAVE_ROUTINE

	return retval;
}

static int hpc_slot_enable(struct slot * slot)
{
897
	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
L
Linus Torvalds 已提交
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
	u8 slot_cmd;
	int retval = 0;

	DBG_ENTER_ROUTINE 

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

	if (slot->hp_slot >= php_ctlr->num_slots) {
		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
		return -1;
	}
	/* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
	slot_cmd = 0x3A;  

	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);

	if (retval) {
		err("%s: Write command failed!\n", __FUNCTION__);
		return -1;
	}

	DBG_LEAVE_ROUTINE
	return retval;
}

static int hpc_slot_disable(struct slot * slot)
{
928
	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
L
Linus Torvalds 已提交
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959
	u8 slot_cmd;
	int retval = 0;

	DBG_ENTER_ROUTINE 

	if (!slot->ctrl->hpc_ctlr_handle) {
		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
		return -1;
	}

	if (slot->hp_slot >= php_ctlr->num_slots) {
		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
		return -1;
	}

	/* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */
	slot_cmd = 0x1F;

	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);

	if (retval) {
		err("%s: Write command failed!\n", __FUNCTION__);
		return -1;
	}

	DBG_LEAVE_ROUTINE
	return retval;
}

static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
{
960
	int retval;
961
	struct controller *ctrl = slot->ctrl;
962
	u8 pi, cmd;
L
Linus Torvalds 已提交
963 964 965

	DBG_ENTER_ROUTINE 

966
	pi = shpc_readb(ctrl, PROG_INTERFACE);
967 968
	if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX))
		return -EINVAL;
L
Linus Torvalds 已提交
969

970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
	switch (value) {
	case PCI_SPEED_33MHz:
		cmd = SETA_PCI_33MHZ;
		break;
	case PCI_SPEED_66MHz:
		cmd = SETA_PCI_66MHZ;
		break;
	case PCI_SPEED_66MHz_PCIX:
		cmd = SETA_PCIX_66MHZ;
		break;
	case PCI_SPEED_100MHz_PCIX:
		cmd = SETA_PCIX_100MHZ;
		break;
	case PCI_SPEED_133MHz_PCIX:
		cmd = SETA_PCIX_133MHZ;
		break;
	case PCI_SPEED_66MHz_PCIX_ECC:
		cmd = SETB_PCIX_66MHZ_EM;
		break;
	case PCI_SPEED_100MHz_PCIX_ECC:
		cmd = SETB_PCIX_100MHZ_EM;
		break;
	case PCI_SPEED_133MHz_PCIX_ECC:
		cmd = SETB_PCIX_133MHZ_EM;
		break;
	case PCI_SPEED_66MHz_PCIX_266:
		cmd = SETB_PCIX_66MHZ_266;
		break;
	case PCI_SPEED_100MHz_PCIX_266:
		cmd = SETB_PCIX_100MHZ_266;
		break;
	case PCI_SPEED_133MHz_PCIX_266:
		cmd = SETB_PCIX_133MHZ_266;
		break;
	case PCI_SPEED_66MHz_PCIX_533:
		cmd = SETB_PCIX_66MHZ_533;
		break;
	case PCI_SPEED_100MHz_PCIX_533:
		cmd = SETB_PCIX_100MHZ_533;
		break;
	case PCI_SPEED_133MHz_PCIX_533:
		cmd = SETB_PCIX_133MHZ_533;
		break;
	default:
		return -EINVAL;
L
Linus Torvalds 已提交
1015
	}
1016 1017 1018

	retval = shpc_write_cmd(slot, 0, cmd);
	if (retval)
L
Linus Torvalds 已提交
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
		err("%s: Write command failed!\n", __FUNCTION__);

	DBG_LEAVE_ROUTINE
	return retval;
}

static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs)
{
	struct controller *ctrl = NULL;
	struct php_ctlr_state_s *php_ctlr;
	u8 schedule_flag = 0;
	u32 temp_dword, intr_loc, intr_loc2;
	int hp_slot;

	if (!dev_id)
		return IRQ_NONE;

	if (!shpchp_poll_mode) { 
		ctrl = (struct controller *)dev_id;
		php_ctlr = ctrl->hpc_ctlr_handle;
	} else { 
		php_ctlr = (struct php_ctlr_state_s *) dev_id;
		ctrl = (struct controller *)php_ctlr->callback_instance_id;
	}

	if (!ctrl)
		return IRQ_NONE;
	
	if (!php_ctlr || !php_ctlr->creg)
		return IRQ_NONE;

	/* Check to see if it was our interrupt */
1051
	intr_loc = shpc_readl(ctrl, INTR_LOC);
L
Linus Torvalds 已提交
1052 1053 1054 1055 1056 1057 1058 1059

	if (!intr_loc)
		return IRQ_NONE;
	dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); 

	if(!shpchp_poll_mode) {
		/* Mask Global Interrupt Mask - see implementation note on p. 139 */
		/* of SHPC spec rev 1.0*/
1060
		temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE);
1061 1062
		temp_dword |= GLOBAL_INTR_MASK;
		temp_dword &= ~SERR_INTR_RSVDZ_MASK;
1063
		shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword);
L
Linus Torvalds 已提交
1064

1065
		intr_loc2 = shpc_readl(ctrl, INTR_LOC);
L
Linus Torvalds 已提交
1066 1067 1068 1069 1070 1071
		dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 
	}

	if (intr_loc & 0x0001) {
		/* 
		 * Command Complete Interrupt Pending 
1072
		 * RO only - clear by writing 1 to the Command Completion
L
Linus Torvalds 已提交
1073 1074
		 * Detect bit in Controller SERR-INT register
		 */
1075
		temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE);
1076
		temp_dword &= ~SERR_INTR_RSVDZ_MASK;
1077
		shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword);
1078
		ctrl->cmd_busy = 0;
L
Linus Torvalds 已提交
1079 1080 1081
		wake_up_interruptible(&ctrl->queue);
	}

1082 1083
	if ((intr_loc = (intr_loc >> 1)) == 0)
		goto out;
L
Linus Torvalds 已提交
1084 1085 1086 1087

	for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { 
	/* To find out which slot has interrupt pending */
		if ((intr_loc >> hp_slot) & 0x01) {
1088
			temp_dword = shpc_readl(ctrl, SLOT_REG(hp_slot));
1089 1090
			dbg("%s: Slot %x with intr, slot register = %x\n",
				__FUNCTION__, hp_slot, temp_dword);
1091 1092
			if ((php_ctlr->switch_change_callback) &&
			    (temp_dword & MRL_CHANGE_DETECTED))
L
Linus Torvalds 已提交
1093 1094
				schedule_flag += php_ctlr->switch_change_callback(
					hp_slot, php_ctlr->callback_instance_id);
1095 1096
			if ((php_ctlr->attention_button_callback) &&
			    (temp_dword & BUTTON_PRESS_DETECTED))
L
Linus Torvalds 已提交
1097 1098
				schedule_flag += php_ctlr->attention_button_callback(
					hp_slot, php_ctlr->callback_instance_id);
1099 1100
			if ((php_ctlr->presence_change_callback) &&
			    (temp_dword & PRSNT_CHANGE_DETECTED))
L
Linus Torvalds 已提交
1101 1102
				schedule_flag += php_ctlr->presence_change_callback(
					hp_slot , php_ctlr->callback_instance_id);
1103 1104
			if ((php_ctlr->power_fault_callback) &&
			    (temp_dword & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED)))
L
Linus Torvalds 已提交
1105 1106 1107 1108
				schedule_flag += php_ctlr->power_fault_callback(
					hp_slot, php_ctlr->callback_instance_id);
			
			/* Clear all slot events */
1109
			temp_dword &= ~SLOT_REG_RSVDZ_MASK;
1110
			shpc_writel(ctrl, SLOT_REG(hp_slot), temp_dword);
L
Linus Torvalds 已提交
1111

1112
			intr_loc2 = shpc_readl(ctrl, INTR_LOC);
L
Linus Torvalds 已提交
1113 1114 1115
			dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 
		}
	}
1116
 out:
L
Linus Torvalds 已提交
1117 1118
	if (!shpchp_poll_mode) {
		/* Unmask Global Interrupt Mask */
1119
		temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE);
1120
		temp_dword &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK);
1121
		shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword);
L
Linus Torvalds 已提交
1122 1123 1124 1125 1126 1127 1128
	}
	
	return IRQ_HANDLED;
}

static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
{
1129
	int retval = 0;
1130
	struct controller *ctrl = slot->ctrl;
L
Linus Torvalds 已提交
1131
	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
1132 1133 1134
	u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
	u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1);
	u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2);
L
Linus Torvalds 已提交
1135 1136 1137 1138

	DBG_ENTER_ROUTINE 

	if (pi == 2) {
1139
		if (slot_avail2 & SLOT_133MHZ_PCIX_533)
1140
			bus_speed = PCI_SPEED_133MHz_PCIX_533;
1141
		else if (slot_avail2 & SLOT_100MHZ_PCIX_533)
1142
			bus_speed = PCI_SPEED_100MHz_PCIX_533;
1143
		else if (slot_avail2 & SLOT_66MHZ_PCIX_533)
1144
			bus_speed = PCI_SPEED_66MHz_PCIX_533;
1145
		else if (slot_avail2 & SLOT_133MHZ_PCIX_266)
1146
			bus_speed = PCI_SPEED_133MHz_PCIX_266;
1147
		else if (slot_avail2 & SLOT_100MHZ_PCIX_266)
1148
			bus_speed = PCI_SPEED_100MHz_PCIX_266;
1149
		else if (slot_avail2 & SLOT_66MHZ_PCIX_266)
1150 1151 1152 1153
			bus_speed = PCI_SPEED_66MHz_PCIX_266;
	}

	if (bus_speed == PCI_SPEED_UNKNOWN) {
1154
		if (slot_avail1 & SLOT_133MHZ_PCIX)
1155
			bus_speed = PCI_SPEED_133MHz_PCIX;
1156
		else if (slot_avail1 & SLOT_100MHZ_PCIX)
1157
			bus_speed = PCI_SPEED_100MHz_PCIX;
1158
		else if (slot_avail1 & SLOT_66MHZ_PCIX)
1159
			bus_speed = PCI_SPEED_66MHz_PCIX;
1160
		else if (slot_avail2 & SLOT_66MHZ)
1161
			bus_speed = PCI_SPEED_66MHz;
1162
		else if (slot_avail1 & SLOT_33MHZ)
1163 1164 1165
			bus_speed = PCI_SPEED_33MHz;
		else
			retval = -ENODEV;
L
Linus Torvalds 已提交
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
	}

	*value = bus_speed;
	dbg("Max bus speed = %d\n", bus_speed);
	DBG_LEAVE_ROUTINE 
	return retval;
}

static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
{
1176
	int retval = 0;
1177
	struct controller *ctrl = slot->ctrl;
L
Linus Torvalds 已提交
1178
	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
1179 1180
	u16 sec_bus_reg = shpc_readw(ctrl, SEC_BUS_CONFIG);
	u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
1181
	u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7);
L
Linus Torvalds 已提交
1182 1183 1184

	DBG_ENTER_ROUTINE 

1185 1186 1187
	if ((pi == 1) && (speed_mode > 4)) {
		*value = PCI_SPEED_UNKNOWN;
		return -ENODEV;
L
Linus Torvalds 已提交
1188 1189
	}

1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
	switch (speed_mode) {
	case 0x0:
		*value = PCI_SPEED_33MHz;
		break;
	case 0x1:
		*value = PCI_SPEED_66MHz;
		break;
	case 0x2:
		*value = PCI_SPEED_66MHz_PCIX;
		break;
	case 0x3:
		*value = PCI_SPEED_100MHz_PCIX;
		break;
	case 0x4:
		*value = PCI_SPEED_133MHz_PCIX;
		break;
	case 0x5:
		*value = PCI_SPEED_66MHz_PCIX_ECC;
		break;
	case 0x6:
		*value = PCI_SPEED_100MHz_PCIX_ECC;
		break;
	case 0x7:
		*value = PCI_SPEED_133MHz_PCIX_ECC;
		break;
	case 0x8:
		*value = PCI_SPEED_66MHz_PCIX_266;
		break;
	case 0x9:
		*value = PCI_SPEED_100MHz_PCIX_266;
		break;
	case 0xa:
		*value = PCI_SPEED_133MHz_PCIX_266;
		break;
	case 0xb:
		*value = PCI_SPEED_66MHz_PCIX_533;
		break;
	case 0xc:
		*value = PCI_SPEED_100MHz_PCIX_533;
		break;
	case 0xd:
		*value = PCI_SPEED_133MHz_PCIX_533;
		break;
	default:
		*value = PCI_SPEED_UNKNOWN;
		retval = -ENODEV;
		break;
L
Linus Torvalds 已提交
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
	}

	dbg("Current bus speed = %d\n", bus_speed);
	DBG_LEAVE_ROUTINE 
	return retval;
}

static struct hpc_ops shpchp_hpc_ops = {
	.power_on_slot			= hpc_power_on_slot,
	.slot_enable			= hpc_slot_enable,
	.slot_disable			= hpc_slot_disable,
	.set_bus_speed_mode		= hpc_set_bus_speed_mode,	  
	.set_attention_status	= hpc_set_attention_status,
	.get_power_status		= hpc_get_power_status,
	.get_attention_status	= hpc_get_attention_status,
	.get_latch_status		= hpc_get_latch_status,
	.get_adapter_status		= hpc_get_adapter_status,

	.get_max_bus_speed		= hpc_get_max_bus_speed,
	.get_cur_bus_speed		= hpc_get_cur_bus_speed,
	.get_adapter_speed		= hpc_get_adapter_speed,
	.get_mode1_ECC_cap		= hpc_get_mode1_ECC_cap,
	.get_prog_int			= hpc_get_prog_int,

	.query_power_fault		= hpc_query_power_fault,
	.green_led_on			= hpc_set_green_led_on,
	.green_led_off			= hpc_set_green_led_off,
	.green_led_blink		= hpc_set_green_led_blink,
	
	.release_ctlr			= hpc_release_ctlr,
};

1269
int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
L
Linus Torvalds 已提交
1270 1271 1272
{
	struct php_ctlr_state_s *php_ctlr, *p;
	void *instance_id = ctrl;
1273
	int rc, num_slots = 0;
L
Linus Torvalds 已提交
1274 1275
	u8 hp_slot;
	static int first = 1;
1276
	u32 shpc_base_offset;
1277
	u32 tempdword, slot_reg, slot_config;
L
Linus Torvalds 已提交
1278 1279 1280 1281
	u8 i;

	DBG_ENTER_ROUTINE

1282 1283
	ctrl->pci_dev = pdev;  /* pci_dev of the P2P bridge */

L
Linus Torvalds 已提交
1284
	spin_lock_init(&list_lock);
1285
	php_ctlr = kzalloc(sizeof(*php_ctlr), GFP_KERNEL);
L
Linus Torvalds 已提交
1286 1287 1288 1289 1290 1291 1292 1293

	if (!php_ctlr) {	/* allocate controller state data */
		err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
		goto abort;
	}

	php_ctlr->pci_dev = pdev;	/* save pci_dev in context */

1294 1295
	if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
				PCI_DEVICE_ID_AMD_GOLAM_7450)) {
1296 1297 1298
		/* amd shpc driver doesn't use Base Offset; assume 0 */
		ctrl->mmio_base = pci_resource_start(pdev, 0);
		ctrl->mmio_size = pci_resource_len(pdev, 0);
L
Linus Torvalds 已提交
1299
	} else {
1300 1301 1302
		ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC);
		if (!ctrl->cap_offset) {
			err("%s : cap_offset == 0\n", __FUNCTION__);
L
Linus Torvalds 已提交
1303 1304
			goto abort_free_ctlr;
		}
1305 1306
		dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset);

1307
		rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset);
L
Linus Torvalds 已提交
1308
		if (rc) {
1309
			err("%s: cannot read base_offset\n", __FUNCTION__);
L
Linus Torvalds 已提交
1310 1311
			goto abort_free_ctlr;
		}
1312

1313
		rc = shpc_indirect_read(ctrl, 3, &tempdword);
L
Linus Torvalds 已提交
1314
		if (rc) {
1315
			err("%s: cannot read slot config\n", __FUNCTION__);
L
Linus Torvalds 已提交
1316 1317
			goto abort_free_ctlr;
		}
1318 1319
		num_slots = tempdword & SLOT_NUM;
		dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots);
L
Linus Torvalds 已提交
1320

1321
		for (i = 0; i < 9 + num_slots; i++) {
1322
			rc = shpc_indirect_read(ctrl, i, &tempdword);
L
Linus Torvalds 已提交
1323
			if (rc) {
1324 1325
				err("%s: cannot read creg (index = %d)\n",
				    __FUNCTION__, i);
L
Linus Torvalds 已提交
1326 1327
				goto abort_free_ctlr;
			}
1328 1329
			dbg("%s: offset %d: value %x\n", __FUNCTION__,i,
					tempdword);
L
Linus Torvalds 已提交
1330
		}
1331 1332 1333 1334

		ctrl->mmio_base =
			pci_resource_start(pdev, 0) + shpc_base_offset;
		ctrl->mmio_size = 0x24 + 0x4 * num_slots;
L
Linus Torvalds 已提交
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
	}

	if (first) {
		spin_lock_init(&hpc_event_lock);
		first = 0;
	}

	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, 
		pdev->subsystem_device);
	
	if (pci_enable_device(pdev))
		goto abort_free_ctlr;

1348
	if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) {
L
Linus Torvalds 已提交
1349 1350 1351 1352
		err("%s: cannot reserve MMIO region\n", __FUNCTION__);
		goto abort_free_ctlr;
	}

1353
	php_ctlr->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size);
L
Linus Torvalds 已提交
1354
	if (!php_ctlr->creg) {
1355 1356 1357
		err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__,
		    ctrl->mmio_size, ctrl->mmio_base);
		release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
L
Linus Torvalds 已提交
1358 1359 1360 1361
		goto abort_free_ctlr;
	}
	dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);

1362
	mutex_init(&ctrl->crit_sect);
1363 1364
	mutex_init(&ctrl->cmd_lock);

L
Linus Torvalds 已提交
1365 1366 1367 1368 1369
	/* Setup wait queue */
	init_waitqueue_head(&ctrl->queue);

	/* Find the IRQ */
	php_ctlr->irq = pdev->irq;
1370 1371 1372 1373
	php_ctlr->attention_button_callback = shpchp_handle_attention_button,
	php_ctlr->switch_change_callback = shpchp_handle_switch_change;
	php_ctlr->presence_change_callback = shpchp_handle_presence_change;
	php_ctlr->power_fault_callback = shpchp_handle_power_fault;
L
Linus Torvalds 已提交
1374 1375
	php_ctlr->callback_instance_id = instance_id;

1376 1377 1378
	ctrl->hpc_ctlr_handle = php_ctlr;
	ctrl->hpc_ops = &shpchp_hpc_ops;

L
Linus Torvalds 已提交
1379
	/* Return PCI Controller Info */
1380 1381 1382
	slot_config = shpc_readl(ctrl, SLOT_CONFIG);
	php_ctlr->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8;
	php_ctlr->num_slots = slot_config & SLOT_NUM;
L
Linus Torvalds 已提交
1383 1384 1385 1386
	dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset);
	dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots);

	/* Mask Global Interrupt Mask & Command Complete Interrupt Mask */
1387
	tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
L
Linus Torvalds 已提交
1388
	dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
1389 1390 1391
	tempdword |= (GLOBAL_INTR_MASK  | GLOBAL_SERR_MASK |
		      COMMAND_INTR_MASK | ARBITER_SERR_MASK);
	tempdword &= ~SERR_INTR_RSVDZ_MASK;
1392 1393
	shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword);
	tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
L
Linus Torvalds 已提交
1394 1395 1396 1397 1398 1399
	dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);

	/* Mask the MRL sensor SERR Mask of individual slot in
	 * Slot SERR-INT Mask & clear all the existing event if any
	 */
	for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
1400
		slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
L
Linus Torvalds 已提交
1401 1402
		dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
			hp_slot, slot_reg);
1403 1404 1405 1406 1407 1408
		slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK |
			     BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK |
			     CON_PFAULT_INTR_MASK   | MRL_CHANGE_SERR_MASK |
			     CON_PFAULT_SERR_MASK);
		slot_reg &= ~SLOT_REG_RSVDZ_MASK;
		shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
L
Linus Torvalds 已提交
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430
	}
	
	if (shpchp_poll_mode)  {/* Install interrupt polling code */
		/* Install and start the interrupt polling timer */
		init_timer(&php_ctlr->int_poll_timer);
		start_int_poll_timer( php_ctlr, 10 );   /* start with 10 second delay */
	} else {
		/* Installs the interrupt handler */
		rc = pci_enable_msi(pdev);
		if (rc) {
			info("Can't get msi for the hotplug controller\n");
			info("Use INTx for the hotplug controller\n");
		} else
			php_ctlr->irq = pdev->irq;
		
		rc = request_irq(php_ctlr->irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
		dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
		if (rc) {
			err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
			goto abort_free_ctlr;
		}
	}
1431 1432 1433
	dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __FUNCTION__,
			pdev->bus->number, PCI_SLOT(pdev->devfn),
			PCI_FUNC(pdev->devfn), pdev->irq);
1434
	get_hp_hw_control_from_firmware(pdev);
L
Linus Torvalds 已提交
1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453

	/*  Add this HPC instance into the HPC list */
	spin_lock(&list_lock);
	if (php_ctlr_list_head == 0) {
		php_ctlr_list_head = php_ctlr;
		p = php_ctlr_list_head;
		p->pnext = NULL;
	} else {
		p = php_ctlr_list_head;

		while (p->pnext)
			p = p->pnext;

		p->pnext = php_ctlr;
	}
	spin_unlock(&list_lock);

	ctlr_seq_num++;

1454 1455 1456
	/*
	 * Unmask all event interrupts of all slots
	 */
L
Linus Torvalds 已提交
1457
	for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
1458
		slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
L
Linus Torvalds 已提交
1459 1460
		dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
			hp_slot, slot_reg);
1461 1462 1463 1464
		slot_reg &= ~(PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK |
			      BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK |
			      CON_PFAULT_INTR_MASK | SLOT_REG_RSVDZ_MASK);
		shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
L
Linus Torvalds 已提交
1465 1466 1467
	}
	if (!shpchp_poll_mode) {
		/* Unmask all general input interrupts and SERR */
1468
		tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
1469 1470
		tempdword &= ~(GLOBAL_INTR_MASK | COMMAND_INTR_MASK |
			       SERR_INTR_RSVDZ_MASK);
1471 1472
		shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword);
		tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
L
Linus Torvalds 已提交
1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
		dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
	}

	DBG_LEAVE_ROUTINE
	return 0;

	/* We end up here for the many possible ways to fail this API.  */
abort_free_ctlr:
	kfree(php_ctlr);
abort:
	DBG_LEAVE_ROUTINE
	return -1;
}