summaryrefslogtreecommitdiff
path: root/package/acx
diff options
context:
space:
mode:
authorflorian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73>2008-01-04 02:10:09 +0000
committerflorian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73>2008-01-04 02:10:09 +0000
commit379d926d214f384ab4591566ee4e29f32b10b4ee (patch)
tree79db1267a8dffa4c72e8052d6148da6362d48b43 /package/acx
parent2b34935d2a755953f759811bf4437ba266f65efc (diff)
Add native vlynq support to the old acx driver (#2864)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@10102 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/acx')
-rw-r--r--package/acx/patches/003-native_vlynq.patch557
1 files changed, 557 insertions, 0 deletions
diff --git a/package/acx/patches/003-native_vlynq.patch b/package/acx/patches/003-native_vlynq.patch
new file mode 100644
index 0000000000..cdbe335ca5
--- /dev/null
+++ b/package/acx/patches/003-native_vlynq.patch
@@ -0,0 +1,557 @@
+Binary files acx-20071003/.pci.c.swp and acx-20071003.new/.pci.c.swp differ
+diff -urN acx-20071003/acx_struct.h acx-20071003.new/acx_struct.h
+--- acx-20071003/acx_struct.h 2007-10-03 17:42:18.000000000 +0200
++++ acx-20071003.new/acx_struct.h 2008-01-04 02:06:43.000000000 +0100
+@@ -1440,7 +1440,13 @@
+
+ const u16 *io; /* points to ACX100 or ACX111 PCI I/O register address set */
+
++#ifdef CONFIG_PCI
+ struct pci_dev *pdev;
++#endif
++#ifdef CONFIG_VLYNQ
++ struct vlynq_device *vdev;
++#endif
++ struct device *bus_dev;
+
+ unsigned long membase;
+ unsigned long membase2;
+diff -urN acx-20071003/pci.c acx-20071003.new/pci.c
+--- acx-20071003/pci.c 2008-01-04 02:05:00.000000000 +0100
++++ acx-20071003.new/pci.c 2008-01-04 03:10:42.000000000 +0100
+@@ -59,12 +59,17 @@
+ #include <linux/pm.h>
+ #include <linux/vmalloc.h>
+ #include <linux/dma-mapping.h>
++#ifdef CONFIG_VLYNQ
++#include <linux/vlynq.h>
++#endif
++
+
+ #include "acx.h"
+
+
+ /***********************************************************************
+ */
++#ifdef CONFIG_PCI
+ #define PCI_TYPE (PCI_USES_MEM | PCI_ADDR0 | PCI_NO_ACPI_WAKE)
+ #define PCI_ACX100_REGION1 0x01
+ #define PCI_ACX100_REGION1_SIZE 0x1000 /* Memory size - 4K bytes */
+@@ -102,7 +107,7 @@
+ #define PCI_POWER_ERROR -1
+ #endif
+
+-
++#endif
+ /***********************************************************************
+ */
+ static void acxpci_i_tx_timeout(struct net_device *ndev);
+@@ -653,11 +658,11 @@
+ snprintf(filename, sizeof(filename), "tiacx1%02dc%02X",
+ IS_ACX111(adev)*11, adev->radio_type);
+
+- fw_image = acx_s_read_fw(&adev->pdev->dev, filename, &file_size);
++ fw_image = acx_s_read_fw(adev->bus_dev, filename, &file_size);
+ if (!fw_image) {
+ adev->need_radio_fw = 1;
+ filename[sizeof("tiacx1NN")-1] = '\0';
+- fw_image = acx_s_read_fw(&adev->pdev->dev, filename, &file_size);
++ fw_image = acx_s_read_fw(adev->bus_dev, filename, &file_size);
+ if (!fw_image) {
+ FN_EXIT1(NOT_OK);
+ return NOT_OK;
+@@ -716,7 +721,7 @@
+ snprintf(filename, sizeof(filename), "tiacx1%02dr%02X",
+ IS_ACX111(adev)*11,
+ adev->radio_type);
+- radio_image = acx_s_read_fw(&adev->pdev->dev, filename, &size);
++ radio_image = acx_s_read_fw(adev->bus_dev, filename, &size);
+ if (!radio_image) {
+ printk("acx: can't load radio module '%s'\n", filename);
+ goto fail;
+@@ -933,7 +938,9 @@
+
+ ecpu_ctrl = read_reg16(adev, IO_ACX_ECPU_CTRL) & 1;
+ if (!ecpu_ctrl) {
++#ifdef CONFIG_PCI
+ acxpci_l_reset_mac(adev);
++#endif
+ ecpu_ctrl = read_reg16(adev, IO_ACX_ECPU_CTRL) & 1;
+ }
+
+@@ -1473,6 +1480,7 @@
+ static void
+ dummy_netdev_init(struct net_device *ndev) {}
+
++#ifdef CONFIG_PCI
+ static int __devinit
+ acxpci_e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ {
+@@ -1606,6 +1614,7 @@
+ ** just _presume_ that we're under sem (instead of actually taking it): */
+ /* acx_sem_lock(adev); */
+ adev->pdev = pdev;
++ adev->bus_dev = &pdev->dev;
+ adev->ndev = ndev;
+ adev->dev_type = DEVTYPE_PCI;
+ adev->chip_type = chip_type;
+@@ -1956,7 +1965,7 @@
+ return OK;
+ }
+ #endif /* CONFIG_PM */
+-
++#endif /* CONFIG_PCI */
+
+ /***********************************************************************
+ ** acxpci_s_up
+@@ -2051,7 +2060,7 @@
+ /* then wait until interrupts have finished executing on other CPUs */
+ acx_lock(adev, flags);
+ disable_acx_irq(adev);
+- synchronize_irq(adev->pdev->irq);
++ synchronize_irq(adev->irq);
+ acx_unlock(adev, flags);
+
+ /* we really don't want to have an asynchronous tasklet disturb us
+@@ -3573,9 +3582,8 @@
+ {
+ void *ptr;
+
+- ptr = dma_alloc_coherent(adev->pdev ? &adev->pdev->dev : NULL,
+- size, phy, GFP_KERNEL);
+-
++ ptr = dma_alloc_coherent(adev->bus_dev, size, phy, GFP_KERNEL);
++
+ if (ptr) {
+ log(L_DEBUG, "%s sz=%d adr=0x%p phy=0x%08llx\n",
+ msg, (int)size, ptr, (unsigned long long)*phy);
+@@ -4137,6 +4145,379 @@
+ }
+
+
++#ifdef CONFIG_VLYNQ
++struct vlynq_reg_config {
++ u32 offset;
++ u32 value;
++};
++
++struct vlynq_known {
++ u32 chip_id;
++ char name[32];
++ struct vlynq_mapping rx_mapping[4];
++ int irq;
++ int irq_type;
++ int num_regs;
++ struct vlynq_reg_config regs[10];
++};
++
++#define CHIP_TNETW1130 0x00000009
++#define CHIP_TNETW1350 0x00000029
++static struct vlynq_known known_devices[] = {
++ {
++ .chip_id = CHIP_TNETW1130, .name = "TI TNETW1130",
++ .rx_mapping = {
++ { .size = 0x22000, .offset = 0xf0000000 },
++ { .size = 0x40000, .offset = 0xc0000000 },
++ { .size = 0x0, .offset = 0x0 },
++ { .size = 0x0, .offset = 0x0 },
++ },
++ .irq = 0,
++ .irq_type = IRQ_TYPE_EDGE_RISING,
++ .num_regs = 5,
++ .regs = {
++ {
++ .offset = 0x790,
++ .value = (0xd0000000 - PHYS_OFFSET)
++ },
++ {
++ .offset = 0x794,
++ .value = (0xd0000000 - PHYS_OFFSET)
++ },
++ { .offset = 0x740, .value = 0 },
++ { .offset = 0x744, .value = 0x00010000 },
++ { .offset = 0x764, .value = 0x00010000 },
++ },
++ },
++ {
++ .chip_id = CHIP_TNETW1350, .name = "TI TNETW1350",
++ .rx_mapping = {
++ { .size = 0x100000, .offset = 0x00300000 },
++ { .size = 0x80000, .offset = 0x00000000 },
++ { .size = 0x0, .offset = 0x0 },
++ { .size = 0x0, .offset = 0x0 },
++ },
++ .irq = 0,
++ .irq_type = IRQ_TYPE_EDGE_RISING,
++ .num_regs = 5,
++ .regs = {
++ {
++ .offset = 0x790,
++ .value = (0x60000000 - PHYS_OFFSET)
++ },
++ {
++ .offset = 0x794,
++ .value = (0x60000000 - PHYS_OFFSET)
++ },
++ { .offset = 0x740, .value = 0 },
++ { .offset = 0x744, .value = 0x00010000 },
++ { .offset = 0x764, .value = 0x00010000 },
++ },
++ },
++};
++
++static struct vlynq_device_id acx_vlynq_id[] = {
++ { CHIP_TNETW1130, vlynq_div_auto, 0 },
++ { CHIP_TNETW1350, vlynq_div_auto, 1 },
++ { 0, 0, 0 },
++};
++
++static __devinit int vlynq_probe(struct vlynq_device *vdev,
++ struct vlynq_device_id *id)
++{
++ int result = -EIO, i;
++ u32 addr;
++ acx_device_t *adev = NULL;
++ struct net_device *ndev = NULL;
++ acx111_ie_configoption_t co;
++ struct vlynq_mapping mapping[4] = { { 0, }, };
++ struct vlynq_known *match = NULL;
++ int err;
++
++ FN_ENTER;
++ result = vlynq_enable_device(vdev);
++ if (result)
++ return result;
++
++ match = &known_devices[id->driver_data];
++
++ if (!match) {
++ result = -ENODEV;
++ goto fail;
++ }
++
++ mapping[0].offset = ARCH_PFN_OFFSET << PAGE_SHIFT;
++ mapping[0].size = 0x02000000;
++ vlynq_set_local_mapping(vdev, vdev->mem_start, mapping);
++ vlynq_set_remote_mapping(vdev, 0, match->rx_mapping);
++
++ set_irq_type(vlynq_virq_to_irq(vdev, match->irq), match->irq_type);
++
++ addr = (u32)ioremap(vdev->mem_start, 0x1000);
++ if (!addr) {
++ printk(KERN_ERR "%s: failed to remap io memory\n",
++ vdev->dev.bus_id);
++ result = -ENXIO;
++ goto fail;
++ }
++
++ for (i = 0; i < match->num_regs; i++)
++ iowrite32(match->regs[i].value,
++ (u32 *)(addr + match->regs[i].offset));
++
++ iounmap((void *)addr);
++
++ ndev = alloc_netdev(sizeof(*adev), "wlan%d", dummy_netdev_init);
++ /* (NB: memsets to 0 entire area) */
++ if (!ndev) {
++ printk("acx: no memory for netdevice struct\n");
++ goto fail_alloc_netdev;
++ }
++ ether_setup(ndev);
++ ndev->open = &acxpci_e_open;
++ ndev->stop = &acxpci_e_close;
++ ndev->hard_start_xmit = &acx_i_start_xmit;
++ ndev->get_stats = &acx_e_get_stats;
++#if IW_HANDLER_VERSION <= 5
++ ndev->get_wireless_stats = &acx_e_get_wireless_stats;
++#endif
++ ndev->wireless_handlers = (struct iw_handler_def *)&acx_ioctl_handler_def;
++ ndev->set_multicast_list = &acxpci_i_set_multicast_list;
++ ndev->tx_timeout = &acxpci_i_tx_timeout;
++ ndev->change_mtu = &acx_e_change_mtu;
++ ndev->watchdog_timeo = 4 * HZ;
++
++ adev = ndev2adev(ndev);
++
++ memset(adev, 0, sizeof(*adev));
++ /** Set up our private interface **/
++ spin_lock_init(&adev->lock); /* initial state: unlocked */
++ /* We do not start with downed sem: we want PARANOID_LOCKING to work */
++ sema_init(&adev->sem, 1);
++ /* since nobody can see new netdev yet, we can as well
++ ** just _presume_ that we're under sem (instead of actually taking it): */
++ /* acx_sem_lock(adev); */
++ adev->ndev = ndev;
++ adev->vdev = vdev;
++ adev->bus_dev = &vdev->dev;
++ adev->dev_type = DEVTYPE_PCI;
++
++/** Finished with private interface **/
++
++ vlynq_set_drvdata(vdev, ndev);
++ if (!request_mem_region(vdev->mem_start, vdev->mem_end - vdev->mem_start, "acx")) {
++ printk("acx: cannot reserve VLYNQ memory region\n");
++ goto fail_request_mem_region;
++ }
++ adev->iobase = ioremap(vdev->mem_start, vdev->mem_end - vdev->mem_start);
++ if (!adev->iobase) {
++ printk("acx: ioremap() FAILED\n");
++ goto fail_ioremap;
++ }
++ adev->iobase2 = adev->iobase + match->rx_mapping[0].size;
++ adev->chip_type = CHIPTYPE_ACX111;
++ adev->chip_name = match->name;
++ adev->io = IO_ACX111;
++ ndev->irq = vlynq_virq_to_irq(vdev, match->irq);
++ ndev->base_addr = adev->iobase;
++
++ printk("acx: found %s-based wireless network card at %s, irq:%d, "
++ "phymem:0x%x, mem:0x%p\n",
++ match->name, vdev->dev.bus_id, ndev->irq,
++ vdev->mem_start, adev->iobase);
++ log(L_ANY, "initial debug setting is 0x%04X\n", acx_debug);
++
++ if (0 == ndev->irq) {
++ printk("acx: can't use IRQ 0\n");
++ goto fail_irq;
++ }
++
++ /* to find crashes due to weird driver access
++ * to unconfigured interface (ifup) */
++ adev->mgmt_timer.function = (void (*)(unsigned long))0x0000dead;
++#ifdef NONESSENTIAL_FEATURES
++ acx_show_card_eeprom_id(adev);
++#endif /* NONESSENTIAL_FEATURES */
++
++#ifdef SET_MODULE_OWNER
++ SET_MODULE_OWNER(ndev);
++#endif
++ SET_NETDEV_DEV(ndev, adev->bus_dev);
++
++ log(L_IRQ|L_INIT, "using IRQ %d\n", ndev->irq);
++
++
++ /* ok, pci setup is finished, now start initializing the card */
++
++ /* NB: read_reg() reads may return bogus data before reset_dev(),
++ * since the firmware which directly controls large parts of the I/O
++ * registers isn't initialized yet.
++ * acx100 seems to be more affected than acx111 */
++ if (OK != acxpci_s_reset_dev(adev))
++ goto fail_reset;
++
++ if (OK != acx_s_init_mac(adev))
++ goto fail_init_mac;
++
++ acx_s_interrogate(adev, &co, ACX111_IE_CONFIG_OPTIONS);
++/* TODO: merge them into one function, they are called just once and are the same for pci & usb */
++ if (OK != acxpci_read_eeprom_byte(adev, 0x05, &adev->eeprom_version))
++ goto fail_read_eeprom_version;
++
++ acx_s_parse_configoption(adev, &co);
++ acx_s_set_defaults(adev);
++ acx_s_get_firmware_version(adev); /* needs to be after acx_s_init_mac() */
++ acx_display_hardware_details(adev);
++
++ /* Register the card, AFTER everything else has been set up,
++ * since otherwise an ioctl could step on our feet due to
++ * firmware operations happening in parallel or uninitialized data */
++
++
++ acx_proc_register_entries(ndev);
++
++ /* Now we have our device, so make sure the kernel doesn't try
++ * to send packets even though we're not associated to a network yet */
++ acx_stop_queue(ndev, "on probe");
++ acx_carrier_off(ndev, "on probe");
++
++ /* after register_netdev() userspace may start working with dev
++ * (in particular, on other CPUs), we only need to up the sem */
++ /* acx_sem_unlock(adev); */
++
++ printk("acx " ACX_RELEASE ": net device %s, driver compiled "
++ "against wireless extensions %d and Linux %s\n",
++ ndev->name, WIRELESS_EXT, UTS_RELEASE);
++
++ log(L_IRQ | L_INIT, "using IRQ %d\n", ndev->irq);
++
++/** done with board specific setup **/
++ err = register_netdev(ndev);
++ if (OK != err) {
++ printk("acx: register_netdev() FAILED: %d\n", err);
++ goto fail_register_netdev;
++ }
++
++#if CMD_DISCOVERY
++ great_inquisitor(adev);
++#endif
++
++ result = OK;
++ goto done;
++
++ /* error paths: undo everything in reverse order... */
++
++
++ acxpci_s_delete_dma_regions(adev);
++
++ fail_init_mac:
++ fail_read_eeprom_version:
++ fail_reset:
++ free_netdev(ndev);
++
++ fail_alloc_netdev:
++ fail_irq:
++
++ iounmap(adev->iobase);
++ fail_ioremap:
++
++ release_mem_region(vdev->mem_start, vdev->mem_end - vdev->mem_start);
++ fail_request_mem_region:
++ fail_register_netdev:
++ fail:
++ vlynq_disable_device(vdev);
++ done:
++ FN_EXIT1(result);
++ return result;
++}
++
++static void vlynq_remove(struct vlynq_device *vdev)
++{
++ struct net_device *ndev = vlynq_get_drvdata(vdev);;
++ acx_device_t *adev;
++ unsigned long flags;
++ FN_ENTER;
++
++ if (!ndev) {
++ log(L_DEBUG, "%s: card is unused. Skipping any release code\n",
++ __func__);
++ goto end;
++ }
++
++ acx_lock(adev, flags);
++ adev = ndev2adev(ndev);
++ acx_unlock(adev, flags);
++
++ /* If device wasn't hot unplugged... */
++ if (adev_present(adev)) {
++
++ acx_sem_lock(adev);
++
++ /* disable both Tx and Rx to shut radio down properly */
++ acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_TX, NULL, 0);
++ acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_RX, NULL, 0);
++ acx_lock(adev, flags);
++ /* disable power LED to save power :-) */
++ log(L_INIT, "switching off power LED to save power\n");
++ acxpci_l_power_led(adev, 0);
++ /* stop our eCPU */
++ acx_unlock(adev, flags);
++
++ acx_sem_unlock(adev);
++ }
++
++ /* unregister the device to not let the kernel
++ * (e.g. ioctls) access a half-deconfigured device
++ * NB: this will cause acxpci_e_close() to be called,
++ * thus we shouldn't call it under sem! */
++ log(L_INIT, "removing device %s\n", ndev->name);
++ unregister_netdev(ndev);
++
++ /* unregister_netdev ensures that no references to us left.
++ * For paranoid reasons we continue to follow the rules */
++ acx_sem_lock(adev);
++
++
++ if (adev->dev_state_mask & ACX_STATE_IFACE_UP) {
++ acxpci_s_down(ndev);
++ CLEAR_BIT(adev->dev_state_mask, ACX_STATE_IFACE_UP);
++ }
++
++ acx_proc_unregister_entries(ndev);
++
++ /* finally, clean up PCI bus state */
++ acxpci_s_delete_dma_regions(adev);
++ if (adev->iobase)
++ iounmap(adev->iobase);
++ if (adev->iobase2)
++ iounmap(adev->iobase2);
++ release_mem_region(vdev->mem_start, vdev->mem_end - vdev->mem_start);
++
++ /* remove dev registration */
++
++ acx_sem_unlock(adev);
++ vlynq_disable_device(vdev);
++
++ /* Free netdev (quite late,
++ * since otherwise we might get caught off-guard
++ * by a netdev timeout handler execution
++ * expecting to see a working dev...) */
++ free_netdev(ndev);
++
++ end:
++ FN_EXIT0;
++}
++
++static struct vlynq_driver vlynq_acx = {
++ .name = "acx_vlynq",
++ .id_table = acx_vlynq_id,
++ .probe = vlynq_probe,
++ .remove = __devexit_p(vlynq_remove),
++};
++#endif
++
++
++#ifdef CONFIG_PCI
+ /***********************************************************************
+ ** Data for init_module/cleanup_module
+ */
+@@ -4192,7 +4573,7 @@
+ .resume = acxpci_e_resume
+ #endif /* CONFIG_PM */
+ };
+-
++#endif /* CONFIG_PCI */
+
+ /***********************************************************************
+ ** acxpci_e_init_module
+@@ -4202,7 +4583,7 @@
+ int __init
+ acxpci_e_init_module(void)
+ {
+- int res;
++ int res = 0;
+
+ FN_ENTER;
+
+@@ -4222,11 +4603,15 @@
+ #endif
+ log(L_INIT,
+ "acx: " ENDIANNESS_STRING
+- "acx: PCI module " ACX_RELEASE " initialized, "
++ "acx: PCI/VLYNQ module " ACX_RELEASE " initialized, "
+ "waiting for cards to probe...\n"
+ );
+-
++#ifdef CONFIG_PCI
+ res = pci_register_driver(&acxpci_drv_id);
++#endif
++#ifdef CONFIG_VLYNQ
++ res = vlynq_register_driver(&vlynq_acx);
++#endif
+ FN_EXIT1(res);
+ return res;
+ }
+@@ -4242,8 +4627,13 @@
+ acxpci_e_cleanup_module(void)
+ {
+ FN_ENTER;
++#ifdef CONFIG_VLYNQ
++ vlynq_unregister_driver(&vlynq_acx);
++#endif
+
++#ifdef CONFIG_PCI
+ pci_unregister_driver(&acxpci_drv_id);
++#endif
+
+ FN_EXIT0;
+ }