PCI-X hotplug support for Compaq driver
Hi Greg,
Attached is a patch against 2.4.20 (should apply to .21-pre3 and BK-current as well) that adds 66/100/133MHz PCI-X support to the Compaq Hotplug driver.
Please apply.
Thanks,
Torben Mathiasen
drivers/hotplug/cpqphp.h +213 -3
@@ -30,7 +30,7 @@#include "pci_hotplug.h" #include <asm/io.h> /* for read? and write? functions */ - +#include <linux/delay.h> /* for delays */ #if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE )#define MY_NAME "cpqphp.o"
@@ -145,6 +145,10 @@u8 reserved11;/* 0x2b */ u8 slot_SERR;/* 0x2c */ u8 slot_power;/* 0x2d */ +u8 reserved12;/* 0x2e */ +u8 reserved13;/* 0x2f */ +u8 next_curr_freq;/* 0x30 */ +u8 reset_freq_mode;/* 0x31 */ } __attribute__ ((packed));/* offsets to the controller registers based on the above structure layout */
@@ -172,6 +176,8 @@CTRL_RESERVED11 = offsetof(struct ctrl_reg , reserved11),SLOT_SERR = offsetof(struct ctrl_reg , slot_SERR),SLOT_POWER = offsetof(struct ctrl_reg , slot_power), +NEXT_CURR_FREQ = offsetof(struct ctrl_reg , next_curr_freq), + RESET_FREQ_MODE = offsetof(struct ctrl_reg, reset_freq_mode), }; struct hrt {
@@ -345,6 +351,8 @@#define PCI_SUB_HPC_ID2 0xA2F8#define PCI_SUB_HPC_ID3 0xA2F9#define PCI_SUB_HPC_ID_INTC 0xA2FA +#define PCI_SUB_HPC_ID4 0xA2FC +#define PCI_SUB_HPC_ID5 0xA2FD#define INT_BUTTON_IGNORE 0#define INT_PRESENCE_ON 1
@@ -474,7 +482,7 @@/* inline functions */ - +extern inline struct slot *find_slot (struct controller *ctrl,u8 device);/* Inline functions to check the sanity of a pointer that is passed to us */ static inline int slot_paranoia_check (struct slot *slot,const char *function)
@@ -629,14 +637,82 @@ } +/* +* get_controller_speed - find the current frequency/mode of controller. +* +* @ctrl: controller to get frequency/mode for. +* +* Returns controller speed. +* +*/ static inline u8 get_controller_speed (struct controller *ctrl) { +u8 curr_freq;u16 misc; +if (ctrl->pcix_support) { + curr_freq =readb (ctrl->hpc_reg +NEXT_CURR_FREQ ); +if ((curr_freq &0xB0 ) ==0xB0 ) +return PCI_SPEED_133MHz_PCIX; +if ((curr_freq &0xA0 ) ==0xA0 ) +return PCI_SPEED_100MHz_PCIX; +if ((curr_freq &0x90 ) ==0x90 ) +return PCI_SPEED_66MHz_PCIX; +if (curr_freq &0x10 ) +return PCI_SPEED_66MHz; + +return PCI_SPEED_33MHz; + } + misc =readw (ctrl->hpc_reg +MISC );return (misc &0x0800 ) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; } +/* +* get_adapter_speed - find the max supported frequency/mode of adapter. +* +* @ctrl: hotplug controller. +* @hp_slot: hotplug slot where adapter is installed. +* +* Returns adapter speed. +* +*/ +static inline u8 get_adapter_speed (struct controller *ctrl,u8 hp_slot) +{ +u32 temp_dword =readl (ctrl->hpc_reg +NON_INT_INPUT ); +dbg ("slot: %d, PCIXCAP: %8x\n" , hp_slot, temp_dword); +if (ctrl->pcix_support) { +if (temp_dword & (0x10000 << hp_slot)) +return PCI_SPEED_133MHz_PCIX; +if (temp_dword & (0x100 << hp_slot)) +return PCI_SPEED_66MHz_PCIX; + } + +if (temp_dword & (0x01 << hp_slot)) +return PCI_SPEED_66MHz; + +return PCI_SPEED_33MHz; +} + +static char *get_speed_string (int speed) +{ +switch (speed) { +case (PCI_SPEED_33MHz): +return "33MHz PCI" ; +case (PCI_SPEED_66MHz): +return "66MHz PCI" ; +case (PCI_SPEED_50MHz_PCIX): +return "50MHz PCI-X" ; +case (PCI_SPEED_66MHz_PCIX): +return "66MHz PCI-X" ; +case (PCI_SPEED_100MHz_PCIX): +return "100MHz PCI-X" ; +case (PCI_SPEED_133MHz_PCIX): +return "133MHz PCI-X" ; +default : +return "UNKNOWN" ; + } +}static inline void enable_slot_power (struct controller *ctrl,u8 slot) {
@@ -744,5 +820,139 @@ return retval; } -#endif +/** +* set_controller_speed - set the frequency and/or mode of a specific +* controller segment. +* +* @ctrl: controller to change frequency/mode for. +* @adapter_speed: the speed of the adapter we want to match. +* @hp_slot: the slot number where the adapter is installed. +* +* Returns 0 if we successfully change frequency and/or mode to match the +* adapter speed. +* +*/ +static inline u8 set_controller_speed (struct controller *ctrl,u8 adapter_speed,u8 hp_slot) +{ +struct slot *slot; +u8 reg; +u8 slot_power =readb (ctrl->hpc_reg +SLOT_POWER ); +u16 reg16; +u32 leds =readl (ctrl->hpc_reg +LED_CONTROL ); + +if (ctrl->speed == adapter_speed) +return 0 ; + +/* We don't allow freq/mode changes if we find another adapter running +* in another slot on this controller */ +for (slot = ctrl->slot; slot; slot = slot->next) { +if (slot->device == (hp_slot + ctrl->slot_device_offset)) +continue ; +if (!slot->hotplug_slot && !slot->hotplug_slot->info) +continue ; +if (slot->hotplug_slot->info->adapter_status ==0 ) +continue ; +/* If another adapter is running on the same segment but at a +* lower speed/mode, we allow the new adapter to function at +* this rate if supported */ +if (ctrl->speed < adapter_speed) +return 0 ; + +return 1 ; + } + +/* If the controller doesn't support freq/mode changes and the +* controller is running at a higher mode, we bail */ +if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability)) +return 1 ; + +/* But we allow the adapter to run at a lower rate if possible */ +if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability)) +return 0 ; + +/* We try to set the max speed supported by both the adapter and +* controller */ +if (ctrl->speed_capability < adapter_speed) { +if (ctrl->speed == ctrl->speed_capability) +return 0 ; + adapter_speed = ctrl->speed_capability; + } + +writel (0x0L , ctrl->hpc_reg +LED_CONTROL ); +writeb (0x00 , ctrl->hpc_reg +SLOT_ENABLE ); + +set_SOGO (ctrl); +wait_for_ctrl_irq (ctrl); + +if (adapter_speed != PCI_SPEED_133MHz_PCIX) + reg =0xF5 ; +else + reg =0xF4 ; +pci_write_config_byte (ctrl->pci_dev,0x41 , reg); + + reg16 =readw (ctrl->hpc_reg +NEXT_CURR_FREQ ); + reg16 &= ~0x000F ; +switch (adapter_speed) { +case (PCI_SPEED_133MHz_PCIX): + reg =0x75 ; + reg16 |=0xB ; +break ; +case (PCI_SPEED_100MHz_PCIX): + reg =0x74 ; + reg16 |=0xA ; +break ; +case (PCI_SPEED_66MHz_PCIX): + reg =0x73 ; + reg16 |=0x9 ; +break ; +case (PCI_SPEED_66MHz): + reg =0x73 ; + reg16 |=0x1 ; +break ; +default :/* 33MHz PCI 2.2 */ + reg =0x71 ; +break ; + + } + reg16 |=0xB <<12 ; +writew (reg16, ctrl->hpc_reg +NEXT_CURR_FREQ ); + +mdelay (5 ); + +/* Renable interrupts */ +writel (0 , ctrl->hpc_reg +INT_MASK ); +pci_write_config_byte (ctrl->pci_dev,0x41 , reg); + +/* Restart state machine */ + reg = ~0xF ; +pci_read_config_byte (ctrl->pci_dev,0x43 , ®); +pci_write_config_byte (ctrl->pci_dev,0x43 , reg); + +/* Only if mode change...*/ +if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) || + ((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) +set_SOGO (ctrl); + +wait_for_ctrl_irq (ctrl); +mdelay (1100 ); + +/* Restore LED/Slot state */ +writel (leds, ctrl->hpc_reg +LED_CONTROL ); +writeb (slot_power, ctrl->hpc_reg +SLOT_ENABLE ); + +set_SOGO (ctrl); +wait_for_ctrl_irq (ctrl); + + ctrl->speed = adapter_speed; + slot =find_slot (ctrl, hp_slot + ctrl->slot_device_offset); + +info ("Successfully changed frequency/mode for adapter in slot %d\n" , + slot->number); +info ("Bus %d now running in %s mode\n" , ctrl->pci_dev->bus->number, +get_speed_string (ctrl->speed)); + +return 0 ; +} + +#endif
drivers/hotplug/cpqphp_core.c +65 -8
123 lines not on this page · raw message
drivers/hotplug/cpqphp_ctrl.c +75 -60
199 lines not on this page · raw message
drivers/hotplug/cpqphp_proc.c +1 -0
@@ -54,6 +54,7 @@ out +=sprintf (out,"hot plug ctrl Info Page\n" ); out +=sprintf (out,"bus = %d, device = %d, function = %d\n" ,ctrl->bus, ctrl->device, ctrl->function); + out +=sprintf (out,"bus frequency/mode = %s\n" ,get_speed_string (ctrl->speed)); out +=sprintf (out,"Free resources: memory\n" ); index =11 ; res = ctrl->mem_head;
drivers/hotplug/pci_hotplug.h +4 -3
@@ -33,9 +33,10 @@enum pci_bus_speed { PCI_SPEED_33MHz =0x00 , PCI_SPEED_66MHz =0x01 , - PCI_SPEED_66MHz_PCIX =0x02 , - PCI_SPEED_100MHz_PCIX =0x03 , - PCI_SPEED_133MHz_PCIX =0x04 , + PCI_SPEED_50MHz_PCIX =0x02 , + PCI_SPEED_66MHz_PCIX =0x03 , + PCI_SPEED_100MHz_PCIX =0x04 , + PCI_SPEED_133MHz_PCIX =0x05 , PCI_SPEED_66MHz_PCIX_266 =0x09 , PCI_SPEED_100MHz_PCIX_266 =0x0a , PCI_SPEED_133MHz_PCIX_266 =0x0b ,
Quoted 6 lines · Torben Mathiasen
Hi Greg,
Attached is a patch against 2.4.20 (should apply to .21-pre3 and BK-current as well) that adds 66/100/133MHz PCI-X support to the Compaq Hotplug driver.
Please apply.
Looks almost ready. Could you make up a 2.5 version first? I don't like to have new features in 2.4 before they go into 2.5.
drivers/hotplug/cpqphp.h line 485
Quoted 3 lines
/* inline functions */
drivers/hotplug/cpqphp.h +1
-1- +extern inline struct slot *find_slot (struct controller *ctrl,u8 device);
Can you just make this a normal function then, with a more private name?
Quoted 9 lines
+/*
+ *get_controller_speed- find the current frequency/mode of controller.
+ *
+ * @ctrl: controller to get frequency/mode for.
+ *
+ * Returns controller speed.
+ *
+ */
static inline u8get_controller_speed(struct controller *ctrl)
Thanks for documenting this and get_adapter_speed().
Quoted 9 lines
drivers/hotplug/cpqphp.h +9
-0+static char *get_speed_string (int speed) +{ +switch (speed) { +case (PCI_SPEED_33MHz): +return "33MHz PCI" ; +case (PCI_SPEED_66MHz): +return "66MHz PCI" ; +case (PCI_SPEED_50MHz_PCIX): +return "50MHz PCI-X" ;
drivers/hotplug/cpqphp.h line 715
Quoted 10 lines
drivers/hotplug/cpqphp.h +10
-0+case (PCI_SPEED_66MHz_PCIX): +return "66MHz PCI-X" ; +case (PCI_SPEED_100MHz_PCIX): +return "100MHz PCI-X" ; +case (PCI_SPEED_133MHz_PCIX): +return "133MHz PCI-X" ; +default : +return "UNKNOWN" ; + } +}
Ick, why? Just for a debugging message? That /proc file is on the short list of things to delete :)
Quoted 6 lines
drivers/hotplug/pci_hotplug.h +0
-0@@ -33,9 +33,10 @@enum pci_bus_speed { PCI_SPEED_33MHz =0x00 , PCI_SPEED_66MHz =0x01 ,
drivers/hotplug/pci_hotplug.h line 42
Quoted 10 lines
drivers/hotplug/pci_hotplug.h +4
-3- PCI_SPEED_66MHz_PCIX =0x02 , - PCI_SPEED_100MHz_PCIX =0x03 , - PCI_SPEED_133MHz_PCIX =0x04 , + PCI_SPEED_50MHz_PCIX =0x02 , + PCI_SPEED_66MHz_PCIX =0x03 , + PCI_SPEED_100MHz_PCIX =0x04 , + PCI_SPEED_133MHz_PCIX =0x05 , PCI_SPEED_66MHz_PCIX_266 =0x09 , PCI_SPEED_100MHz_PCIX_266 =0x0a , PCI_SPEED_133MHz_PCIX_266 = 0x0b,
Where are you getting the PCI_SPEED_50MHz_PCIX value from? I took these values from the Hotplug PCI draft spec. Has 02 been reserved for 50MHz PCIX and the other values changed?
If it's not in the spec, I'd recommend adding it to the end of the list, with a big comment about why it's different from the spec values.
thanks,
greg k-h
Sure. I started out doing the patch for 2.5, but hit some hotplug bugs so I decided to get it working for 2.4 first and then port it to 2.5. I'll get on that.
A few comments below.
Quoted 14 lines
Quoted 14 lines
drivers/hotplug/cpqphp.h +14
-0+static char *get_speed_string (int speed) +{ +switch (speed) { +case (PCI_SPEED_33MHz): +return "33MHz PCI" ; +case (PCI_SPEED_66MHz): +return "66MHz PCI" ; +case (PCI_SPEED_50MHz_PCIX): +return "50MHz PCI-X" ; +case (PCI_SPEED_66MHz_PCIX): +return "66MHz PCI-X" ; +case (PCI_SPEED_100MHz_PCIX): +return "100MHz PCI-X" ; +case (PCI_SPEED_133MHz_PCIX):
Quoted 9 lines
drivers/hotplug/cpqphp.h line 715
Quoted 5 lines
drivers/hotplug/cpqphp.h +5
-0+return "133MHz PCI-X" ; +default : +return "UNKNOWN" ; + } +}Ick, why? Just for a debugging message? That /proc file is on the short list of things to delete :)
I wanted the user to be able to know exactly which bus speed/mode the driver switched to in case of a freq/mode change. Besides that it also put the info in proc as you mention.
Quoted 21 lines
Quoted 6 lines
drivers/hotplug/pci_hotplug.h +0
-0@@ -33,9 +33,10 @@enum pci_bus_speed { PCI_SPEED_33MHz =0x00 , PCI_SPEED_66MHz =0x01 ,drivers/hotplug/pci_hotplug.h line 42
Quoted 10 lines
drivers/hotplug/pci_hotplug.h +4
-3- PCI_SPEED_66MHz_PCIX =0x02 , - PCI_SPEED_100MHz_PCIX =0x03 , - PCI_SPEED_133MHz_PCIX =0x04 , + PCI_SPEED_50MHz_PCIX =0x02 , + PCI_SPEED_66MHz_PCIX =0x03 , + PCI_SPEED_100MHz_PCIX =0x04 , + PCI_SPEED_133MHz_PCIX =0x05 , PCI_SPEED_66MHz_PCIX_266 =0x09 , PCI_SPEED_100MHz_PCIX_266 =0x0a , PCI_SPEED_133MHz_PCIX_266 = 0x0b,Where are you getting the
PCI_SPEED_50MHz_PCIXvalue from? I took these values from the Hotplug PCI draft spec. Has 02 been reserved for 50MHz PCIX and the other values changed?
Quoted 3 lines
If it's not in the spec, I'd recommend adding it to the end of the list, with a big comment about why it's different from the spec values.
Sure, we used to ship a system that only supported 50MHz PCI-X, but I'll have to get more details on that.
Torben
Quoted 3 lines · Torben Mathiasen
Sure. I started out doing the patch for 2.5, but hit some hotplug bugs so I decided to get it working for 2.4 first and then port it to 2.5. I'll get on that.
Thanks.
Quoted 3 lines
I wanted the user to be able to know exactly which bus speed/mode the driver switched to in case of a freq/mode change. Besides that it also put the info in proc as you mention.
But that is what the cur_bus_speed and max_bus_speed files in pcihpfs for the slot are for, right? Isn't this just duplicating that information?
Quoted 2 lines
Sure, we used to ship a system that only supported 50MHz PCI-X, but I'll have to get more details on that.
So 50MHz PCI-X is not in the spec, right? If you all supported it, why didn't you get it included in the spec? :)
thanks,
greg k-h