123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- /*
- * WHCI UWB Multi-interface Controller enumerator.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- *
- * This file is released under the GNU GPL v2.
- */
- #include <linux/delay.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/pci.h>
- #include <linux/dma-mapping.h>
- #include <linux/slab.h>
- #include <linux/uwb/whci.h>
- #include <linux/uwb/umc.h>
- struct whci_card {
- struct pci_dev *pci;
- void __iomem *uwbbase;
- u8 n_caps;
- struct umc_dev *devs[0];
- };
- /* Fix faulty HW :( */
- static
- u64 whci_capdata_quirks(struct whci_card *card, u64 capdata)
- {
- u64 capdata_orig = capdata;
- struct pci_dev *pci_dev = card->pci;
- if (pci_dev->vendor == PCI_VENDOR_ID_INTEL
- && (pci_dev->device == 0x0c3b || pci_dev->device == 0004)
- && pci_dev->class == 0x0d1010) {
- switch (UWBCAPDATA_TO_CAP_ID(capdata)) {
- /* WLP capability has 0x100 bytes of aperture */
- case 0x80:
- capdata |= 0x40 << 8; break;
- /* WUSB capability has 0x80 bytes of aperture
- * and ID is 1 */
- case 0x02:
- capdata &= ~0xffff;
- capdata |= 0x2001;
- break;
- }
- }
- if (capdata_orig != capdata)
- dev_warn(&pci_dev->dev,
- "PCI v%04x d%04x c%06x#%02x: "
- "corrected capdata from %016Lx to %016Lx\n",
- pci_dev->vendor, pci_dev->device, pci_dev->class,
- (unsigned)UWBCAPDATA_TO_CAP_ID(capdata),
- (unsigned long long)capdata_orig,
- (unsigned long long)capdata);
- return capdata;
- }
- /**
- * whci_wait_for - wait for a WHCI register to be set
- *
- * Polls (for at most @max_ms ms) until '*@reg & @mask == @result'.
- */
- int whci_wait_for(struct device *dev, u32 __iomem *reg, u32 mask, u32 result,
- unsigned long max_ms, const char *tag)
- {
- unsigned t = 0;
- u32 val;
- for (;;) {
- val = le_readl(reg);
- if ((val & mask) == result)
- break;
- if (t >= max_ms) {
- dev_err(dev, "%s timed out\n", tag);
- return -ETIMEDOUT;
- }
- msleep(10);
- t += 10;
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(whci_wait_for);
- /*
- * NOTE: the capinfo and capdata registers are slightly different
- * (size and cap-id fields). So for cap #0, we need to fill
- * in. Size comes from the size of the register block
- * (statically calculated); cap_id comes from nowhere, we use
- * zero, that is reserved, for the radio controller, because
- * none was defined at the spec level.
- */
- static int whci_add_cap(struct whci_card *card, int n)
- {
- struct umc_dev *umc;
- u64 capdata;
- int bar, err;
- umc = umc_device_create(&card->pci->dev, n);
- if (umc == NULL)
- return -ENOMEM;
- capdata = le_readq(card->uwbbase + UWBCAPDATA(n));
- bar = UWBCAPDATA_TO_BAR(capdata) << 1;
- capdata = whci_capdata_quirks(card, capdata);
- /* Capability 0 is the radio controller. It's size is 32
- * bytes (WHCI0.95[2.3, T2-9]). */
- umc->version = UWBCAPDATA_TO_VERSION(capdata);
- umc->cap_id = n == 0 ? 0 : UWBCAPDATA_TO_CAP_ID(capdata);
- umc->bar = bar;
- umc->resource.start = pci_resource_start(card->pci, bar)
- + UWBCAPDATA_TO_OFFSET(capdata);
- umc->resource.end = umc->resource.start
- + (n == 0 ? 0x20 : UWBCAPDATA_TO_SIZE(capdata)) - 1;
- umc->resource.name = dev_name(&umc->dev);
- umc->resource.flags = card->pci->resource[bar].flags;
- umc->resource.parent = &card->pci->resource[bar];
- umc->irq = card->pci->irq;
- err = umc_device_register(umc);
- if (err < 0)
- goto error;
- card->devs[n] = umc;
- return 0;
- error:
- kfree(umc);
- return err;
- }
- static void whci_del_cap(struct whci_card *card, int n)
- {
- struct umc_dev *umc = card->devs[n];
- umc_device_unregister(umc);
- }
- static int whci_n_caps(struct pci_dev *pci)
- {
- void __iomem *uwbbase;
- u64 capinfo;
- uwbbase = pci_iomap(pci, 0, 8);
- if (!uwbbase)
- return -ENOMEM;
- capinfo = le_readq(uwbbase + UWBCAPINFO);
- pci_iounmap(pci, uwbbase);
- return UWBCAPINFO_TO_N_CAPS(capinfo);
- }
- static int whci_probe(struct pci_dev *pci, const struct pci_device_id *id)
- {
- struct whci_card *card;
- int err, n_caps, n;
- err = pci_enable_device(pci);
- if (err < 0)
- goto error;
- pci_enable_msi(pci);
- pci_set_master(pci);
- err = -ENXIO;
- if (!pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
- pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
- else if (!pci_set_dma_mask(pci, DMA_BIT_MASK(32)))
- pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
- else
- goto error_dma;
- err = n_caps = whci_n_caps(pci);
- if (n_caps < 0)
- goto error_ncaps;
- err = -ENOMEM;
- card = kzalloc(sizeof(struct whci_card)
- + sizeof(struct umc_dev *) * (n_caps + 1),
- GFP_KERNEL);
- if (card == NULL)
- goto error_kzalloc;
- card->pci = pci;
- card->n_caps = n_caps;
- err = -EBUSY;
- if (!request_mem_region(pci_resource_start(pci, 0),
- UWBCAPDATA_SIZE(card->n_caps),
- "whci (capability data)"))
- goto error_request_memregion;
- err = -ENOMEM;
- card->uwbbase = pci_iomap(pci, 0, UWBCAPDATA_SIZE(card->n_caps));
- if (!card->uwbbase)
- goto error_iomap;
- /* Add each capability. */
- for (n = 0; n <= card->n_caps; n++) {
- err = whci_add_cap(card, n);
- if (err < 0 && n == 0) {
- dev_err(&pci->dev, "cannot bind UWB radio controller:"
- " %d\n", err);
- goto error_bind;
- }
- if (err < 0)
- dev_warn(&pci->dev, "warning: cannot bind capability "
- "#%u: %d\n", n, err);
- }
- pci_set_drvdata(pci, card);
- return 0;
- error_bind:
- pci_iounmap(pci, card->uwbbase);
- error_iomap:
- release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps));
- error_request_memregion:
- kfree(card);
- error_kzalloc:
- error_ncaps:
- error_dma:
- pci_disable_msi(pci);
- pci_disable_device(pci);
- error:
- return err;
- }
- static void whci_remove(struct pci_dev *pci)
- {
- struct whci_card *card = pci_get_drvdata(pci);
- int n;
- pci_set_drvdata(pci, NULL);
- /* Unregister each capability in reverse (so the master device
- * is unregistered last). */
- for (n = card->n_caps; n >= 0 ; n--)
- whci_del_cap(card, n);
- pci_iounmap(pci, card->uwbbase);
- release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps));
- kfree(card);
- pci_disable_msi(pci);
- pci_disable_device(pci);
- }
- static struct pci_device_id whci_id_table[] = {
- { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
- { 0 },
- };
- MODULE_DEVICE_TABLE(pci, whci_id_table);
- static struct pci_driver whci_driver = {
- .name = "whci",
- .id_table = whci_id_table,
- .probe = whci_probe,
- .remove = whci_remove,
- };
- module_pci_driver(whci_driver);
- MODULE_DESCRIPTION("WHCI UWB Multi-interface Controller enumerator");
- MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
- MODULE_LICENSE("GPL");
|