Commit a00aa6c5 authored by Russell King's avatar Russell King

[PCMCIA] pcmcia-10: Make cardbus use the new PCI functionality.

Now that we have the critical PCI changes in place, we can convert
cardbus to use this PCI functionality.  This allows us to scan
behind PCI to PCI bridges on cardbus cards, and setup the bus
resources using the generic PCI support code.

Note that drivers/pci/setup-bus.c needs to be built when hotplug
(ie, cardbus) is enabled.
parent 00dbc966
...@@ -29,6 +29,9 @@ ifdef CONFIG_HOTPLUG_PCI_CPCI ...@@ -29,6 +29,9 @@ ifdef CONFIG_HOTPLUG_PCI_CPCI
obj-y += setup-bus.o obj-y += setup-bus.o
endif endif
# Hotplug (eg, cardbus) now requires setup-bus
obj-$(CONFIG_HOTPLUG) += setup-bus.o
ifndef CONFIG_X86 ifndef CONFIG_X86
obj-y += syscall.o obj-y += syscall.o
endif endif
......
...@@ -89,10 +89,6 @@ static int pc_debug = PCMCIA_DEBUG; ...@@ -89,10 +89,6 @@ static int pc_debug = PCMCIA_DEBUG;
#define PCDATA_CODE_TYPE 0x0014 #define PCDATA_CODE_TYPE 0x0014
#define PCDATA_INDICATOR 0x0015 #define PCDATA_INDICATOR 0x0015
typedef struct cb_config_t {
struct pci_dev *dev[8];
} cb_config_t;
/*===================================================================== /*=====================================================================
Expansion ROM's have a special layout, and pointers specify an Expansion ROM's have a special layout, and pointers specify an
...@@ -175,11 +171,10 @@ int read_cb_mem(socket_info_t * s, int space, u_int addr, u_int len, void *ptr) ...@@ -175,11 +171,10 @@ int read_cb_mem(socket_info_t * s, int space, u_int addr, u_int len, void *ptr)
DEBUG(3, "cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len); DEBUG(3, "cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len);
if (!s->cb_config) dev = pci_find_slot(s->cap.cb_dev->subordinate->number, 0);
if (!dev)
goto fail; goto fail;
dev = s->cb_config->dev[0];
/* Config space? */ /* Config space? */
if (space == 0) { if (space == 0) {
if (addr + len > 0x100) if (addr + len > 0x100)
...@@ -221,109 +216,61 @@ int read_cb_mem(socket_info_t * s, int space, u_int addr, u_int len, void *ptr) ...@@ -221,109 +216,61 @@ int read_cb_mem(socket_info_t * s, int space, u_int addr, u_int len, void *ptr)
=====================================================================*/ =====================================================================*/
int cb_alloc(socket_info_t * s) /*
* Since there is only one interrupt available to CardBus
* devices, all devices downstream of this device must
* be using this IRQ.
*/
static void cardbus_assign_irqs(struct pci_bus *bus, int irq)
{ {
struct pci_bus *bus; struct pci_dev *dev;
u_short vend, v, dev;
u_char i, hdr, fn;
cb_config_t *c;
int irq;
bus = s->cap.cb_dev->subordinate;
pci_bus_read_config_word(bus, 0, PCI_VENDOR_ID, &vend);
pci_bus_read_config_word(bus, 0, PCI_DEVICE_ID, &dev);
printk(KERN_INFO "cs: cb_alloc(bus %d): vendor 0x%04x, "
"device 0x%04x\n", bus->number, vend, dev);
pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr);
fn = 1;
if (hdr & 0x80) {
do {
if (pci_bus_read_config_word(bus, fn, PCI_VENDOR_ID, &v) ||
!v || v == 0xffff)
break;
fn++;
} while (fn < 8);
}
s->functions = fn;
c = kmalloc(sizeof(struct cb_config_t), GFP_ATOMIC);
if (!c)
return CS_OUT_OF_RESOURCE;
memset(c, 0, sizeof(struct cb_config_t));
for (i = 0; i < fn; i++) {
c->dev[i] = kmalloc(sizeof(struct pci_dev), GFP_ATOMIC);
if (!c->dev[i]) {
for (; i--; )
kfree(c->dev[i]);
kfree(c);
return CS_OUT_OF_RESOURCE;
}
memset(c->dev[i], 0, sizeof(struct pci_dev));
}
irq = s->cap.pci_irq; list_for_each_entry(dev, &bus->devices, bus_list) {
for (i = 0; i < fn; i++) {
struct pci_dev *dev = c->dev[i];
u8 irq_pin; u8 irq_pin;
int r;
dev->bus = bus;
dev->sysdata = bus->sysdata;
dev->dev.parent = bus->dev;
dev->dev.bus = &pci_bus_type;
dev->devfn = i;
pci_read_config_word(dev, PCI_VENDOR_ID, &dev->vendor);
pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
dev->hdr_type = hdr & 0x7f;
dev->dma_mask = 0xffffffff;
dev->dev.dma_mask = &dev->dma_mask;
pci_setup_device(dev);
strcpy(dev->dev.bus_id, dev->slot_name);
/* We need to assign resources for expansion ROM. */
for (r = 0; r < 7; r++) {
struct resource *res = dev->resource + r;
if (res->flags)
pci_assign_resource(dev, r);
}
/* Does this function have an interrupt at all? */
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
if (irq_pin) if (irq_pin) {
dev->irq = irq; dev->irq = irq;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
/* pci_enable_device needs to be called after pci_assign_resource */ }
/* because it returns an error if (!res->start && res->end). */
if (pci_enable_device(dev)) if (dev->subordinate)
continue; cardbus_assign_irqs(dev->subordinate, irq);
if (irq_pin)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
device_register(&dev->dev);
pci_insert_device(dev, bus);
} }
}
s->cb_config = c; int cb_alloc(socket_info_t * s)
s->irq.AssignedIRQ = irq; {
struct pci_bus *bus = s->cap.cb_dev->subordinate;
struct pci_dev *dev;
unsigned int max, pass;
s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0));
// pcibios_fixup_bus(bus);
max = bus->secondary;
for (pass = 0; pass < 2; pass++)
list_for_each_entry(dev, &bus->devices, bus_list)
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
max = pci_scan_bridge(bus, dev, max, pass);
/*
* Size all resources below the CardBus controller.
*/
pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus);
cardbus_assign_irqs(bus, s->cap.pci_irq);
pci_enable_bridges(bus);
pci_bus_add_devices(bus);
s->irq.AssignedIRQ = s->cap.pci_irq;
return CS_SUCCESS; return CS_SUCCESS;
} }
void cb_free(socket_info_t * s) void cb_free(socket_info_t * s)
{ {
cb_config_t *c = s->cb_config; struct pci_dev *bridge = s->cap.cb_dev;
if (c) { pci_remove_behind_bridge(bridge);
s->cb_config = NULL;
pci_remove_behind_bridge(s->cap.cb_dev);
kfree(c);
printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cb_dev->subordinate->number);
}
} }
...@@ -396,11 +396,9 @@ int pcmcia_get_first_tuple(client_handle_t handle, tuple_t *tuple) ...@@ -396,11 +396,9 @@ int pcmcia_get_first_tuple(client_handle_t handle, tuple_t *tuple)
tuple->TupleLink = tuple->Flags = 0; tuple->TupleLink = tuple->Flags = 0;
#ifdef CONFIG_CARDBUS #ifdef CONFIG_CARDBUS
if (s->state & SOCKET_CARDBUS) { if (s->state & SOCKET_CARDBUS) {
struct pci_dev *dev = s->cap.cb_dev;
u_int ptr; u_int ptr;
struct pci_dev *dev = pci_find_slot (s->cap.cb_dev->subordinate->number, 0); pci_bus_read_config_dword(dev->subordinate, 0, PCI_CARDBUS_CIS, &ptr);
if (!dev)
return CS_BAD_HANDLE;
pci_read_config_dword(dev, 0x28, &ptr);
tuple->CISOffset = ptr & ~7; tuple->CISOffset = ptr & ~7;
SPACE(tuple->Flags) = (ptr & 7); SPACE(tuple->Flags) = (ptr & 7);
} else } else
......
...@@ -136,7 +136,6 @@ typedef struct socket_info_t { ...@@ -136,7 +136,6 @@ typedef struct socket_info_t {
#ifdef CONFIG_CARDBUS #ifdef CONFIG_CARDBUS
struct resource * cb_cis_res; struct resource * cb_cis_res;
u_char *cb_cis_virt; u_char *cb_cis_virt;
struct cb_config_t *cb_config;
#endif #endif
struct { struct {
u_int AssignedIRQ; u_int AssignedIRQ;
......
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