[go: nahoru, domu]

shpchp.h revision 6aa562c248e05db993e4a5f405f899c0cfabb7f2
1/*
2 * Standard Hot Plug Controller Driver
3 *
4 * Copyright (C) 1995,2001 Compaq Computer Corporation
5 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
6 * Copyright (C) 2001 IBM
7 * Copyright (C) 2003-2004 Intel Corporation
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or (at
14 * your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
19 * NON INFRINGEMENT.  See the GNU General Public License for more
20 * details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com>
27 *
28 */
29#ifndef _SHPCHP_H
30#define _SHPCHP_H
31
32#include <linux/types.h>
33#include <linux/pci.h>
34#include <linux/delay.h>
35#include <linux/sched.h>	/* signal_pending(), struct timer_list */
36#include <linux/mutex.h>
37
38#include "pci_hotplug.h"
39
40#if !defined(MODULE)
41	#define MY_NAME	"shpchp"
42#else
43	#define MY_NAME	THIS_MODULE->name
44#endif
45
46extern int shpchp_poll_mode;
47extern int shpchp_poll_time;
48extern int shpchp_debug;
49extern struct workqueue_struct *shpchp_wq;
50
51/*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
52#define dbg(format, arg...) do { if (shpchp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
53#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
54#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
55#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
56
57#define SLOT_NAME_SIZE 10
58struct slot {
59	u8 bus;
60	u8 device;
61	u16 status;
62	u32 number;
63	u8 is_a_board;
64	u8 state;
65	u8 presence_save;
66	u8 pwr_save;
67	struct timer_list task_event;
68	u8 hp_slot;
69	struct controller *ctrl;
70	struct hpc_ops *hpc_ops;
71	struct hotplug_slot *hotplug_slot;
72	struct list_head	slot_list;
73	char name[SLOT_NAME_SIZE];
74	struct work_struct work;	/* work for button event */
75	struct mutex lock;
76};
77
78struct event_info {
79	u32 event_type;
80	struct slot *p_slot;
81	struct work_struct work;
82};
83
84struct controller {
85	struct mutex crit_sect;		/* critical section mutex */
86	struct mutex cmd_lock;		/* command lock */
87	struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
88	int num_slots;			/* Number of slots on ctlr */
89	int slot_num_inc;		/* 1 or -1 */
90	struct pci_dev *pci_dev;
91	struct list_head slot_list;
92	struct hpc_ops *hpc_ops;
93	wait_queue_head_t queue;	/* sleep & wake process */
94	u8 bus;
95	u8 device;
96	u8 function;
97	u8 slot_device_offset;
98	u8 add_support;
99	u32 pcix_misc2_reg;	/* for amd pogo errata */
100	enum pci_bus_speed speed;
101	u32 first_slot;		/* First physical slot number */
102	u8 slot_bus;		/* Bus where the slots handled by this controller sit */
103	u32 cap_offset;
104	unsigned long mmio_base;
105	unsigned long mmio_size;
106};
107
108
109/* Define AMD SHPC ID  */
110#define PCI_DEVICE_ID_AMD_GOLAM_7450	0x7450
111#define PCI_DEVICE_ID_AMD_POGO_7458	0x7458
112
113/* AMD PCIX bridge registers */
114
115#define PCIX_MEM_BASE_LIMIT_OFFSET	0x1C
116#define PCIX_MISCII_OFFSET		0x48
117#define PCIX_MISC_BRIDGE_ERRORS_OFFSET	0x80
118
119/* AMD PCIX_MISCII masks and offsets */
120#define PERRNONFATALENABLE_MASK		0x00040000
121#define PERRFATALENABLE_MASK		0x00080000
122#define PERRFLOODENABLE_MASK		0x00100000
123#define SERRNONFATALENABLE_MASK		0x00200000
124#define SERRFATALENABLE_MASK		0x00400000
125
126/* AMD PCIX_MISC_BRIDGE_ERRORS masks and offsets */
127#define PERR_OBSERVED_MASK		0x00000001
128
129/* AMD PCIX_MEM_BASE_LIMIT masks */
130#define RSE_MASK			0x40000000
131
132#define INT_BUTTON_IGNORE		0
133#define INT_PRESENCE_ON			1
134#define INT_PRESENCE_OFF		2
135#define INT_SWITCH_CLOSE		3
136#define INT_SWITCH_OPEN			4
137#define INT_POWER_FAULT			5
138#define INT_POWER_FAULT_CLEAR		6
139#define INT_BUTTON_PRESS		7
140#define INT_BUTTON_RELEASE		8
141#define INT_BUTTON_CANCEL		9
142
143#define STATIC_STATE			0
144#define BLINKINGON_STATE		1
145#define BLINKINGOFF_STATE		2
146#define POWERON_STATE			3
147#define POWEROFF_STATE			4
148
149#define PCI_TO_PCI_BRIDGE_CLASS		0x00060400
150
151/* Error messages */
152#define INTERLOCK_OPEN			0x00000002
153#define ADD_NOT_SUPPORTED		0x00000003
154#define CARD_FUNCTIONING		0x00000005
155#define ADAPTER_NOT_SAME		0x00000006
156#define NO_ADAPTER_PRESENT		0x00000009
157#define NOT_ENOUGH_RESOURCES		0x0000000B
158#define DEVICE_TYPE_NOT_SUPPORTED	0x0000000C
159#define WRONG_BUS_FREQUENCY		0x0000000D
160#define POWER_FAILURE			0x0000000E
161
162#define REMOVE_NOT_SUPPORTED		0x00000003
163
164#define DISABLE_CARD			1
165
166/*
167 * error Messages
168 */
169#define msg_initialization_err	"Initialization failure, error=%d\n"
170#define msg_button_on		"PCI slot #%s - powering on due to button press.\n"
171#define msg_button_off		"PCI slot #%s - powering off due to button press.\n"
172#define msg_button_cancel	"PCI slot #%s - action canceled due to button press.\n"
173
174/* sysfs functions for the hotplug controller info */
175extern int __must_check shpchp_create_ctrl_files(struct controller *ctrl);
176
177extern int	shpchp_sysfs_enable_slot(struct slot *slot);
178extern int	shpchp_sysfs_disable_slot(struct slot *slot);
179
180extern u8	shpchp_handle_attention_button(u8 hp_slot, void *inst_id);
181extern u8	shpchp_handle_switch_change(u8 hp_slot, void *inst_id);
182extern u8	shpchp_handle_presence_change(u8 hp_slot, void *inst_id);
183extern u8	shpchp_handle_power_fault(u8 hp_slot, void *inst_id);
184
185/* pci functions */
186extern int	shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num);
187extern int	shpchp_configure_device(struct slot *p_slot);
188extern int	shpchp_unconfigure_device(struct slot *p_slot);
189extern void	shpchp_remove_ctrl_files(struct controller *ctrl);
190extern void	cleanup_slots(struct controller *ctrl);
191extern void	queue_pushbutton_work(void *data);
192
193
194#ifdef CONFIG_ACPI
195static inline int get_hp_params_from_firmware(struct pci_dev *dev,
196			struct hotplug_params *hpp)
197{
198	if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev->bus, hpp)))
199			return -ENODEV;
200	return 0;
201}
202#define get_hp_hw_control_from_firmware(pdev) \
203	do { \
204		if (DEVICE_ACPI_HANDLE(&(pdev->dev))) \
205			acpi_run_oshp(DEVICE_ACPI_HANDLE(&(pdev->dev))); \
206	} while (0)
207#else
208#define get_hp_params_from_firmware(dev, hpp) (-ENODEV)
209#define get_hp_hw_control_from_firmware(dev) do { } while (0)
210#endif
211
212struct ctrl_reg {
213	volatile u32 base_offset;
214	volatile u32 slot_avail1;
215	volatile u32 slot_avail2;
216	volatile u32 slot_config;
217	volatile u16 sec_bus_config;
218	volatile u8  msi_ctrl;
219	volatile u8  prog_interface;
220	volatile u16 cmd;
221	volatile u16 cmd_status;
222	volatile u32 intr_loc;
223	volatile u32 serr_loc;
224	volatile u32 serr_intr_enable;
225	volatile u32 slot1;
226	volatile u32 slot2;
227	volatile u32 slot3;
228	volatile u32 slot4;
229	volatile u32 slot5;
230	volatile u32 slot6;
231	volatile u32 slot7;
232	volatile u32 slot8;
233	volatile u32 slot9;
234	volatile u32 slot10;
235	volatile u32 slot11;
236	volatile u32 slot12;
237} __attribute__ ((packed));
238
239/* offsets to the controller registers based on the above structure layout */
240enum ctrl_offsets {
241	BASE_OFFSET =	offsetof(struct ctrl_reg, base_offset),
242	SLOT_AVAIL1 =	offsetof(struct ctrl_reg, slot_avail1),
243	SLOT_AVAIL2	=	offsetof(struct ctrl_reg, slot_avail2),
244	SLOT_CONFIG =	offsetof(struct ctrl_reg, slot_config),
245	SEC_BUS_CONFIG =	offsetof(struct ctrl_reg, sec_bus_config),
246	MSI_CTRL	=	offsetof(struct ctrl_reg, msi_ctrl),
247	PROG_INTERFACE =	offsetof(struct ctrl_reg, prog_interface),
248	CMD		=	offsetof(struct ctrl_reg, cmd),
249	CMD_STATUS	=	offsetof(struct ctrl_reg, cmd_status),
250	INTR_LOC	= 	offsetof(struct ctrl_reg, intr_loc),
251	SERR_LOC	= 	offsetof(struct ctrl_reg, serr_loc),
252	SERR_INTR_ENABLE =	offsetof(struct ctrl_reg, serr_intr_enable),
253	SLOT1 =		offsetof(struct ctrl_reg, slot1),
254	SLOT2 =		offsetof(struct ctrl_reg, slot2),
255	SLOT3 =		offsetof(struct ctrl_reg, slot3),
256	SLOT4 =		offsetof(struct ctrl_reg, slot4),
257	SLOT5 =		offsetof(struct ctrl_reg, slot5),
258	SLOT6 =		offsetof(struct ctrl_reg, slot6),
259	SLOT7 =		offsetof(struct ctrl_reg, slot7),
260	SLOT8 =		offsetof(struct ctrl_reg, slot8),
261	SLOT9 =		offsetof(struct ctrl_reg, slot9),
262	SLOT10 =	offsetof(struct ctrl_reg, slot10),
263	SLOT11 =	offsetof(struct ctrl_reg, slot11),
264	SLOT12 =	offsetof(struct ctrl_reg, slot12),
265};
266typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id);
267struct php_ctlr_state_s {
268	struct php_ctlr_state_s *pnext;
269	struct pci_dev *pci_dev;
270	unsigned int irq;
271	unsigned long flags;	/* spinlock's */
272	u32 slot_device_offset;
273	u32 num_slots;
274    	struct timer_list	int_poll_timer;	/* Added for poll event */
275	php_intr_callback_t attention_button_callback;
276	php_intr_callback_t switch_change_callback;
277	php_intr_callback_t presence_change_callback;
278	php_intr_callback_t power_fault_callback;
279	void *callback_instance_id;
280	void __iomem *creg;			/* Ptr to controller register space */
281};
282/* Inline functions */
283
284
285/* Inline functions to check the sanity of a pointer that is passed to us */
286static inline int slot_paranoia_check (struct slot *slot, const char *function)
287{
288	if (!slot) {
289		dbg("%s - slot == NULL", function);
290		return -1;
291	}
292	if (!slot->hotplug_slot) {
293		dbg("%s - slot->hotplug_slot == NULL!", function);
294		return -1;
295	}
296	return 0;
297}
298
299static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
300{
301	struct slot *slot;
302
303	if (!hotplug_slot) {
304		dbg("%s - hotplug_slot == NULL\n", function);
305		return NULL;
306	}
307
308	slot = (struct slot *)hotplug_slot->private;
309	if (slot_paranoia_check (slot, function))
310                return NULL;
311	return slot;
312}
313
314static inline struct slot *shpchp_find_slot (struct controller *ctrl, u8 device)
315{
316	struct slot *slot;
317
318	if (!ctrl)
319		return NULL;
320
321	list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
322		if (slot->device == device)
323			return slot;
324	}
325
326	err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device);
327
328	return NULL;
329}
330
331static inline void amd_pogo_errata_save_misc_reg(struct slot *p_slot)
332{
333	u32 pcix_misc2_temp;
334
335	/* save MiscII register */
336	pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, &pcix_misc2_temp);
337
338	p_slot->ctrl->pcix_misc2_reg = pcix_misc2_temp;
339
340	/* clear SERR/PERR enable bits */
341	pcix_misc2_temp &= ~SERRFATALENABLE_MASK;
342	pcix_misc2_temp &= ~SERRNONFATALENABLE_MASK;
343	pcix_misc2_temp &= ~PERRFLOODENABLE_MASK;
344	pcix_misc2_temp &= ~PERRFATALENABLE_MASK;
345	pcix_misc2_temp &= ~PERRNONFATALENABLE_MASK;
346	pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, pcix_misc2_temp);
347}
348
349static inline void amd_pogo_errata_restore_misc_reg(struct slot *p_slot)
350{
351	u32 pcix_misc2_temp;
352	u32 pcix_bridge_errors_reg;
353	u32 pcix_mem_base_reg;
354	u8  perr_set;
355	u8  rse_set;
356
357	/* write-one-to-clear Bridge_Errors[ PERR_OBSERVED ] */
358	pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MISC_BRIDGE_ERRORS_OFFSET, &pcix_bridge_errors_reg);
359	perr_set = pcix_bridge_errors_reg & PERR_OBSERVED_MASK;
360	if (perr_set) {
361		dbg ("%s  W1C: Bridge_Errors[ PERR_OBSERVED = %08X]\n",__FUNCTION__ , perr_set);
362
363		pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISC_BRIDGE_ERRORS_OFFSET, perr_set);
364	}
365
366	/* write-one-to-clear Memory_Base_Limit[ RSE ] */
367	pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MEM_BASE_LIMIT_OFFSET, &pcix_mem_base_reg);
368	rse_set = pcix_mem_base_reg & RSE_MASK;
369	if (rse_set) {
370		dbg ("%s  W1C: Memory_Base_Limit[ RSE ]\n",__FUNCTION__ );
371
372		pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MEM_BASE_LIMIT_OFFSET, rse_set);
373	}
374	/* restore MiscII register */
375	pci_read_config_dword( p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, &pcix_misc2_temp );
376
377	if (p_slot->ctrl->pcix_misc2_reg & SERRFATALENABLE_MASK)
378		pcix_misc2_temp |= SERRFATALENABLE_MASK;
379	else
380		pcix_misc2_temp &= ~SERRFATALENABLE_MASK;
381
382	if (p_slot->ctrl->pcix_misc2_reg & SERRNONFATALENABLE_MASK)
383		pcix_misc2_temp |= SERRNONFATALENABLE_MASK;
384	else
385		pcix_misc2_temp &= ~SERRNONFATALENABLE_MASK;
386
387	if (p_slot->ctrl->pcix_misc2_reg & PERRFLOODENABLE_MASK)
388		pcix_misc2_temp |= PERRFLOODENABLE_MASK;
389	else
390		pcix_misc2_temp &= ~PERRFLOODENABLE_MASK;
391
392	if (p_slot->ctrl->pcix_misc2_reg & PERRFATALENABLE_MASK)
393		pcix_misc2_temp |= PERRFATALENABLE_MASK;
394	else
395		pcix_misc2_temp &= ~PERRFATALENABLE_MASK;
396
397	if (p_slot->ctrl->pcix_misc2_reg & PERRNONFATALENABLE_MASK)
398		pcix_misc2_temp |= PERRNONFATALENABLE_MASK;
399	else
400		pcix_misc2_temp &= ~PERRNONFATALENABLE_MASK;
401	pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, pcix_misc2_temp);
402}
403
404enum php_ctlr_type {
405	PCI,
406	ISA,
407	ACPI
408};
409
410int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
411
412int shpc_get_ctlr_slot_config( struct controller *ctrl,
413		int *num_ctlr_slots,
414		int *first_device_num,
415		int *physical_slot_num,
416		int *updown,
417		int *flags);
418
419struct hpc_ops {
420	int	(*power_on_slot )		(struct slot *slot);
421	int	(*slot_enable )			(struct slot *slot);
422	int	(*slot_disable )		(struct slot *slot);
423	int	(*set_bus_speed_mode)	(struct slot *slot, enum pci_bus_speed speed);
424	int	(*get_power_status)		(struct slot *slot, u8 *status);
425	int	(*get_attention_status)	(struct slot *slot, u8 *status);
426	int	(*set_attention_status)	(struct slot *slot, u8 status);
427	int	(*get_latch_status)		(struct slot *slot, u8 *status);
428	int	(*get_adapter_status)	(struct slot *slot, u8 *status);
429
430	int	(*get_max_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
431	int	(*get_cur_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
432	int	(*get_adapter_speed)	(struct slot *slot, enum pci_bus_speed *speed);
433	int	(*get_mode1_ECC_cap)	(struct slot *slot, u8 *mode);
434	int	(*get_prog_int)			(struct slot *slot, u8 *prog_int);
435
436	int	(*query_power_fault)	(struct slot *slot);
437	void	(*green_led_on)		(struct slot *slot);
438	void	(*green_led_off)	(struct slot *slot);
439	void	(*green_led_blink)	(struct slot *slot);
440	void	(*release_ctlr)		(struct controller *ctrl);
441	int (*check_cmd_status)		(struct controller *ctrl);
442};
443
444#endif				/* _SHPCHP_H */
445