Commit a8a2be94 authored by rajesh.shah@intel.com's avatar rajesh.shah@intel.com Committed by Greg Kroah-Hartman

[PATCH] pciehp: reduce dependence on ACPI

Reduce the PCI Express hotplug driver's dependence on ACPI.
We don't walk the acpi namespace anymore to build a list of
bridges and devices. We go to ACPI only to run the _OSC or
_OSHP methods to transition control of hotplug hardware from
system BIOS to the hotplug driver, and to run the _HPP
method to get hotplug device parameters like cache line size,
latency timer and SERR/PERR enable from BIOS.

Note that one of the side effects of this patch is that pciehp
does not automatically enable the hot-added device or its DMA
bus mastering capability now. It expects the device driver to
do that. This may break some drivers and we will have to fix
them as they are reported.
Signed-off-by: default avatarRajesh Shah <rajesh.shah@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 71b720c0
...@@ -49,6 +49,13 @@ extern int pciehp_debug; ...@@ -49,6 +49,13 @@ extern int pciehp_debug;
#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
struct hotplug_params {
u8 cache_line_size;
u8 latency_timer;
u8 enable_serr;
u8 enable_perr;
};
struct pci_func { struct pci_func {
struct pci_func *next; struct pci_func *next;
u8 bus; u8 bus;
...@@ -199,6 +206,10 @@ extern int pciehp_save_config (struct controller *ctrl, int busnumber, int num ...@@ -199,6 +206,10 @@ extern int pciehp_save_config (struct controller *ctrl, int busnumber, int num
extern int pciehp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); extern int pciehp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot);
extern int pciehp_configure_device (struct slot *ctrl); extern int pciehp_configure_device (struct slot *ctrl);
extern int pciehp_unconfigure_device (struct pci_func* func); extern int pciehp_unconfigure_device (struct pci_func* func);
extern int get_hp_hw_control_from_firmware(struct pci_dev *dev);
extern void get_hp_params_from_firmware(struct pci_dev *dev,
struct hotplug_params *hpp);
/* Global variables */ /* Global variables */
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "pciehp.h" #include "pciehp.h"
#include "pciehprm.h"
#include <linux/interrupt.h> #include <linux/interrupt.h>
/* Global variables */ /* Global variables */
...@@ -381,6 +380,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ ...@@ -381,6 +380,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
dbg("%s: DRV_thread pid = %d\n", __FUNCTION__, current->pid); dbg("%s: DRV_thread pid = %d\n", __FUNCTION__, current->pid);
pdev = dev->port; pdev = dev->port;
ctrl->pci_dev = pdev;
rc = pcie_init(ctrl, dev, rc = pcie_init(ctrl, dev,
(php_intr_callback_t) pciehp_handle_attention_button, (php_intr_callback_t) pciehp_handle_attention_button,
...@@ -392,8 +392,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ ...@@ -392,8 +392,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
goto err_out_free_ctrl; goto err_out_free_ctrl;
} }
ctrl->pci_dev = pdev;
pci_set_drvdata(pdev, ctrl); pci_set_drvdata(pdev, ctrl);
ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL); ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL);
...@@ -609,18 +607,14 @@ static int __init pcied_init(void) ...@@ -609,18 +607,14 @@ static int __init pcied_init(void)
if (retval) if (retval)
goto error_hpc_init; goto error_hpc_init;
retval = pciehprm_init(PCI);
if (!retval) {
retval = pcie_port_service_register(&hpdriver_portdrv); retval = pcie_port_service_register(&hpdriver_portdrv);
dbg("pcie_port_service_register = %d\n", retval); dbg("pcie_port_service_register = %d\n", retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
if (retval) if (retval)
dbg("%s: Failure to register service\n", __FUNCTION__); dbg("%s: Failure to register service\n", __FUNCTION__);
}
error_hpc_init: error_hpc_init:
if (retval) { if (retval) {
pciehprm_cleanup();
pciehp_event_stop_thread(); pciehp_event_stop_thread();
}; };
...@@ -632,8 +626,6 @@ static void __exit pcied_cleanup(void) ...@@ -632,8 +626,6 @@ static void __exit pcied_cleanup(void)
dbg("unload_pciehpd()\n"); dbg("unload_pciehpd()\n");
unload_pciehpd(); unload_pciehpd();
pciehprm_cleanup();
dbg("pcie_port_service_unregister\n"); dbg("pcie_port_service_unregister\n");
pcie_port_service_unregister(&hpdriver_portdrv); pcie_port_service_unregister(&hpdriver_portdrv);
......
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#include <linux/pci.h> #include <linux/pci.h>
#include "../pci.h" #include "../pci.h"
#include "pciehp.h" #include "pciehp.h"
#include "pciehprm.h"
static void interrupt_event_handler(struct controller *ctrl); static void interrupt_event_handler(struct controller *ctrl);
......
...@@ -1470,6 +1470,10 @@ int pcie_init(struct controller * ctrl, ...@@ -1470,6 +1470,10 @@ int pcie_init(struct controller * ctrl,
} }
dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word); dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word);
rc = get_hp_hw_control_from_firmware(ctrl->pci_dev);
if (rc)
goto abort_free_ctlr;
/* Add this HPC instance into the HPC list */ /* Add this HPC instance into the HPC list */
spin_lock(&list_lock); spin_lock(&list_lock);
if (php_ctlr_list_head == 0) { if (php_ctlr_list_head == 0) {
......
/*
* PCIEHPRM : PCIEHP Resource Manager for ACPI/non-ACPI platform
*
* Copyright (C) 1995,2001 Compaq Computer Corporation
* Copyright (C) 2001,2003 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.
*
* Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
*
*/
#ifndef _PCIEHPRM_H_
#define _PCIEHPRM_H_
#ifdef CONFIG_HOTPLUG_PCI_PCIE_PHPRM_NONACPI
#include "pciehprm_nonacpi.h"
#endif
int pciehprm_init(enum php_ctlr_type ct);
void pciehprm_cleanup(void);
int pciehprm_print_pirt(void);
int pciehprm_find_available_resources(struct controller *ctrl);
int pciehprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type);
void pciehprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type);
#ifdef DEBUG
#define RES_CHECK(this, bits) \
{ if (((this) & (bits - 1))) \
printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); }
#else
#define RES_CHECK(this, bits)
#endif
#endif /* _PCIEHPRM_H_ */
This diff is collapsed.
...@@ -37,15 +37,9 @@ ...@@ -37,15 +37,9 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "pciehp.h" #include "pciehp.h"
#include "pciehprm.h"
#include "pciehprm_nonacpi.h" #include "pciehprm_nonacpi.h"
void pciehprm_cleanup(void)
{
return;
}
int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
{ {
...@@ -53,106 +47,13 @@ int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn ...@@ -53,106 +47,13 @@ int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn
return 0; return 0;
} }
int pciehprm_set_hpp( void get_hp_params_from_firmware(struct pci_dev *dev,
struct controller *ctrl, struct hotplug_params *hpp)
struct pci_func *func,
u8 card_type)
{
u32 rc;
u8 temp_byte;
struct pci_bus lpci_bus, *pci_bus;
unsigned int devfn;
memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
pci_bus = &lpci_bus;
pci_bus->number = func->bus;
devfn = PCI_DEVFN(func->device, func->function);
temp_byte = 0x40; /* hard coded value for LT */
if (card_type == PCI_HEADER_TYPE_BRIDGE) {
/* set subordinate Latency Timer */
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
if (rc) {
dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__,
func->bus, func->device, func->function);
return rc;
}
}
/* set base Latency Timer */
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
if (rc) {
dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
return rc;
}
/* set Cache Line size */
temp_byte = 0x08; /* hard coded value for CLS */
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
if (rc) {
dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
}
/* set enable_perr */
/* set enable_serr */
return rc;
}
void pciehprm_enable_card(
struct controller *ctrl,
struct pci_func *func,
u8 card_type)
{ {
u16 command, bcommand; return;
struct pci_bus lpci_bus, *pci_bus;
unsigned int devfn;
int rc;
memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
pci_bus = &lpci_bus;
pci_bus->number = func->bus;
devfn = PCI_DEVFN(func->device, func->function);
rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR
| PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
if (card_type == PCI_HEADER_TYPE_BRIDGE) {
rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR
| PCI_BRIDGE_CTL_NO_ISA;
rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
}
} }
static int legacy_pciehprm_init_pci(void) int get_hp_hw_control_from_firmware(struct pci_dev *dev)
{ {
return 0; return 0;
} }
int pciehprm_init(enum php_ctlr_type ctrl_type)
{
int retval;
switch (ctrl_type) {
case PCI:
retval = legacy_pciehprm_init_pci();
break;
default:
retval = -ENODEV;
break;
}
return retval;
}
/*
* PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
*
* 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.
*
* Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
*
*/
#ifndef _PCIEHPRM_NONACPI_H_
#define _PCIEHPRM_NONACPI_H_
struct irq_info {
u8 bus, devfn; /* bus, device and function */
struct {
u8 link; /* IRQ line ID, chipset dependent, 0=not routed */
u16 bitmap; /* Available IRQs */
} __attribute__ ((packed)) irq[4];
u8 slot; /* slot number, 0=onboard */
u8 rfu;
} __attribute__ ((packed));
struct irq_routing_table {
u32 signature; /* PIRQ_SIGNATURE should be here */
u16 version; /* PIRQ_VERSION */
u16 size; /* Table size in bytes */
u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */
u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */
u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */
u32 miniport_data; /* Crap */
u8 rfu[11];
u8 checksum; /* Modulo 256 checksum must give zero */
struct irq_info slots[0];
} __attribute__ ((packed));
#endif /* _PCIEHPRM_NONACPI_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment